Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return combination of verbs if user is assigned multiple roles on the same project #486

Closed
ktuite opened this issue May 16, 2022 · 0 comments · Fixed by #507
Closed

Return combination of verbs if user is assigned multiple roles on the same project #486

ktuite opened this issue May 16, 2022 · 0 comments · Fixed by #507
Labels

Comments

@ktuite
Copy link
Member

ktuite commented May 16, 2022

This is for the unusual case (not even supported by frontend) that the same user is assigned multiple roles on the same project.

The endpoint /v1/projects/<id> (extended version) returns a list of verbs the user can do on that project that is computed with this auth.verbsOn query:

const verbsOn = (actorId, actee) => ({ all }) => {
const acteeId = actee.acteeId || actee;
return all(sql`
${_impliedActees(acteeId)}
select verbs from roles
inner join (select "roleId" from assignments
inner join implied on implied.id=assignments."acteeId"
where "actorId"=${actorId})
as assignments on assignments."roleId"=roles.id`)
// TODO: it miiiiight be possible to make postgres do this work?
.then(compose(uniq, flatten, map((r) => r.verbs)));
};
and assigned to the Project here:
? auth.verbsOn(project).then((verbs) => Object.assign({ verbs }, project.forApi()))

The endpoint /v1/projects?forms=true also returns verbs for each project (added in Central v1.5), but is computed with the Projects.getAllByAuthWithForms query. Currently. this query chooses the verbs of the role with the lowest ID. There are some assumptions baked in here about the lower the ID, the more permissive the role, which is true for the current set of roles, but could certainly change.

inner join
(select id, min("roleId") as "bestRole" from projects
inner join
(select "acteeId", role.id as "roleId", role.verbs from assignments
inner join (select id, verbs from roles where verbs ?& array['project.read', 'form.list']) as role
on role.id=assignments."roleId"
where "actorId"=${actorId}) as assignment
on assignment."acteeId" in ('*', 'project', projects."acteeId")
group by id) as filtered
on filtered.id=projects.id

Instead of this approach, we might want to change the query to return the combined list of verbs for both roles. A different approach to try is in this comment of the PR adding verbs to the project + form list: #484 (comment)

From @matthew-white:

Just to recap our conversation from yesterday, things get tricky when a user has multiple roles (for example, if a user is both an administrator and a project manager for some reason). Right now in that case, this query returns the verbs from a single role. It selects the role with the smallest id, with the thought that in Central right now, more powerful roles have had smaller ids. I think it'd be awesome if we could somehow aggregate the verbs from all the roles. That way, /v1/projects and /v1/projects/:id would return the same set of verbs for any given project. I took a look at the list of JSON functions, but I didn't see a function that would do that aggregation specifically. However, one strategy seems to be to convert each element of each array to a row, then aggregate the rows. Based on a Stack Overflow answer that looks promising, here's a rough attempt at such a subquery:

inner join (
  select id, jsonb_agg(distinct value) as verbs
  from (
    select projects.id, roles.verbs
    from projects
    join assignments on
      assignments."actorId" = ${actorId} and
      assignments."acteeId" in ('*', 'project', projects."acteeId")
    join roles on roles.id = assignments."roleId"
    group by projects.id, roles.verbs
  ) as project_verbs, jsonb_array_elements_text(verbs)
  group by id
  having verbs ? 'project.read'
) as filtered on filtered.id = projects.id
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants