Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AO3-6268 Fix All challenge owners/moderators get CCed in "Assignments sent" notification #4912

Open
wants to merge 20 commits into
base: master
Choose a base branch
from

Conversation

Cesium-Ice
Copy link
Contributor

@Cesium-Ice Cesium-Ice commented Sep 16, 2024

Pull Request Checklist

Issue

https://otwarchive.atlassian.net/browse/AO3-6268

Purpose

What does this PR do?

Testing Instructions

How can the Archive's QA team verify that this is working as you intended?

If you have a Jira account with access, please update or comment on the issue
with any new or missing testing instructions instead.

References

Are there other relevant issues/pull requests/mailing list discussions?

Credit

What name and pronouns should we use to credit you in the Archive of Our Own's Release Notes?

Cesium-Ice, they/them
If you have a Jira account, please include the same name in the "Full name"
field on your Jira profile, so we can assign you the issues you're working on.

Please note that if you do not fill in this section, we will use your GitHub account name and
they/them pronouns.

@Cesium-Ice
Copy link
Contributor Author

Running rubocop locally on the files changed in this PR brings up a lot of changes that the rubocop check doesn't seem to catch, should I commit the changes made by the rubocop auto-corrector as well?

Copy link
Contributor

@Bilka2 Bilka2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some notes. Also, could you write a cucumber scenario where the email notification is sent to two maintainers and translated for one and untranslated for the other? The cucumber steps for translated emails defined in email_custom_steps.rb should be helpful for checking the translation status.

should I commit the changes made by the rubocop auto-corrector as well?

It makes reviewing a lot easier to not have style corrections for unrelated lines. But on the other hand, it would be nice to have a consistent style. If you're up for it, you could make it a separate commit from the rest of the changes.

return parent.email if parent && !parent.email.blank?
"#{self.maintainers.collect(&:user).flatten.uniq.collect(&:email).join(',')}"
def maintainers_list
@maintainers_list = self.maintainers.collect(&:user).flatten.uniq
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't this just be returned instead of setting an instance variable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This both sets it as an instance variable and returns it. Rubocop complains about an unnecessary return when I return without setting the instance variable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think rubocop might complain about an extra return keyword, since Ruby returns the last statement by default. Hopefully it should be happy with this though:

Suggested change
@maintainers_list = self.maintainers.collect(&:user).flatten.uniq
self.maintainers.collect(&:user).flatten.uniq

end

def notify_maintainers(subject, message)
# send maintainers a notice via email
UserMailer.collection_notification(self.id, subject, message).deliver_later
@maintainers = self.maintainers_list
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this accessed somewhere later? If not, I think this shouldn't be assigned to an instance variable.

@maintainers = self.maintainers_list
# loop through maintainers and send each a notice via email
@maintainers.each do |i|
UserMailer.collection_notification(self.id, subject, message, i.email).deliver_later
Copy link
Contributor

@Bilka2 Bilka2 Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fulfill the Jira issue, please wrap this in a I18n.with_locale call with the users locale, like the other mailers (e.g. the batch_kudo_notification). Also, it would be a bit nicer code style to use something more descriptive like user for the loop variable.

@message = message
@collection = Collection.find(collection_id)
mail(
to: @collection.get_maintainers_email,
to: email,
subject: "[#{ArchiveConfig.APP_SHORT_NAME}][#{@collection.title}] #{subject}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Regarding your comment on Jira, this is the related issue: The subject locale should include the whole string with the placeholders for the short_name and the collection title, not just the last part.

But not relevant for this PR.)

return parent.email if parent && !parent.email.blank?
"#{self.maintainers.collect(&:user).flatten.uniq.collect(&:email).join(',')}"
def maintainers_list
@maintainers_list = self.maintainers.collect(&:user).flatten.uniq
end

def notify_maintainers(subject, message)
Copy link
Contributor

@Bilka2 Bilka2 Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit of an annoying thing: The subject and message currently have their t() calls where this method is called and then the translation is passed in here. But that wont use the locale later when it is set per user with I18n.with_locale. So please move the subject and message translation for where this method is called into the (suggested) I18n.with_locale block.

Maybe they could even be moved to be directly in the UserMailer method.

@@ -374,7 +374,10 @@ def self.delayed_generate(collection_id)
end
end
REDIS_GENERAL.del(progress_key(collection))
UserMailer.potential_match_generation_notification(collection.id).deliver_later
@maintainers = collection.maintainers_list
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this accessed somewhere later? If not, I think this shouldn't be assigned to an instance variable.

invalid_signup_ids.each {|sid| REDIS_GENERAL.sadd invalid_signup_key(collection), sid}
UserMailer.invalid_signup_notification(collection.id, invalid_signup_ids).deliver_later
@maintainers = collection.maintainers_list
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this accessed somewhere later? If not, I think this shouldn't be assigned to an instance variable.

@Cesium-Ice
Copy link
Contributor Author

I left some notes. Also, could you write a cucumber scenario where the email notification is sent to two maintainers and translated for one and untranslated for the other? The cucumber steps for translated emails defined in email_custom_steps.rb should be helpful for checking the translation status.

Do you have suggestions on how to go about setting up a collection with two maintainers in cucumber?

When I am logged in as "mod1"
      And I go to "Holiday Swap" collection's page
      And I follow "Profile"
      And I follow "Membership"
      And I fill in "Add new members" with "participant1"
      And I press "Submit"

This gets as far as adding participant1 as a member but I don't know how to interact with the drop-down selector to change them into a collection owner

@Bilka2
Copy link
Contributor

Bilka2 commented Sep 18, 2024

Do you have suggestions on how to go about setting up a collection with two maintainers in cucumber?

There is a I have added a co-moderator "..." to collection "..." step that should hopefully do the job.

app/models/collection.rb Fixed Show resolved Hide resolved
@Cesium-Ice
Copy link
Contributor Author

I split off the notify_maintainers function because it was being used for different messages and I couldn't move the message translation into the locale block if I didn't know what message was actually going to be received, unsure if this is the best way to go about things

@Cesium-Ice
Copy link
Contributor Author

Cesium-Ice commented Sep 18, 2024

Does anyone know why rubocop seems to be inconsistent about the things it flags as errors vs the things it flags as warnings?

@Bilka2
Copy link
Contributor

Bilka2 commented Sep 20, 2024

Generally rubocop flags most things as warnings, but I have found that the error level doesn't matter much, usually all the things should be fixed. There might be some strangeness going on with the reporting of the warnings in the github actions due to some reviewdog changes, but rubocop itself should be working fine, especially locally.

Copy link
Contributor

@Bilka2 Bilka2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach to split notify_maintainers is a good idea! I left comments regarding that and some other things, which includes some more annoyances with the target email addresses.

@@ -92,7 +92,7 @@ def invitation_to_claim(invitation_id, archivist_login)
end

# Notifies a writer that their imported works have been claimed
def claim_notification(creator_id, claimed_work_ids, is_user=false)
def claim_notification(creator_id, claimed_work_ids, is_user = false)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is an autocorrection from rubocop? The method is getting changed in #4921 so I think it'd be best to revert this change to avoid merge conflicts.

Comment on lines -33 to +35
to: @user.email,
subject: "[#{ArchiveConfig.APP_SHORT_NAME}]#{'[' + @collection.title + ']'} Request to include work in a collection"
)
to: @user.email,
subject: "[#{ArchiveConfig.APP_SHORT_NAME}]#{'[' + @collection.title + ']'} Request to include work in a collection"
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be easier to avoid this specific rabbithole of rubocop warnings from reviewdog by not changing this unrelated bit of code at all.

@@ -160,7 +160,7 @@ def invite_increase_notification(user_id, total)
I18n.with_locale(@user.preference.locale.iso) do
mail(
to: @user.email,
subject: "#{t 'user_mailer.invite_increase_notification.subject', app_name: ArchiveConfig.APP_SHORT_NAME}"
subject: t("user_mailer.invite_increase_notification.subject", app_name: ArchiveConfig.APP_SHORT_NAME.to_s)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's get this to an even better code style:

Suggested change
subject: t("user_mailer.invite_increase_notification.subject", app_name: ArchiveConfig.APP_SHORT_NAME.to_s)
subject: default_i18n_subject(app_name: ArchiveConfig.APP_SHORT_NAME)

Comment on lines +17 to +19
self.request_signup.present? &&
self.offer_signup.present? &&
!self.request_signup.request_potential_matches.pluck(:offer_signup_id).include?(self.offer_signup_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be easier to avoid this specific rabbithole of rubocop warnings from reviewdog by not changing this unrelated bit of code at all.

Comment on lines -338 to -339
return self.email if !self.email.blank?
return parent.email if parent && !parent.email.blank?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More annoying things, sorry.

These two lines of code are also needed for all the changed collection email sending. So if the collection email or parent collection email are set, send an untranslated email there. If not, send individual emails to all maintainers translated to the language they have selected.

Comment on lines 222 to 224
subject = t("user_mailer.collection_notification.challenge_default.subject", offer_byline: @challenge_assignment.offer_byline )
message = t("user_mailer.collection_notification.challenge_default.complete", offer_byline: @challenge_assignment.offer_byline, request_byline: @challenge_assignment.request_byline, assignments_page_link: collection_assignments_url(@challenge_assignment.collection))
@challenge_assignment.collection.notify_maintainers(subject, message)
Copy link
Contributor

@Bilka2 Bilka2 Sep 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The t() calls here should also be pulled into I18n.with_locale block in the notify_maintainers method, which could maybe be renamed to notify_maintainers_challenge_default to signify that specialization/split of the method.

"Signed-up participant #{@challenge_assignment.offer_byline} has defaulted on their assignment for #{@challenge_assignment.request_byline}. " +
"You may want to assign a pinch hitter on the collection assignments page: #{collection_assignments_url(@challenge_assignment.collection)}")
subject = t("user_mailer.collection_notification.challenge_default.subject", offer_byline: @challenge_assignment.offer_byline )
message = t("user_mailer.collection_notification.challenge_default.complete", offer_byline: @challenge_assignment.offer_byline, request_byline: @challenge_assignment.request_byline, assignments_page_link: collection_assignments_url(@challenge_assignment.collection))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use assignments_page_url as the interpolation variable name for collection_assignments_url.

And I press "Submit"
Then I should see "Sign-up was successfully created."

Given I have added a co-moderator "mod2" to collection "Holiday Swap"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Given I have added a co-moderator "mod2" to collection "Holiday Swap"
When I have added a co-moderator "mod2" to collection "Holiday Swap"

Given I have added a co-moderator "mod2" to collection "Holiday Swap"
And a locale with translated emails
And the user "mod1" enables translated emails
When I close signups for "Holiday Swap"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
When I close signups for "Holiday Swap"
And I close signups for "Holiday Swap"


Then 4 emails should be delivered
And "mod1" should receive 1 email
And the email to "mod1" should be translated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the mods it would be nice to check that it's also the right email, e.g. by checking the subject. The subject will be in English for both the translated and non-translated email, because the fake locale used by mod1 doesn't have translations for the subject and falls back to English.

app/models/collection.rb Fixed Show fixed Hide fixed
@Cesium-Ice
Copy link
Contributor Author

Sorry for all the commits but it seems like rubocop really wants me to internationalize collection.rb

validates_length_of :icon_comment_text, allow_blank: true, maximum: ArchiveConfig.ICON_COMMENT_MAX,
too_long: ts("must be less than %{max} characters long.", max: ArchiveConfig.ICON_COMMENT_MAX)
validates :name, presence: { message: I18n.t("collection.validation.name.presence") }
validates :name, uniqueness: { message: I18n.t("collection.validation.name.uniqueness") }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add write a migration script to add a database constraint so rubocop stops complaining about this, but it feels kinda weird to do that just to please the linter... should I do that or suppress the warning in some way?

Copy link
Contributor

@Bilka2 Bilka2 Sep 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not, that would go completely out of the scope of the original PR. Furthermore, please revert 450dbeb and ec338b0. While the dedication to i18n is appreciated, it would take a lot of extra work to correctly localise the errors and this PR is already quite large. We'd also risk a bug slipping through because manual QA wouldn't test this i18n.

Reviewdog/Rubocop will complain about the ts uses, but that's fine since we're aware that we wont be handling those in this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I've reverted the requested commits

Copy link
Contributor

@Bilka2 Bilka2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few more comments, thank you for your continued work on this.

Regarding tests, because this has quite a few changes to the "challenge default" email I think it'd be good to test that as well, with a setup similar to the other test you added.

Unfortunately I don't see a test for the fallback email behaviour (preferring the collection email, then the parent collection email) in any of the existing files. I'd appreciate if you could add a test for that as well, just to make sure the emails are getting sent to the right addresses. No need to check for translation behaviour there.

validates_format_of :header_image_url, allow_blank: true, with: URI::regexp(%w(http https)), message: ts("is not a valid URL.")
validates_format_of :header_image_url, allow_blank: true, with: /\.(png|gif|jpg)$/, message: ts("can only point to a gif, jpg, or png file."), multiline: true
validates :header_image_url, format: { allow_blank: true, with: URI::DEFAULT_PARSER.make_regexp(%w[http https]), message: ts("is not a valid URL.") }
validates :header_image_url, format: { allow_blank: true, with: /\A\S+\.(png|gif|jpg)\z/, message: ts("can only point to a gif, jpg, or png file."), multiline: true }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the security fix, lets make it even better

Suggested change
validates :header_image_url, format: { allow_blank: true, with: /\A\S+\.(png|gif|jpg)\z/, message: ts("can only point to a gif, jpg, or png file."), multiline: true }
validates :header_image_url, format: { allow_blank: true, with: /\A\S+\.(png|gif|jpg)\z/, message: ts("can only point to a gif, jpg, or png file.")}

Comment on lines 222 to 223
offer_byline = @challenge_assignment.offer_byline
request_byline = @challenge_assignment.request_byline
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More i18n fun times! This needs to be inside the with_locale block too, because it creates text that needs to be localised. More on that in the next comment ...

if offer_signup && offer_signup.pseud
offer_signup.pseud.byline
else
(pinch_hitter ? (pinch_hitter.byline + "* (pinch hitter)") : "- none -")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... for the i18n fun times, this is what needs to be localised. Please use an interpolation variable for the byline and include the formatting (the asterisk and parens and for the other string the dashes) in the localised text.

Same goes for request_byline.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a particular reason why None is capitalized request byline but not offer byline?

Copy link
Contributor

@Bilka2 Bilka2 Sep 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not, the previous code is quite old. From what I could find out from talking to people, this rarely shows up in emails, since the codepath is only taken if the user is deleted.

Comment on lines 343 to 346
if self.email.present?
UserMailer.collection_notification(self.id, subject, message, self.email).deliver_later
elsif self.parent && self.parent.email.present?
UserMailer.collection_notification(self.id, subject, message, self.parent.email).deliver_later
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This email condition (and the other instances of it) could be shortened by making a method that gets the collection email with the fallback to the parent collection email, so you only need one if.

Copy link
Contributor

@Bilka2 Bilka2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for wrangling this annoying bit of code!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants