* Renaming/rearranging constants for clarity
As I'm writing about the Unified Embed project and creating
documentation for the upcoming Forem Fest, I realized that the naming
convention created confusion.
This commit is an effort to tidy up that confusion.
* Normalizing implementation pattern
* Load article before creating a page view for an invalid one
This should resolve a validation error in PageView.create! when the
article does not exist (perhaps it was deleted, or the user suspended,
or it was invalid data sent from the client).
This had been happening dozens of times per day for the last 10
months.
* Use an intention revealing symbol instead of calculated id
Since we only require that find_by not find anything, pass a symbol
that's not going to be the id for any article under any conditions.
As an added benefit, this provides a clear indication of the purpose
of the symbol, without needing to mentally confirm that
```sql
SELECT * FROM articles
WHERE id IN (
SELECT (1 + MAX(id)) FROM articles
) LIMIT 1
```
actually never gives any articles back.
* Add missing spaces
* Use filter_map over map + reject/compact
* Simplify FactoryBot calls
* Use to_h with block instead of map + to_h
* Use guard clause
* Remove slash characters from user supplied user search input
Prevents an error when the search term includes '\'
PG::SyntaxError: ERROR: syntax error in tsquery
https://app.honeybadger.io/projects/66984/faults/79391397
I had originally thought to add this cleanup to Search::Username but
decided to move it as close to the generated (invalid) query as
possible to prevent alternate paths finding their way here.
* Add spec
Since there's no existing tests for the scope - I put the test code on
the caller (Search::Username) rather than the model (User), this seems reasonable.
* When the term is empty (or only slashes) just return null relation
* Handle nil input (search for nothing) correctly
One of the request specs sends a username search with no query, so we
can't call nil.delete or nil.empty?, use blank? of empty?
* Refactoring questions asked of user
In this pull request, I'm extracting and normalizing role-based
questions asked of the user.
Prior to this commit, our codebase has asked two very similar questions
of our user model:
- `user.has_role?(:admin)`
- `user.admin?`
In asking `has_role?(:admin)` we are relying on implementation details
of the rolify gem. In addition, the `has_role?` question asked
throughout controllers or views means that it's harder to create
hieararchies of permissions.
In favoring `user.admin?` as our question, we can use that indirection
as an opportunity to discuss and decide "Should someone with the
`:super_admin` role be `user.admin? == true`?"
The details of this commit is to do three primary things:
1. Ask the `has_role?` questions in "one place" in the code (e.g. the
`Authorizer` module)
2. Extract the role based questions that are on the `User` model and
provde backwards compatable delegation.
3. Structure the code so that it's harder to accidentally call
`user.has_role?` (e.g., make `User#has_role?` and `User#has_any_role?`
private).
This is related to #15624 and the updates are informed by discussion in
PR #15691. This commit supplants #15691.
* Refactoring the liquid tag policy tests
* Fixing typo
* Bump for travis
* Remove modify_hr_tags method definition
this breaks things that call it.
* Remove direct uses of modify_hr_tags fixer method
Remove from class METHODS lists, remove test cases about this behavior, and remove from
methods lists in test cases.
* Remove hr tag modification spec
Still don't understand what problem this was fixing, but I've removed
the test case.
* Implement embed and write specs
* fix slight regex ommision
* remove error over invalid options; add specs to cover
* account for missing options when using embed keyword
* no videos, no ns video_id 🤦🏾♀️
* Don't raise NoMethodError when validating emoji settings
Cargo culted the unique cross model slug validator setup (which is why
value is called name here in the validatable).
Don't raise an error when validating a nil emoji, and assert nil and
empty string are permitted values.
This expects no non-emoji characters (so an empty string would be
permitted), and nil should be permitted.
I believe this might have been introduced by the string settings
cleaner (exchanging "" for nil in form inputs).
* Update app/validators/emoji_only_validator.rb
guard for value, and then validate value
* Skip notification interaction with replies spec
This had been failing in builds (my assumption is that the state flag
for .reacted was either out of sync or not yet ready/unhidden, I'm
still getting more information about this).
The behavior being tested is that clicking the greyed out heart on a
reply enables the .reacted class, and clicking again disables
it. There's a similar test for an admin clicking heart, thumbsdown,
and monocle/flag/vomit icons one by one and checking the state on the
page.
This is a good candidate to move to a cypress test.
* Skip admin interacting with replies to notifications
Same issue as the user interaction - the .reacted class is not
reliably present after a click event.
* Clear the cached community name before loading new page
When the creator settings form had been run before the create new page
spec, the community name would be changed from the default
"DEV(local)" to "Climbing Life". Since the application helper can
memoize this value - and the database will not - ensure these are in
sync by clearing the settings cache before requesting the page (which
will be prefilled based on the setting).
This "fix" should probably be moved into the test introducing the
change, rather than the one impacted by it.
* Move clearing the settings cache closer to the change
Rather than clearing the cache where we were impacted, clear
immediately after the save spec completes.
* Remove reactions to a user when deleting the user
Fixes#15245
---
I have no idea why `create(:vomit_reaction, reactable: user)` gave a
validation error about category being invalid, but `build().save`
worked fine.
* Move relation details to reaction scope `for_user`
Add a user method to access this by passing self to reaction scope
* Create a moderator when flagging user in factory
This might be a missing requirement in the reactions factory - but
this suppresses an error about invalid category I was getting when
setting a privileged reaction on the user via
create(:vomit_reaction, reactable: user)
Everywhere else it looks like we do this with `user: moderator` (where
there's a trusted user in the surrounding context).
* Move trusted user requirement into vomit_reaction factory
* Add a data update script to remove reactions to deleted users
This cleans up the remaining invalid references and should make the
change in #15249 obsolete (i.e. we don't need to limit the view to
exclude items that no longer exist).
* WIP: add a creatore settings form
* WIP: updat the controller to use the Creator Settings FOREM
* feat: use the creator settings form for the new action
* feat: add some default values for the new action
* a note about form data
* update the initiaize function to set some default values
* feat: update the form to use the model data
* feat: permit adn use the attributes within creator_settings_form
* update the flash error
* refactor: require and permit parameters
* chore: use booleans, set defaults and validate the form
* spec: update all the creator_settings tests
* chore: remove comment
* refactor: use self
* feat: aggregate failures'
* chore: remove the logo uploader in the controller
* refactor: update error handling
* feat: update the wasy the controller handles success and error
* chore: remove the resource errors
* feat: show flash message on new line
* fix: use a redirect so that we can get back to /new
* refactor: pass these values through as they seem to be caching whne setting them as default
* chore: change default values
* spec: update tests
* Fix CreatorSettingsForm specs
* fix: use a boolean for public
* spec: add another test for the success var
* fix: radio button labels to correspond + cyress specs
* spec: update based on new changes
* spec: update the params and the expected output
* spec: update the comments and status
* feat: no need for the initialize as we use Active Record Attributes
* feat: update the tac and coc to be persisted when ticked
* fix: amend spec
* blank space
* Message
Co-authored-by: Michael Kohl <me@citizen428.net>
* User decorator (and spec) should use `trusted?`
Fixes a few issues seen in an rspec run that show as:
DEPRECATION WARNING: User#trusted is deprecated, favor
User#trusted? (called from config_body_class at
/opt/apps/forem/app/decorators/user_decorator.rb:58)
And here:
/opt/apps/forem/spec/decorators/user_decorator_spec.rb:112
/opt/apps/forem/spec/decorators/user_decorator_spec.rb:121
/opt/apps/forem/spec/decorators/user_decorator_spec.rb:130
/opt/apps/forem/spec/decorators/user_decorator_spec.rb:139
* prefer User trusted? to trusted
DEPRECATION WARNING: User#trusted is deprecated, favor
User#trusted? (called from permissions at
/opt/apps/forem/app/models/rating_vote.rb:25)
* Prefer trusted? to trusted in user spec
* Use warned? rather than warned in admin article partial
* use trusted? rather than trusted in moderator requests spec
* Prefer trusted? to trusted in moderations controller
* Prefer trusted? to trusted in moderations view
* User auditable? should call trusted? and not trusted
Deprecations go rolling right along.
* Invert guard clause logic to be positive
The original "return unless multiple negated conditions hold" guard
was cumbersome.
Invert to return if any of the exceptions apply, namely:
- this is a comment or readinglist rating (rather than explicit),
allowed for all
- this rating is from a moderator/trusted user (allowed)
- this rating is offered by the article's author (allowed)
I had intended to also remove the safe navigation operators (since it
wasn't clear why there would be a null user or null article, as
rating_vote joins users to articles with a score), but the builtin
validation tests (is expected to validate ...) build objects with
missing attributes, and raise errors when the spec is run.
The data update script "nullify empty tag colors" failed to update
because of the way it was written - in two passes, updating the
background color for tags where the background color was empty, then
updating the foreground color for tags where the foreground color was
empty.
Because both attributes have a validation regex, neither pass updated
any tags (the problematic cases observed had empty string values in both
columns).
Perform in a single loop, over the union of the two sets (expected to
include only the same rows as before), an update for both columns at
once.
Additionally, use update_columns which bypasses _other_ validation
issues (the only one I could suspect is the alias_for check).
Nullify empty strings in alias_for (simplifies a few things, now it's
either valid or null).
When a tag is detected with a "danlging alias" repair it by setting
alias for nil.
* Use the feed source url when the feed url (from links) is empty
This probably should just be using @feed_source_url always to make a
base path for absolute paths without a hostname, rather than expecting
this from the feed.
An example why we should not be using @feed.url would be
individual posts at domain/slug but the "index" page at
domain/blog (with a generic screen on /), and images hosted from
/assets/ without /blog/ anywhere in the asset path.
Partial fix for #15488
* Use item.url as base_url for relative links
It's possible the rss feed and the contained articles are served from
separate hosts/subdomains/paths. Don't assume the entries are related
to the feed or the feed_source_url, use the item's url for relative
links in that item.
* Update failing spec to add url to item double
We're revisiting the behavior of the feed scoring, and the selection
of articles will be less heavily influenced by the article's score.
This test was nested within a group related to active campaigns, but
the minimum score is a user experience setting (so if we want to test
for that it should happen outside the context), and minimum article
score will likely not be a reliable criterion for filtering the home
feed in the future.
Remove this example (it was skipped because failing), as it adds
little value and is at a minimum misplaced (wrong surrounding
context), at worst it's wrong or likely to be wrong soon.
* Removing the stackbit integration
The feature didn't quite work and Stackbit no longer supports this
integration.
Yes there are a few places where the webhooks has a string of "stackbit"
but I'm hesitant to remove that, as they are the part of the Webhooks
tests.
Closes#15700
* Update lib/data_update_scripts/20211206222716_remove_stackbit_page.rb
Co-authored-by: Michael Kohl <citizen428@forem.com>
Co-authored-by: Michael Kohl <citizen428@forem.com>
* Extracting cross-model uniqueness validator
Prior to this commit, we had somewhat duplicated logic across four
models. In adding this validator we're consolidating the logic and
tidying up each of the other models; letting the validator know which
models are part of the "uniqueness gang."
* Adding conditional test for validator
* Bump for travis
* Apply suggestions from code review
Co-authored-by: Michael Kohl <citizen428@forem.com>
Co-authored-by: Michael Kohl <citizen428@forem.com>
I think this is related to some requests triggering the weighted query
field test (which changes the rules for the home feed in a way that
may include these campaign tags and handles relevancy differently from
the scoring).
It's reasonable to revisit these. Either the entire context should
include an assertion that all field tests return the original
strategy, never weighted, or we should determine their importance if
we expect the weighted query strategy to be universally deployed (or
widely deployed).
* Add two guards when purchasing credits
This prevents sending an empty card to stripe, and avoids a
foreseeable error when purchasing 0 credits. Error returned from
stripe is "This value must be greater than or equal to 1".
* Move redirect back into action method
Only use validation methods to check input and set appropriate messages.
* Accept organization id if set
The payment service will use the organization id (and charge the
organization) when that's the purchaser. Don't fail when no stripe
token or card selected if an organization admin is purchasing credits.
* Move validation into the payment processing service
This cleans up the number of details the controller needs to worry
about
Now only if the process payment service had any tests...
* Prevent only organization_id from permitting purchase
and move this check to a method, with an intention revealing name
* Add i18n translation for error message
There weren't any service side error messages - this will be displayed
in a view (credits/purchase) but comes from the payment service -
other messages (from stripe) are passed through as-is there.
If this is the wrong _place_ for the translation I can retool.
* Add unit test for payment processing
Only checking errors are raised as expected and the internal error
message is translated.
* Leave translation alone
Revert test translation
Prior to this fix, in the production rails console we ran the following:
```ruby
Articles::Feeds::WeightedQueryStrategy
.new(user: nil, page: 1, tags: nil)
.featured_story_and_default_home_feed(user_signed_in: false)
```
The result was: `[nil, []]`. Which in the
[StoriesController#assign_feed_stories][1] is where we have the
following:
```ruby
@featured_story, @stories = feed
.featured_story_and_default_home_feed(
user_signed_in: user_signed_in?)
```
In Blazer, I ran the following query at 2021-12-02 Thu 20:41 EST:
```sql
SELECT * FROM articles
WHERE featured = true
AND published = true
AND published_at > (NOW() - interval '7 days')
AND published_at < NOW()
AND main_image IS NOT NULL
```
So the logic of filtering with `only_featured` resulted in the
`@featured_story` being `nil`. Which then cascaded into the logic for
determining the remainder of the results.
For further discussion see the inline comments and specs that I wrote.
In addition to the above, I'm also reusing
`Articles::Feeds::FindFeaturedStory`
Prior to this commit, the `Articles::Feeds::WeightedQueryStrategy` first
grabbed the featured story, then grabbed the remaining articles. This
is different than the implementation of the
`Articles::Feeds::LargeForemExperimental` in which we first grab all the
articles then claim one as the featured.
In the WeightedQueryStrategy, the articles would not include the
featured. However, in the LargeForemExperimental it would. This
results in upstream logic in [app/javascript/articles/Feed.jsx][2]
going through and removing one of the articles.
[1]:c1a3ba99eb/app/controllers/stories_controller.rb (L237-L271)
[2]:c1a3ba99eb/app/javascript/articles/Feed.jsx (L57-L63)
Fixes a failure where the follow did not calculate implicit
points correctly.
The underlying issue was that the factory created `article` did not have
a cached_tags value containing `tag.name`
saved (`article.tags.pluck(:name)` was correct, but the cached_tags
was not). This happens automatically when saving an article from the
post editor, and any time we subsequently modify an article.
Supersedes #15456