Investigation in !226612 uncovered larger issue with how we query for billed members. As the issue has a broader scope than initially identified, I'm adjusting the weight to
Group model, BilledUsersFinder, GroupMembersFinder, and MembersFinder
@karichards You're right, nice catch, we wouldn't want to lose any records. I just discovered another finder MembersFinder that handles a similar deduplication challenge that we could follow.
It uses a custom DISTINCT ON query that:
user_id, invite_email)last_joined or access_level_desc) would workWe could adapt this approach for BilledMembersFinder by creating a similar custom distinct_on_billed_members method that keeps the max access level and oldest join date, then lets Member.sort_by_attribute handle the requested sorting afterward. Wdyt?
is the suggestion to add
member_access_levelandmember_joined_dateto the response? I think the payload itself doesn't necessarily need new fields
@karichards Yes, that's my suggestion, but you're right that the payload doesn't need new fields. I suggested it thinking it might help clarify the sort order since the response currently doesn't return any member-specific data.
My thinking is that the fix is to sort the member records and then extract the users in that sorted order, WDYT?
For sure, that sounds like a good MVC, we can always add additional fields later if needed.
LGTM!
@vij Passing it off to you for maintainer review
Since this MR is focused on event details coverage, I'd suggest leaving the code in and having a separate follow-up MR to specifically update the stub and test the correct user.
Having said that, I'm not strongly opinionated either way and it'd be fine if we remove it now, as long as we address it in a follow-up.
Add tests for audit event details to the group SCIM deprovisioning service specs.
Issue: #588829
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Great initiative, thanks for the context!
This MR fixes broken links on the Communication page
Please verify the check list and ensure to tick them off before the MR is merged.
Sandra To (0b650c58) at 17 Mar 18:30
Fix broken links in communication
BilledUsersFinder to query users instead of members, preventing all member-specific sort options (access_level_asc, access_level_desc, last_joined, oldest_joined) from working. See more: !226612 (comment 3151751284)
BilledUsersFinder which calls User.sort_by_attribute instead of Member.sort_by_attribute
GroupMembersFinder uses distinct_on_user_with_max_access_level to remove duplicated users found, but it's designed for general member listing (ancestors, shared groups) rather than billing-specific filtering (banned users, guest billing rules)::Members::BilledMembersFinder that extends the existing pattern from BilledUserFinder and uses scopes from Group model to cover both billed group and project members. See MR diff: !226612 (diffs)
GroupMembersFinder or BilledUserFinder?BilledMembersFinder?cc @karichards
@abdwdd Will do, thanks! I just found GroupMembersFinder. Related to the other thread, this finder handles member deduplication using distinct_on_user_with_max_access_level. We should definitely review this with a domain expert to figure out the best approach.
Great catch! We can use the distinct_on_user_with_max_access_level scope from the Member model, which removes duplicates and selects the highest access level. It also uses the oldest join date as a tie-breaker when access levels are equal.
]).distinct_on_user_with_max_access_level(group)For sure, I'd be happy to document it! I've created a new BilledMembersFinder that properly handles member sort orders. I tested it locally and confirmed it works correctly for both access level and join date sorting.
Since you mentioned this may need rescoping, should I focus on documenting the findings for now, or would it be helpful to complete the remaining work:
Happy to keep going with the remaining work if you estimate it to be low-effort, or we can save it for later, whatever works best!
Yes, you're correct, thanks for catching that! Some more updates in another open thread: !226612 (comment 3152998038)
@abdwdd @karichards Thank you for the feedback!
By
joined, I understand that the users should be sorted by the date of joining the groupThis is how I understand it as well, based on the description of these attributes in the API reference.
That makes sense, you're absolutely right! I referenced Member.sort_by_attribute, and after checking the Member model more closely, I can see that the logic wouldn't be transferrable to User since Member.created_at (join date) is different from User.created_at (account creation date). Thank you both for pointing this out!
we're not joining on the members table and sorting
I think that join would be complex as it would require knowing about the specific group and its hierarchy to find relevant member records, plus handling cases where a user has multiple membership paths
🤔
Good news! It looks like the joins and some complex queries are already handled in the Group model for finding group projects and group/project members. We can reuse it! BilledMembersFinder below). See ee/app/models/ee/group.rb for existing implementation.
I'm surprised that the endpoint uses
BilledUsersFinderto query for the billable members rather than aBilledMembersFinderor the like that uses sorting options for members. It looks like we don't have something like this at the moment.
Great suggestion! Following the pattern in BilledUsersFinder and using the queries in the Group model, I created ::Members::BilledMembersFinder which properly accesses Members.sort_by_attribute and fixes the sorting for access_level_asc, access_level_desc , last_joined, and oldest_joined . Note: I had to place it in the Members module because rubocop requires new finders to be within a bounded context namespace. Please take a look: !226612 (diffs)
We can update the endpoint to use the new finder, then remove the new scopes added to Users , no database changes needed!
Since the endpoint is public-facing, I think the safest approach would be to continue returning users in the API response but add member_access_level and member_joined_date fields to provide the missing member data while maintaining backward compatibility. What do you think of this approach? Open to suggestions
Sandra To (32fb3850) at 12 Mar 04:13
Add BilledMembersFinder with member sort_by_attribute support