Commit graph

905 commits

Author SHA1 Message Date
yheuhtozr
71b2724faa
app/services i18n (#16189) 2022-01-20 09:25:25 -05:00
Mac Siri
3685530969
Explicitly silence FastImage exceptions (#16176) 2022-01-19 08:56:26 -05:00
Daniel Uber
394d33e134
Select max from a subquery of two things (#16177)
* Select max from a subquery of two things

max(int, int) not a function, says postgres, once it stopped yelling
about parenthesis balancing.

* prefer greatest to select max from subquery
2022-01-18 18:21:14 -05:00
Jeremy Friesen
06f6573436
Ensuring that we don't divide by zero (#16172)
* Ensuring that we don't divide by zero

Adding one to a "always-ish greater than or equal to 0" value.  This
should resolve a flakey test and a seemingly erratic production error.

Resolves https://app.honeybadger.io/projects/66984/faults/83596547

* Favoring min over adding 1

Due to syncrhonization antics, let's not assume time is consistent
across servers.

Timey Whimey Wibbley Wobbley

* Update app/services/articles/feeds/weighted_query_strategy.rb

Co-authored-by: Daniel Uber <djuber@gmail.com>

Co-authored-by: Daniel Uber <djuber@gmail.com>
2022-01-18 17:25:15 -05:00
Jeremy Friesen
5ec47d99dc
Ensuring we don't track views of author or unpublished (#16143)
* Ensuring we don't track views of author or unpublished

Prior to this commit, I was surprised to learn that we:

1) Tracked an author's view of their article.
2) Tracked views of an unpublished article.

This came up from a Forem creator asking if they could reset the view
counter.  Or trigger the reset on publication.

I think a general business logic policy of don't track views for the
author and don't track views for unpublished articles is a reasonable
default.

Were we to pursue the clear views on publication, we'd need to consider
something that went from unpublished -> published -> unpublished ->
published.  Without a more explicit state machine, triggering a
busineiss logic behavior seems a bit unexpected.

In other words, I wrote an article.  There are 20 views when I realize
that I need to unpublished it.  I make the changes in the unpublished
state, and re-publish.  I'd assume that those 20 views would still be
"recorded" and counted towards my article's view counts.

* Adjusting condition structure

Prior to this commit, the `if` clause was rather far to the right.  This
helps make the if clause more pronounced.
2022-01-18 11:23:18 -05:00
Julianna Tetreault
46d40b2f54
Resolves rubocop violations in weighted_query_strategy.rb (#16164) 2022-01-18 09:11:41 -07:00
Michael Kohl
9cc01b2c30
Remove unused Users::ProfileImageGenerator::BACKGROUND_HEXES (#16132) 2022-01-18 10:32:52 +07:00
Daniel Uber
f90459d163
Include badge before serializing (#16160)
We are loading the badge for each included tag in the
Search::TagSerializer and seeing warnings from bullet

```
Bullet::Notification::UnoptimizedQueryError:

GET /search/tags?name=ta
USE eager loading detected
  Tag => [:badge]
  Add to your query: .includes([:badge])

Call stack
  /home/travis/build/forem/forem/app/serializers/search/tag_serializer.rb:5:in `block in <class:TagSerializer>'
  /home/travis/build/forem/forem/app/services/search/tag.rb:11:in `serialize'
  /home/travis/build/forem/forem/app/services/search/tag.rb:7:in `search_documents'
  /home/travis/build/forem/forem/app/controllers/search_controller.rb:54:in `tags'
  /home/travis/build/forem/forem/app/lib/middlewares/set_time_zone.rb:10:in `call'
```

Follow the advice, now when multiple tags are in the result set,
having multiple badges, badges are loaded only once (at query time)
and not one by one (at serialization time).
2022-01-17 17:12:52 -06:00
Jeremy Friesen
5534a8fa18
Addressing rubocop violations (#16156)
```shell
❯ bundle exec rubocop -A
Inspecting 1856 files

Offenses:

app/controllers/admin/settings/mandatory_settings_controller.rb:17:57: C: [Corrected] Rails/CompactBlank: Use compact_blank instead.
            settings_model.public_send("#{key}=", value.reject(&:blank?)) if value.present?
                                                        ^^^^^^^^^^^^^^^^
app/controllers/users_controller.rb:66:58: C: [Corrected] Rails/CompactBlank: Use compact_blank instead.
      Honeycomb.add_field("error", @user.errors.messages.reject { |_, v| v.empty? })
                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^
app/controllers/users_controller.rb:280:58: C: [Corrected] Rails/CompactBlank: Use compact_blank instead.
      Honeycomb.add_field("error", @user.errors.messages.reject { |_, v| v.empty? })
                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^
app/models/settings/base.rb:111:54: C: [Corrected] Rails/CompactBlank: Use compact_blank instead.
          value.split(separator || SEPARATOR_REGEXP).reject(&:empty?).map(&:strip)
                                                     ^^^^^^^^^^^^^^^^
app/services/articles/feeds/weighted_query_strategy.rb:269:121: C: Layout/LineLength: Line is too long. [126/120] (https://rubystyle.guide#max-line-length)
      def initialize(user: nil, number_of_articles: 50, page: 1, tag: nil, strategy: AbExperiment::ORIGINAL_VARIANT, **config)
                                                                                                                        ^^^^^^
app/services/images/optimizer.rb:27:50: C: [Corrected] Rails/CompactBlank: Use compact_blank instead.
      options = DEFAULT_CL_OPTIONS.merge(kwargs).reject { |_, v| v.blank? }
                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
app/services/images/optimizer.rb:46:68: C: [Corrected] Rails/CompactBlank: Use compact_blank instead.
      options = DEFAULT_IMGPROXY_OPTIONS.merge(translated_options).reject { |_, v| v.blank? }
                                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
app/services/settings/upsert.rb:30:55: C: [Corrected] Rails/CompactBlank: Use compact_blank instead.
          settings_class.public_send("#{key}=", value.reject(&:blank?))
                                                      ^^^^^^^^^^^^^^^^

1856 files inspected, 8 offenses detected, 7 offenses corrected
```

After this commit:

```shell
❯ bundle exec rubocop
Inspecting 1856 files

1856 files inspected, no offenses detected
```

1856 files inspected, no offenses detected
2022-01-17 17:21:06 -05:00
Ben Halpern
8159f4383c
Feed experiment 4: Final order (#16128)
* Feed experiment 4: Final order

* Remove development line

* Fix text in tests

* Fix text in tests

* Switch query to greatest of
2022-01-17 17:05:43 -05:00
Jeremy Friesen
02b3bb8a8e
Extracting a not_authored_by scope (#16123)
In my quest to find `where(attribute: value)` in controllers and even
services, I stumbled upon this pattern.

As of this commit (and prior) an Article's associated user is it's author.
2022-01-17 15:20:49 -05:00
Andy Zhao
5b1ca20b16
Prevent banished users from updating their profiles (#16122)
* Don't update social information for suspended/banished accounts

* Prevent suspended users/accounts from updating their profile information

* Add tests and fix some logic
2022-01-17 10:54:02 -05:00
Ben Halpern
5a033fcce3
Turn featured back on as query scoring weight (#16093) 2022-01-14 07:32:52 -05:00
Josh Puetz
629c7114da
Login with Google (#15986) 2022-01-13 10:25:52 -06:00
Jeremy Friesen
a65954107f
Refactoring to add helper method (#16064)
* Refactoring to add helper method

Prior to this commit, we made view level calls to service modules.  This
refactor provides convenience methods on the model.

Furthermore, it addresses a few Rubocop violations that "come along for
the ride."

* Ensuring cached entity squaks like User

* Fixing broken spec

* Fixing typo
2022-01-12 11:21:44 -05:00
Daniel Uber
c489971ecf
Allow admin control of auth broadcast messages (was: Don't suggest apple authentication) (#16069)
* Don't send auth broadcasts for providers that are in beta

Currently we have :apple as a restricted provider (you can enable it,
but it's treated as beta here, rather than generally available).

While we were correctly checking if you had all GA providers enabled
in authenticated_with_all_providers?, we were incorrectly pulling
all enabled provider names in find_auth_broadcast (the message to send
the user), and picking apple_connect.

Since it doesn't make sense to omit apple id login from consideration
when checking if all available auth methods are used, then recommend
that it be used consistently, capture this "GA" state as a method, and
use it both in the test "does this user have all available identity
providers enabled?" and the selection "which identity provider can I
suggest they setup?" consistently.

Since we're about to enable google as an auth source (in #15986) I'll
check with Josh if he expects this to be GA on release or in limited
beta.

* Clean up authenticated_with_all_providers?

We have a method identities that returns the enabled identities for
the user (a relation), and a method ga_providers that returns a list
of enabled and not beta provider symbols.

Change the set difference to use Array#all? (which will exit early on
the first failure). Efficiency note: while I think this reads
better,it's possible this issues a number of small (cheap) queries for
identity by user id and provider id, but there's a unique index on
(provider, user_id) that should be effective.

* Only check providers that have active broadcast messages

An admin can stop sending "connect using apple" follow ups by
disabling that broadcast.

I randomized the enabled/active broadcasts for connection options so
they're not always pulling the same (facebook? apple?) option every
time.

* Clean up lost thought in comment
2022-01-12 09:59:14 -06:00
Daniel Uber
f20b8bd412
Prefer named comparison #after? to numeric comparison on times (#16057)
ActiveSupport adds DateAndTime::Calculations#after? (and before?) -
which clarifies intent (users newer than the relative time are
skipped) of the early returns.
2022-01-11 15:34:20 -06:00
Daniel Uber
6a9757c8ef
Modify welcome notification generator to handle errors per-message (#16060)
* Modify welcome notification generator to handle errors per-message

The original flow aborted all processing when any
ActiveRecord::RecordNotFound exception was raised. This causes a
situation where a missing broadcast message (by title) causes that
notification message to fail, and each day the same failure to
occur (since it wasn't successfully sent the day before), blocking all
further messages.

We want these to proceed on the schedule implicit in the checks, and
failing early prevents that.

Modify the error handling to catch RecordNotFound on each message, and
continue throught the checks until a notification is enqueued or all
checks have been attempted.

* Run welcome broadcast check 4 hours after the user was created

This started to fail when I modified the generator (why? because the
user was 7 days old and _other_ notifications would be sent).

Ensure the user is 4 hours old before checking that the disabled
welcome broadcast message is checked, and not sent.
2022-01-11 14:27:21 -06:00
Ben Halpern
294b3471af
Proposing feed experiment 3: More comment count weight (#15993)
* Initial work

* Implement strategy injection into WeightedQueryStrategy

* Modify field_test config and adding variants

* Change orginal to constant and make some other adjustments

* Fix hardcoded test values
2022-01-11 11:05:06 -05:00
yheuhtozr
d794e70cbc
small non-views ruby i18n (#16004) 2022-01-11 10:05:18 +07:00
Jeremy Friesen
c5bf4bf880
Extracting duplicate logic (#16035)
Prior to this commit, we had two places that need to know the nuances
ofquerying for tag flares and what we should include in our queries for
serialization.

With this commit, we're factoring towards a common source of knowledge
and providing a much needed test for the expected output of this
serialization.

Loosely related to #15916, #15983, #15994, and #16032.
2022-01-10 15:19:04 -05:00
Suzanne Aitchison
54eaee899e
Update tag search and suggest (#15810)
* add needed fields to tag search

* specs

* add badge to tags suggest response (#15840)

* Add badge to tags suggest response

* Update tags_spec.rb

Co-authored-by: Jeremy Friesen <jeremy.n.friesen@gmail.com>

* limit tag search badge to only badge_image

* only unpack badge image if badge exists

Co-authored-by: Dwight Scott <dwight@forem.com>
Co-authored-by: Jeremy Friesen <jeremy.n.friesen@gmail.com>
2022-01-05 07:51:17 +00:00
Michael Kohl
ec9a5adcb5
Remove store_attribute gem (#15923) 2022-01-04 11:15:57 +07:00
Daniel Uber
349ba97a5e
Send custom user agent string when fetching feeds (#15942)
* Send custom user agent string when fetching feeds

dev.to blocks access to the feeds for user agent "Ruby"

Use "Forem Feeds Import" as alternate user agent when fetching feeds.

fixes https://github.com/forem/forem/issues/15939

* Update app/services/feeds/import.rb

Co-authored-by: Michael Kohl <citizen428@forem.com>

Co-authored-by: Michael Kohl <citizen428@forem.com>
2022-01-03 22:09:24 -06:00
Jeremy Friesen
6269aa4108
Proposing a new feed experiment (#15789)
* Proposing a new feed experiment

This commit involves tweaking a few subtle aspects of the challenger:

1) Remove the sort by published date on the relevance score.  The
   articles will now be listed in the order of perceived relevance.
2) Disable a few levers that did little.  There really aren't any
   `articles.featured = true` articles in the database.
3) Gently increase the weight of each comment in a linear manner.
4) Give a little more weight to posts that don't have followed tags.

In addition, it involves renaming the conversions to better convey their
implementation.  This renaming helps create more descriptive labels for
the test results at `/admin/abtests`.

This commit also adds logic to repurpose the AbExperiment feed_strategy
logic; I envision adjusting the weighted feed strategy levers with some
frequency.

Per discussions, I'm also disabling the "not logged in" feed testing.
We'll use the LargeForemExperimental for this.

* Flipping attribute name to positive

Mentally "not disabled" is harder to parse than "enabled".  This change
helps with setting an optimistic attribute.

* Bump for travis

* Bump for travis

* Removing file committed by mistake

* Extracting method
2022-01-03 14:38:14 -05:00
Jeremy Friesen
5430c2e203
Refactoring and documenting class (#15849)
* Refactoring and documenting class

I came to this commit by looking for raw `where` method calls to the
Article object.  Originally, I was looking at `where.not(user_id: :id)`
but found this service class.

In this class, I saw some significant duplication and went with a bit of
refactoring and some documentation.

This refactoring removed some unnecessary guards and calculations (as
documented inline).

* Naming a constant and adding more documentation
2022-01-03 09:30:41 -05:00
Daniel Uber
cd835c281f
Periodic Digest Email frequency should be in days (#15904)
* Use the most recent timestamp from sent digest messages

The original logic here had queried for up to 10 (unordered) messages
from the database for this user, perhaps leveraging the knowledge that
we purge old messages after 90 days to ensure 10 was enough.

Since the last message in the limited and unordered list could have
had any sent_at time in the past 90 days, it's possible users could
pass the "should send email" check multiple times in a day (and get
multiple digest emails, I'm not certain when the rake task runs but it
could be as frequently as once per deployment?)

Since we're only using this list of messages to find the most recently
sent message, select the maximum sent time.

* convert periodic_email_digest setting to days

Time.current - last_email_sent_at gives an integer count of elapsed
seconds

Settings::General.periodic_email_digest is an integer count of days
between digests.

Convert to days (so we're only sending digests when enough time has
elapsed) instead of defaulting to once every 2 seconds (or at least
several times per day).

* Clean up comparison

Rather than subtracting the current time from the last time, and
checking that the difference in time is greater than the periodic
setting, use days.ago to get the timestamp far enough in the past, and
ensure last email was sent before that ( `sent_at < n.days.ago` ).

This seems like it reads clearer than the original implementation.

* Prefer Time.before? to numeric comparison

Change the method name from last_email_sent_at to last_email_sent, so
that the comparison reads like English (the other callers use it as a
number)

And since the code reveals its intention clearly, there's no need for
an inline comment about the next line any more.
2021-12-30 09:23:24 -06:00
Jeremy Friesen
f2cf46d426
Refactoring to leverage an Article scope (#15850)
* Refactoring to leverage an Article scope

I've been looking at the queries that involve filtering articles based
on scores.  There's several places that seem to be close to consistent,
but have some nuanced difference.

This refactor consolidates one of those "almost the same" cases.

* Bump for travis
2021-12-29 09:25:31 -05:00
Michael Kohl
5da625cadb
Rubocop fixes (#15892)
* 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
2021-12-28 09:11:41 -06:00
Michael Kohl
06d6b68d9d
Remove webhooks and related code (#15827) 2021-12-28 10:56:37 +07:00
Josh Puetz
10c13078cb
User correct username in mobile mention notifications (#15861) 2021-12-22 10:31:22 -06:00
Jeremy Friesen
a40efc6bbd
Refactoring questions asked of user (#15762)
* 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
2021-12-21 12:45:12 -05:00
Michael Kohl
872b007c30
Remove Doorkeeper gem (#15749) 2021-12-21 12:29:58 +07:00
Daniel Uber
032378b3bd
Disable dash replacement filter in markdown fixer (#15839)
* 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.
2021-12-20 15:39:55 -06:00
Anna Buianova
9f688be406
Moved setting old_username from before_validation to Users::Update (#15782)
* Moved setting old_username from before_validation to Users::Update

* Removed unused code

* Fixed specs after moving setting old_usernames
2021-12-20 11:08:09 +03:00
Andy Zhao
6335f9a7e9
Remove profile when banish (#15818)
* Clear profile when banishing user

* Add test for clearing profile when banishing

* Also clear any social usernames
2021-12-17 15:36:35 -05:00
Jeremy Friesen
aa7712a80e
Extracting container for allowed tags & attrs (#15338)
* Extracting container for allowed tags & attrs

Prior to this commit, we had several different locations in which we
specified ALLOWED_TAGS and ALLOWED_ATTRIBUTES for HTML rendering and
sanitization.

Curious to see how these either intersected or didn't, I opted to
create a container module that allows for us to more readily normalize
these allowed tags and attributes.  It's possible that we won't do any
normalization, but this work helps make that easier.

Ideally, I'd love us to contextualize "why did we choose the
tags/attributes we chose?"  But for now, I think consolidating these
tags and attributes will help make adding a `details` and `summary` tag
easier.

This relates to forem/rfcs#296

See [Google Sheet][1] for analysis of what tags/attributes are used, the
intersection and union.

[1]:https://docs.google.com/spreadsheets/d/1yj-a1qus1o0o4cj-_gOMP5yteeg-_f3s5z7kvK0Y7RM/edit#gid=0

* Fixing misnamed constant

* Fixing misnamed constant

* Extracting additional HtmlRendering use cases

* Adding comparative documentation for HTML tags

* Fixing broken parameter signature

* Moving constants into MarkdownProcessor
2021-12-16 12:24:45 -05:00
Josh Puetz
731849a068
Mobile mention notifications (#15780) 2021-12-16 11:06:54 -06:00
Josh Puetz
3fd03b5ed6
Remove line break after linking username mentions (#15788) 2021-12-16 10:39:07 -06:00
ludwiczakpawel
0cce606938
Error message after authentication failure due to email address not being whitelisted (#15779)
* cosmetics

* cosmetics

* Build restart

* generator failing build?

* generator failing build?
2021-12-15 21:25:27 +01:00
Nick Taylor
6df9309284
Added the logo upload to the admin -> customization -> config -> images section. (#15729)
Co-authored-by: Michael Kohl <citizen428@forem.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Suzanne Aitchison <suzanne@forem.com>
Co-authored-by: Mac Siri <mac@forem.com>
Co-authored-by: Ridhwana <Ridhwana.Khan16@gmail.com>
2021-12-15 14:10:27 -05:00
Jamie Gaskins
cde4e08534
Automatically create user profile if it's missing (#15787)
I don't know how it's nil, but it is, so we can remediate that here
2021-12-15 14:03:51 -05:00
Jeremy Friesen
a5058d3744
Consolidating role query logic (#15773)
* Consolidating role query logic

Prior to this commit, we had two logically identical chunks of code.

With this commit, we consolidate that logic into a single method.  In
addition, we remove one place where the application knows about the
roles implementation.

Loosely related to #15624.

* Bump for travis
2021-12-15 10:49:32 -05:00
Daniel Uber
421dad2900
Remove reactions to a user when deleting the user (#15724)
* 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).
2021-12-10 11:24:23 -06:00
Daniel Uber
64568d3a3d
Use the rss item's url when handling relative image links (#15497)
* 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
2021-12-09 14:08:54 -06:00
Josh Soref
0403e78f08
Spelling (#15702)
* spelling: access

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: additional

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: administrative

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: aggregate

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: assigns

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: attributes

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: autocomplete

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: because

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: between

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: bootstrap

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: calculating

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: captcha

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: character

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: chosen

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: commenter

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: competitor

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: componentize

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: contrast

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: corresponding

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: description

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: destroyed

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: destroys

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: discussion

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: episode

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: escaped

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: evaluates

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: expired

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: explicitly

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: facebook

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: fragment

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: functionality

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: improper

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: incentive

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: interfere

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: latest

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: message

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: minimum

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: moderator

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: mouseover

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: mutual

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: nonexistent

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: notification

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: occasionally

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: occurrence

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: occurs

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: octokit

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: offset

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: omitted

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: opacity

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: organization

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: organizations

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: overridden

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: override

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: overriding

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: prefill

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: previous

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: profile

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: recycling

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: registered

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: repositories

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: rescuing

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: response

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: returns

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: second

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: separator

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: services

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: subscriber

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: subscription

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: success

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: successful

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: successfully

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: suppress

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: test

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: thought

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: uniqueness

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: unknown

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: unproductive

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: unreachable

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: unsuccessful

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: utilities

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: utility

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: valid

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: voluntarily

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: vomited

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: website

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: withholding

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

Co-authored-by: Josh Soref <jsoref@users.noreply.github.com>
2021-12-07 06:59:10 -07:00
Josh Soref
5324eb1477
Spelling fixes to live code (#15670)
Co-authored-by: Josh Soref <jsoref@users.noreply.github.com>
2021-12-06 12:11:25 +02:00
Daniel Uber
0eb4e690ed
Validate payment info present before attempting to process (#15629)
* 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
2021-12-03 13:09:23 -06:00
Jeremy Friesen
8c126ca2e0
Fixing blank home page for anonymous/visitor (#15665)
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)
2021-12-03 08:32:02 -05:00
Jeremy Friesen
c1e5d4884d
Deprecating User#trusted in favor of User#trusted? (#15639)
`User#trusted?` is more Ruby idiomatic than `User#trusted`.  This helps
align the various "User#question?" methods.

I've added a deprecation warning, but don't believe that this is active
in the code-base.
2021-12-02 08:54:58 -05:00