organisation user pins#953
Conversation
GitLab Pipeline ActionGeneral informationLink to pipeline: https://gitlab.com/code0-tech/development/sagittarius/-/pipelines/2499021059 Status: Passed Job summariesrspec: [cloud]Coverage report available at https://code0-tech.gitlab.io/-/development/sagittarius/-/jobs/14206894193/artifacts/tmp/coverage/index.html rspec: [ee]Coverage report available at https://code0-tech.gitlab.io/-/development/sagittarius/-/jobs/14206894192/artifacts/tmp/coverage/index.html rspec: [ce]Coverage report available at https://code0-tech.gitlab.io/-/development/sagittarius/-/jobs/14206894191/artifacts/tmp/coverage/index.html docs:previewDocumentation preview available at https://code0-tech.gitlab.io/-/development/telescopium/-/jobs/14206929445/artifacts/out/index.html rubocop788 files inspected, no offenses detected |
| [Types::GlobalIdType[::Organization]], | ||
| required: true, | ||
| description: 'Ordered list of organization IDs to pin for the user.' | ||
| argument :user_id, Types::GlobalIdType[::User], required: true, description: 'ID of the user to update.' |
There was a problem hiding this comment.
I would have used the current user rather than passing it as an argument. Or do you see a use case for an user updating the pins of another user?
|
|
||
| authorize :read_user_organization_pin | ||
|
|
||
| field :organization, Types::OrganizationType, null: false, description: 'The pinned organization' |
There was a problem hiding this comment.
If a user isn't allowed to see the organization (maybe they got removed from it after pinning it), this field will be null due to authorization. If the field couldn't be null, this will bubble up to the first nullable field and return an error.
| field :organization, Types::OrganizationType, null: false, description: 'The pinned organization' | |
| field :organization, Types::OrganizationType, null: true, description: 'The pinned organization' |
| end | ||
|
|
||
| def pinned_organizations | ||
| organization_pins.map(&:organization) |
There was a problem hiding this comment.
This would load all pins of the user and map them in memory with N+1 queries.
| organization_pins.map(&:organization) | |
| object.pinned_organizations |
We would loose the sorting though. I think we can probably remove the whole pinned_organizations field and only expose organization_pins.
Taucher2003
left a comment
There was a problem hiding this comment.
I think the Namespaces::Members::DeleteService should remove an organization pin when a user is removed from that organization.
| has_many :namespaces, through: :namespace_memberships, inverse_of: :users | ||
|
|
||
| has_many :user_identities, inverse_of: :user | ||
| has_many :user_organization_pins, -> { order(priority: :asc) }, inverse_of: :user, dependent: :delete_all |
There was a problem hiding this comment.
We use ON DELETE CASCADE in the schema, so we don't need this. Let the database handle the deletion of these records rather than rails doing it manually
| has_many :user_organization_pins, -> { order(priority: :asc) }, inverse_of: :user, dependent: :delete_all | |
| has_many :user_organization_pins, -> { order(priority: :asc) }, inverse_of: :user |
| class Organization < ApplicationRecord | ||
| include NamespaceParent | ||
|
|
||
| has_many :user_organization_pins, inverse_of: :organization, dependent: :delete_all |
There was a problem hiding this comment.
We use ON DELETE CASCADE in the schema, so we don't need this. Let the database handle the deletion of these records rather than rails doing it manually
| has_many :user_organization_pins, inverse_of: :organization, dependent: :delete_all | |
| has_many :user_organization_pins, inverse_of: :organization |
| validates :priority, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 } | ||
| validates :organization_id, uniqueness: { scope: :user_id } | ||
| validates :priority, uniqueness: { scope: :user_id } |
There was a problem hiding this comment.
Works, but we can use a single validates for priority
| validates :priority, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 } | |
| validates :organization_id, uniqueness: { scope: :user_id } | |
| validates :priority, uniqueness: { scope: :user_id } | |
| validates :priority, presence: true, | |
| numericality: { only_integer: true, greater_than_or_equal_to: 0 }, | |
| uniqueness: { scope: :user_id } | |
| validates :organization_id, uniqueness: { scope: :user_id } |
| class UserOrganizationPinPolicy < BasePolicy | ||
| delegate { subject.user } | ||
|
|
||
| rule { can?(:read_user) }.enable :read_user_organization_pin |
There was a problem hiding this comment.
Either we don't need this here or we don't need the enable for this ability in the UserPolicy.
Also, I don't think someone should be able to read the pins of another user.
| rule { can?(:read_user) }.enable :read_user_organization_pin | |
| condition(:user_is_self) { subject.id == user&.id } | |
| rule { user_is_self }.enable :read_user_organization_pin |
| rule { ~anonymous }.policy do | ||
| enable :read_user | ||
| enable :read_user_organization_pin | ||
| end |
There was a problem hiding this comment.
| rule { ~anonymous }.policy do | |
| enable :read_user | |
| enable :read_user_organization_pin | |
| end | |
| rule { ~anonymous }.enable :read_user |
| return ServiceResponse.error(message: 'Missing permission', error_code: :missing_permission) | ||
| end | ||
|
|
||
| organizations = Organization.where(id: organization_ids) |
There was a problem hiding this comment.
A user should only be able to pin organizations that it is a member of
| organizations = Organization.where(id: organization_ids) | |
| organizations = OrganizationsFinder.new(id: organization_ids, namespace_member_user: user).execute |
| end | ||
|
|
||
| AuditService.audit( | ||
| :user_updated, |
There was a problem hiding this comment.
This should be its own event
|
|
||
| t.rollback_and_return! ServiceResponse.error( | ||
| message: 'Failed to update user organization pins', | ||
| error_code: :invalid_user, |
There was a problem hiding this comment.
This should probably also be its own error code
|
|
||
| pins = user.reload.user_organization_pins.order(:priority) | ||
| expect(pins.pluck(:organization_id)).to eq(organization_ids) | ||
| expect(pins.pluck(:priority)).to eq([0, 1]) |
There was a problem hiding this comment.
This will always be successful because the test orders the pins by priority
| end | ||
|
|
||
| def execute | ||
| unless Ability.allowed?(current_authentication, :update_user, user) |
There was a problem hiding this comment.
Using update_user allows an admin to change the pins of a user. If we don't want that, we need a separate ability
Resolves: #556