Establish billable member membership type with a Group
What does this MR do?
Adds an additional attribute to the BillableMember
entity for the GET /api/v4/groups/:id/billable_members
REST endpoint.
Why?
We recently added the ability to remove billable members from a root group within the seat usage page.
This uncovered an edge case problem when removing a billable member that could belong to a group outside of the root group hierarchy:
graph TB
subgraph Invited/Shared Group associations
E(Outside Group)-->|Member|F(User C)
E-->|Member| G(User D)
end
D-->|GroupGroupLink|E
subgraph Root Group Associations
A[Root Group] -->|Member| B(User A)
A-->|Member| C(User B)
A-->D[Sub-Group]
end
In this example, User C
and User D
are not direct members of Root Group
but are considered billable within Root Group
.
We cannot individually remove either of those members from Root Group
because of the relationships and implications on having partial-group access - groups are invited as a whole and should continue to have access as a whole.
What is the solution?
The currently agreed solution is to identify which members are from a group invite and expose that to the frontend, which can then remove the ability to try and delete them.
This is more complicated than it appears on the surface, because Group -> User associations are represented by a Member
record in the database, but this is not the case with members of invited/shared groups. These are associated via the GroupGroupLink
join table (demonstrated in the diagram above).
These associations are handled already when calculating billable members, and a somewhat expensive set of queries are already performed to generate a Set of user IDs that are billable, throughout a root Group's hierarchy.
This MR attempts to leverage that work by making the various sets of IDs accessible as a hash to compare against to establish how they're associated, rather than re-performing the expensive queries for each user in the entity (or some other location).
Testing
curl --request GET \
--url http://127.0.0.1:3000/api/v4/groups/:group_id/billable_members \
--header 'PRIVATE-TOKEN: <your private token>'
Refs #324658 (closed)
Does this MR meet the acceptance criteria?
Conformity
-
📋 Does this MR need a changelog?-
I have included a changelog entry. -
I have not included a changelog entry because _____.
-
-
Documentation (if required) -
Code review guidelines -
Merge request performance guidelines -
Style guides -
Database guides -
Separation of EE specific content
Availability and Testing
-
Review and add/update tests for this feature/bug. Consider all test levels. See the Test Planning Process. -
Tested in all supported browsers -
Informed Infrastructure department of a default or new setting change, if applicable per definition of done
Security
If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:
-
Label as security and @ mention @gitlab-com/gl-security/appsec
-
The MR includes necessary changes to maintain consistency between UI, API, email, or other methods -
Security reports checked/validated by a reviewer from the AppSec team