Draft: Mark Organization and Group as "not isolated"
What does this MR do and why?
Most data in the database belongs to an organization and in many cases also to a namespace. If we want to transfer a Top Level Group to an organization, we need to be sure that all the data in that group is part of the same organization.
We expect that the logic will work like this:
- A crawler will establish that a group is isolated
- The logic in this MR will check if the group (or organization) is still isolated
Implementation
-
after_commit, we check if anybelongs_toassociations have been updated - If so, a
Organizations::CheckOrganizationIsolationStatusWorkeris scheduled. Arguments: model name, record id, changed fields - The worker returns if the record is not found or the state of the record has been changed
- The worker will call
Gitlab::Organizations::IsolationStatus.new(record, changed_associations).verify! - This class will check if the record and the updated
belongs_torecord belong to the same organization. - If they don't match, the isolation state of the Organization and (if exist) the Namespace will be changed to false
References
Related to #577780
How to set up and validate locally
Adding a member to a group
While working in Default Organization, we will invate an user from another organization. This will change the isolation status to false for both the group and the organization
Use rails console to create a user in another user:
my_org = Organizations::Organization.find_or_create_by!(path: 'my-org') { |org| org.name = 'My Org' }
# Mark groups and organizations as isolated
Organizations::Organization.all.each{|o| o.mark_as_isolated! }
Group.all.each{|g| g.mark_as_isolated!}
root = User.find_by(username: 'root')
other_user = User.find_by(username: 'user-in-my-org') || ::Users::AuthorizedCreateService.new(root, {name: 'User In MyOrg', username: 'user-in-my-org', organization_id: my_org.id, email: 'test@example.org', password: 'r234234cc#'}).execute
# We will use the group 'twitter' and the 'Default org'
# Both should be isolated:
Group.find_by(path: 'twitter').isolated?
Organizations::Organization.find_by(path: 'default').isolated?
Use the web interface to add a user to 'Twitter' group
- Go to http://gdk.test:3000/groups/twitter/-/group_members
- Click 'Invite members'
- In the username field, search user
user-in-my-org - Click 'Invite'
Return to Rails console and check isolation status:
Group.find_by(path: 'twitter').isolated?
Organizations::Organization.find_by(path: 'default').isolated?
# Remove member
other_user.destroy
Test composite primary key
my_org = Organizations::Organization.find_or_create_by!(path: 'my-org') { |org| org.name = 'My Org' }
# Mark groups and organizations as isolated
Organizations::Organization.all.each{|o| o.mark_as_isolated! }
Group.all.each{|g| g.mark_as_isolated!}
root = User.find_by(username: 'root')
other_user = User.find_by(username: 'user-in-my-org') || ::Users::AuthorizedCreateService.new(root, {name: 'User In MyOrg', username: 'user-in-my-org', organization_id: my_org.id, email: 'test@example.org', password: 'r234234cc#'}).execute
root.organization.isolated? # true
Now, while logged in as user root:
- Go to profile page http://gdk.test:3000/user-in-my-org
- Click
Follow
root.organization.isolated? # Is now false
# Cleanup
Users::UserFollowUser.where(follower: root, followee: other_user).delete_all
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.