Fix duplicate emails sent for PrAT and GrAT expiring tokens

What does this MR do and why?

Fix duplicate emails sent for PrAT and GrAT expiring tokens

When sending notifications to inherited members of a group or project, we sometimes send a duplicate of that email. This is because the finders may return multiple memebrship records for the same group / project hierarchy and user. These are usually filtered out by using distinct on user_id and invite_email , however it's possible for a user to be invited via email to a parent group and have a non-email direct membership in a subgroup or project. This will produce multiple Member records from the relevant Finder classes, and will result in duplicate emails being sent to the same user.

This change attempts to fix the above case for email notifications.

References

Please include cross links to any resources that are relevant to this MR. This will give reviewers and future readers helpful context to give an efficient review of the changes introduced.

MR acceptance checklist

Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Screenshots or screen recordings

Screenshots are required for UI changes, and strongly recommended for all other merge requests.

Before After

Database review

Postgres.ai private links:

tl;dr the only differences are the outer SELECT DISTINCT ON(user_id) and the lack of the paginated LIMIT 1000 from find_each

this branch:

master branch:

How to set up and validate locally

  1. Enable the feature flag for the group or instance-wide: Feature.enable(:pat_expiry_inherited_members_notification, :instance)
  2. Create or visit a group with an Ultimate license
  3. Invite a new user test-user to the group as an owner by entering their email address in the invite box - test-user should have a direct membership in the parent group "Invited by" the original user (the corresponding Member model should have something in the invite_email column)
  4. As test-user , create a sub-group: test-subgroup - test-user should now have a direct membership as "Owner" in test-subgroup
  5. As test-user , create a project in the sub-group: test-project
  6. Create a project access token on test-project expiring in 5 days
  7. Run the PersonalAccessTokens::ExpiringWorker either via the Rails console ( PersonalAccessTokens::ExpiringWorker.new.perform ) or via selecting Enqueue now in the Sidekiq page: https://gdk.test:3443/admin/sidekiq/cron/personal_access_tokens_expiring_worker
  8. Check letter-opener to ensure only one email is sent to test-user

Related to #463016 (closed)

Edited by Andrew Evans

Merge request reports

Loading