* feat: Add a pack file that pulls in the MultiSelect Component
* feat: move the tags to its own component
* save tags
* refactor: create a getCSRFToken function in the packs files so that it can be used in the admin
* feat: import the new module in request.js
* feat: remove unnecessary id
* feat: first pass of csrf token test
* chore: update the test
* fix: csrf token
* feat: hide the enw functionality behinda feature flag
* fix: loading form twice
* refactor: import for csrftoken
* chore: update the description of the function
* feat: use acts_on_taggable to craete a relationship between display_ad and tag
* feat: add a tag field to the display_ad form
* feat: add the selected tags from the multiselect autocomplete component to the input text field that references the tag_list
* feat: add the tag_list to the controller so that we can save it to the db with the display ad parameters
* feat: pull out the tag validation from the article and the display_ads into a concern
* feat: write soem tests for validating the tag on the display_ads model
* feat: add the tag_list as a hidden field
* feat: set the selected tags on edit
* feat: add a js class for the placement area
* feat: use the change in the dropdown to determine whether we show the tags field dropdown
* refactor: rename and brak up fucntions
* feat: show the tags field if the value of the placement area is already set
* fix: move if statement out of the change event
* feat: hide tags field and clear the tag list
* refactor: delete the display ads
* tests: ensure that we test the toggle
* fix:ensure that the tags on the hidden field show up as a string in the input field
* feat: update the jsdoc
* fix: no need to replace space with comma since we showing as string in form
* feat: update the name of the label
* fix: add hidden back
* feat: add cached_tag_list to displya_ads + the index
* feat: udpdate the schema
* refactor: move the scopes into the a module that can be re-used between display_ads and articles
* feat: account for showing display ads with the targeted tags that match the article
* feat: write a spec to show the correct ads based on the article_tags
* refactor: change TagListValidateable to Taggable and move out the not_cached_tagged_with_any scope
* test teh relationship between display ads and tags
* feat: write soem tests for validating the tag on the display_ads model
* chore: change empty to blank
* feat: will show display ads with no tags set if there are no article tags
* feat: add a newline
* Removed code related to tracking html_variants
* Remove code related to HtmlVariant#find_for_test
* Remove spec for HtmlVariant#success_rate
* Ignore html_variants.success_rate
* Drop tables related to HtmlVariant tracking
* Restore DisplayAdEvents.counts_for
* Try a rollup service for DisplayAdEvent
* Schedule daily rollup worker for one month prior
* Refactor aggregator
* More testing for rollup
* Add test for rollup attribute fidelity
* DisplayAd success_rate based on counts_for
* feat: remove initializeSponsorshipVisibility and related code
* feat: remove sponsorships from sidebar
* feat: remove sponsorships from the admin - route, controller, view, spec
* feat: remove the admin menu item
* feat: remove the i8n for admin sponsors controller
* feat: sponsorship decorator was not being used anywhere
* feat: sponsorship slack messenger was not being used anywhere
* feat: remove the sponsorship_headline that gets configures on the admin
* feat: remove the /sponsors page
* feat: remove renedring of single_sponsor partial and associated partials
* feat: remove the navigation link rake task for sponsors
* feat: remove sponsorship from tags
* feat: remove i8n constants used
* remove sponsor references in text to the privacy page
* feat: remove the sponsorship detail from the organization page
* feat: remove the sponsors css that was used for app/views/pages/sponsors.html.erb
* feat: remove the sponsorship i8n that was used in the slack messengers
* feat: swap out the decorators to use Article as an example
* feat: remove spec to show sponsors on home page
* feat: update the specs to use Article Decorator instead of the Sponsorship Decorator
* fix: use direct and not all
* fix: remove tests for tag sponsorship
* fix: remove organization sponsorship test
* feat: remove more i8n
* remove unused css from app/views/organizations/_sidebar_additional.html.erb
* feat: remove sponsorship relationship from tag and organization
* remove seed
* feat: remove all Sponsor related specs
* feat: remove model, associated i8n and specs
* feat: remove sponsor from navbar
* feat: add a guard clause if we're unable to constantinize the purchase_type
* feat; remove sponsorship related tests
* feat: remove sponsorship relationship
* feat: remov especs related to sponsorship
* feat: remove tag sponsorship validation
* feat: remove the sponsorship factory
* feat: drop the sponsorships table
* feat: remove initializeSponsorshipVisibility and related code
* feat: remove sponsorships from sidebar
* feat: remove sponsorships from the admin - route, controller, view, spec
* feat: remove the admin menu item
* feat: remove the i8n for admin sponsors controller
* feat: sponsorship decorator was not being used anywhere
* feat: sponsorship slack messenger was not being used anywhere
* feat: remove the sponsorship_headline that gets configures on the admin
* feat: remove the /sponsors page
* feat: remove renedring of single_sponsor partial and associated partials
* feat: remove the navigation link rake task for sponsors
* feat: remove sponsorship from tags
* feat: remove i8n constants used
* remove sponsor references in text to the privacy page
* feat: remove the sponsorship detail from the organization page
* feat: remove the sponsors css that was used for app/views/pages/sponsors.html.erb
* feat: remove the sponsorship i8n that was used in the slack messengers
* feat: swap out the decorators to use Article as an example
* feat: remove spec to show sponsors on home page
* feat: update the specs to use Article Decorator instead of the Sponsorship Decorator
* fix: use direct and not all
* fix: remove tests for tag sponsorship
* fix: remove organization sponsorship test
* feat: remove more i8n
* remove unused css from app/views/organizations/_sidebar_additional.html.erb
* feat: remove sponsorship relationship from tag and organization
* remove seed
* feat: remove all Sponsor related specs
* feat: remove model, associated i8n and specs
* feat: remove sponsor from navbar
* feat: add a guard clause if we're unable to constantinize the purchase_type
* feat; remove sponsorship related tests
* feat: remove sponsorship relationship
* feat: remov especs related to sponsorship
* feat: remove tag sponsorship validation
* feat: remove the sponsorship factory
* feat: add a migration that creates a display_to column on the display_ads table
* feat: add an enum for display_to
* feat/WIP: add rough draft of the field to the UI and permit it in the controller
* feat: take into account on whether an ad needs to be shown on logged in or out or both + update cache keys on sign in
* fix: if a user is not signed in then we want to display all and logged out
* fix: display_for spec in model
* feat: add some tests for display_to
* feat: style the label
* feat: show the display_to on the index page
* feat: add a seed for e2e
* chore: force true
* feat: create a migration to add the display ad name column to the tanle
* feat: add a display ad name to the interface
* feat: add a display ad name after create
* feat: whoops the migration file
* feat: add a DUS to update previous Display Ads names
* fix: test
* refactor: update the name after_save
* fix: add name to params
* add new column with enum value
* refactor to use display_to column
* add some more specs to application_helper
* test for the backfill DUS
* fix line length
* refactor
* ContextNotification model
* Create and destroy context notifications when notifications are sent/unsent
* Added a transaction when creating notifications and context notifications
* Documentation for context notifications
We already have a partial unique index for this column scoped on
`published = true`, which is still useful. This index does not make that
index redundant because that index is used to enforce a constraint that
we *only* want to apply to published articles. This index will be used
when `WHERE published` is not part of the query.
* Add boolean attribute main_image_from_frontmatter to indicate if cover image was set via frontmatter
* use article model spec for main_image_from_frontmatter test cases
* Add data migration script and spec for main_image_from_frontmatter for articles
* Update app/models/article.rb
Co-authored-by: Jeremy Friesen <jeremy.n.friesen@gmail.com>
Co-authored-by: Jeremy Friesen <jeremy.n.friesen@gmail.com>
Co-authored-by: Michael Kohl <me@citizen428.net>
This is meant as a conversation. Throughout the code-base we have have
`Tag.order(hotness_score: :desc)` and with PR #16322 we'll also have
`Tag.order(taggings_count: :desc)`.
My understanding is that if we have sorting, we might want to consider
an index. I put this forward as a conversation with a possible quick win.
Related to #16322
* Convert symbol hash keys to strings when calling .perform_async
Fixes a warning from Sidekiq 6.4.0+ about perform_async arguments
which are not equal when passed to perform (`JSON.parse(JSON.dump(arg))`
should equal arg).
This is a safety measure to prevent passing objects (like classes, or
model instances) rather than their representations (like a class name,
or a model's attributes hash).
This warning will be an error in sidekiq 7
* Turn warning into an error in non-production environments
* Use string keys for reaction notification and article fetched
Missed these two on the first pass
* Update example argument hashes for #enqueues_on_correct_queue
Since this calls perform_async under the hood we need to pass json
safe hashes in the test cases as well.
https://github.com/forem/forem/blob/main/spec/workers/shared_examples/enqueues_on_correct_queue.rb
* Convert keys from FollowData#to_h to string before perform_async
I'm not sure enough where else (outside of notification) to_h is being
called, so I'm converting here when building args, rather than in
FollowData#to_h, which might be my next step.
* Let FollowData#to_h return a hash with string keys
Update spec to use string keys as well.
* Make to_h return string keys for ReactionData
Like FollowData, the #to_h method is only used to call
notifications (this is used to enqueue sidekiq jobs).
* Remove a key that was in the hash
Since reaction_data calls to_h, it gets string and not symbol,
keys. Call Hash#except with a key that was actually there.
This change restores setting usernames to something less obnoxious.
Prior to this commit, I would on occassion get the following error in
seeds:
```shell
❯ bin/rails db:seed
Seeding with multiplication factor: 1
1. Creating Organizations.
2. Creating 10 Users.
rake aborted!
ActiveRecord::RecordInvalid: Validation failed: Username is too long (maximum is 30 characters)
./forem/db/seeds.rb:67:in `block (2 levels) in <main>'
./forem/db/seeds.rb:60:in `times'
./forem/db/seeds.rb:60:in `block in <main>'
./forem/app/lib/seeder.rb:30:in `create_if_none'
./forem/db/seeds.rb:57:in `<main>'
<internal:~/.rbenv/versions/3.0.2/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
<internal:~/.rbenv/versions/3.0.2/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
-e:1:in `<main>'
Tasks: TOP => db:seed
(See full trace by running task with --trace)
```
Related to work done in #16067
Prior to this commit, we were somewhat naively rendering Hash style data
attributes in our ERB templates. By rendering each hash attribute
separately, we were rendering characters that could break the
javascript (e.g. double hack or backslash `"` or `\`).
By moving to this view_object rendering, we leverage Rails's `to_json`
behavior to ensure properly escaped values. As part of this exercise, I
generalized the method to allow for other places to benefit from this
behavior.
This generalization also helps ensure that we have a more conformant
rendering (e.g. we should always have an :id, :className, and :name
value in our data-info hash).
_Note: I've updated the user's names for Cypress tests as they are more
likely to catch the particular issue than anything else. I assume that
I'm going to break some cypress tests and will need some help fixing
them._
Closes#15916, #14704
Supersedes #15983
How to test locally:
Assuming you have seeded database (e.g. `rails db:seed`), checkout the
"main" branch. Then in `rails console` find a user that's written articles:
```ruby
user = Article.last.user
user.update(name: "\\: #{user.name}")
user.articles.each(&:save)
```
Now, again on the "main" branch, start your application (e.g.,
`bin/startup`).
Then get a logged in and a logged out browser session going. Open your
web inspector and open console. Then go to the local instances homepage
(e.g., http://localhost:3000) and look for JS errors.
On the main branch, you should see an exception around
`JSON.parse(button.data.info)` (assuming that the `user`'s article is
rendered on the homepage).
Then go to the user's page (e.g. https://localhost:3000/:user-slug) and
look for JS parse errors.
On this PR's branch (e.g.,
`jeremyf/take-two-at-resolving-gh-15916`)
you shouldn't see those console errors.
More importantly, the Follow buttons should work.
* Generator output
Add your logic here!
* replicate the logic from the forem connect migration
* Add data update script
This will generate the expected broadcast message to fix#16059
* Add apple connect to seeds file
* Remove Connect
* Remove more Connect specs
* Remove a lot more Connect code
* 🚮
* It all has to go
* Explicitly add httpclient
* Update application layout
* Remove messages association from User
* Start fixing specs
* reintroduce util function and refactor references
* Remove Connect Cypress test
* Fix more specs
* Remove Connect from listings
* Ignore contact_via_connect column on listings
* Remove contact_via_connect usages
* Ignore mod_chat_channel_id on tags
* Drop Connect tables
* Remove email_connect_messages from user notification settings
* Re-add httpclient 2.8.3
This was mistakenly removed as a merge conflict
* Don't need to exclude removed chat channel file
* Remove unneeded style for chat channels
* Remove unneeded channel list prop type
* Remove chat channels index/connect-link from getPageEntries
* Re-add comment from httpclient in Gemfile
* Remove connect references from mailers
Tag Moderators no longer have a chat channel
No longer will users be notified about new messages (there won't be
any)
No longer will users be notified about channel invites (you can't
invite anyone anymore)
* Don't configure Pusher and remove PUSHER_* from .env_sample
since it's removed from gemfile, the Pusher constant will not resolve, if this is
configured in the environment variables we'll fail to boot.
Co-authored-by: Suzanne Aitchison <suzanne@forem.com>
Co-authored-by: Dan Uber <dan@forem.com>
* Add PGHero for more insights into the DB
Andrew Kane's Ruby gems will continue being added until morale improves!
* Add linux x86_64 protobuf
* Fix discrepancy between Gemfile and Gemfile.lock
No idea how this happened, but it happened when merging `main` back into
this branch.
Co-authored-by: Dan Uber <dan@forem.com>
* Add one reaction to each article when seeding the database
* Add reaction to article when created
and sync reactions count.
There's still a gap where the redis-cached reaction count could be
present but not cleared during seeder runs (redis is disconnected for
caching and rails cache is set to the null store). Since we are able
to enqueue sidekiq jobs redis is live - but it's a bad idea to use
sidekiq's connection to flush keys in redis.
* Make the reaction count update script a no-op
* Remove unused data update script and limit user id queries
Pull all user ids into an array before you start creating articles,
and sample from the array rather than repeatedly asking for the first
user from a random ordered db result.
* fail if we can't create reaction
thanks @jgaskins
Co-authored-by: Jamie Gaskins <jamie@forem.com>
* Revert "fail if we can't create reaction"
This reverts commit c35f6d47d2e8956a240133b9e6ad0d144f1b4722.
There is a uniqueness constraint on (user, reactable, category) that
could be triggered when seeding due to random selection. It's better
to skip creation when a validation error occurs than to break the seed
completely.
There are expected to be 0-9 reactions per article, we don't require a
set number on each article, and likely won't notice any specific
problem if the random number is one lower than it would have been
because some reactions were skipped due to uniqueness violations.
Co-authored-by: Jamie Gaskins <jamie@forem.com>
* Fix and clean up podcast pages
* Adjust tests
* Fix a test
* Fix missing i18n
* Fix tests
* Fix tests
* Fiddle with test
* Sure up css and tests
* Add featured as allowed param
* Fix a couple tests
* xit out test
* Update app/views/podcast_episodes/index.html.erb
* Update app/views/podcast_episodes/index.html.erb
Co-authored-by: ludwiczakpawel <ludwiczakpawel@gmail.com>
Co-authored-by: ludwiczakpawel <ludwiczakpawel@gmail.com>
Set a NOT NULL constraint on tags timestamps
This commit also monkeypatches in a method for StrongMigrations to
disable a check temporarily. This migration is safe enough for DEV (it's
not ideal, but it'll only lock the table for a matter of milliseconds),
so we'll be fine disabling it but we don't want to disable the check
globally for all migrations in case there's a migration where this is
not safe.
* Initial forem omniauth strategy setup work
* Finish basic raw proof of concept
* Some playing around
* use OAuth payloads + PASSPORT_OAUTH_URL for local dev
* Use FeatureFlag for Forem Passport Auth
* Working on tests
* Fix tests 🤞🏼 & some cleanup
* Use correct namespace within lib directory (match class namespace)
* Test to ensure Forem Passport auth is restricted by FeatureFlag
* Add broadcast + work on tests
* Update spec/lib/data_update_scripts/insert_forem_connect_broadcast_message_spec.rb
Co-authored-by: Michael Kohl <citizen428@forem.com>
* Hash format
* Schema cleanup + inline comments
* Use temprorary Heroku domain
* More cleanup
* Missed one
* Back to passport.forem.com
* Require correct path in lib
* Apply suggestions from code review
Co-authored-by: Michael Kohl <citizen428@forem.com>
* Use with_indifferent_access for symbol hash access in Forem strategy
Co-authored-by: benhalpern <bendhalpern@gmail.com>
Co-authored-by: Michael Kohl <citizen428@forem.com>
* When calling Faker::Markdown, avoid "sandwich" method
Since random can also be selected by random (without the exclude
list), avoid calling sandwich occassionally from random's call to
random.
This avoids generating body_markdown exceeding 12 newlines (which is
validated in Listing and prevents save, breaking the seeds process).
* just take 10 lines, don't be clever
Co-authored-by: Jamie Gaskins <jamie@forem.com>
Co-authored-by: Jamie Gaskins <jamie@forem.com>