Skip to content

Commit

Permalink
add route to update project members
Browse files Browse the repository at this point in the history
  • Loading branch information
dancoates committed Jun 17, 2024
1 parent e30590f commit 8a779ea
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 13 deletions.
17 changes: 14 additions & 3 deletions api/routes/project.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
from fastapi import APIRouter
from fastapi import APIRouter, HTTPException

from api.utils.db import (
Connection,
get_project_db_connection,
get_projectless_db_connection,
)
from db.python.tables.project import ProjectMemberWithRole, ProjectPermissionsTable
from models.models.project import FullWriteAccessRoles, Project, ProjectMemberRole
from models.models.project import (
FullWriteAccessRoles,
Project,
ProjectMemberRole,
project_member_role_names,
)

router = APIRouter(prefix='/project', tags=['project'])

Expand Down Expand Up @@ -105,7 +110,6 @@ async def delete_project_data(
success = await ptable.delete_project_data(
project_id=connection.project.id,
delete_project=delete_project,
author=connection.author,
)

return {'success': success}
Expand All @@ -124,6 +128,13 @@ async def update_project_members(

await ptable.check_member_admin_permissions(author=connection.author)
assert connection.project

for member in members:
if member['role'] not in project_member_role_names:
raise HTTPException(
400, f'Role {member["role"]} is not valid for member {member["member"]}'
)

await ptable.set_project_members(project=connection.project, members=members)

return {'success': True}
59 changes: 50 additions & 9 deletions db/python/tables/project.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# pylint: disable=global-statement
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Tuple

from databases import Database
from typing_extensions import TypedDict

from api.settings import is_all_access
from db.python.utils import Forbidden, NotFoundError, get_logger, to_db_json
from models.models.project import Project, ProjectMemberRole
from models.models.project import Project, project_member_role_names

# Avoid circular import for type definition
if TYPE_CHECKING:
Expand Down Expand Up @@ -188,7 +188,6 @@ async def update_project(self, project_name: str, update: dict, author: str):
async def delete_project_data(self, project_id: int, delete_project: bool) -> bool:
"""
Delete data in metamist project, requires project_creator_permissions
Can optionally delete the project also.
"""
if delete_project:
# stop allowing delete project with analysis-runner entries
Expand Down Expand Up @@ -239,16 +238,58 @@ async def delete_project_data(self, project_id: int, delete_project: bool) -> bo
return True

async def set_project_members(
self, project: Project, members: list[ProjectMemberRole]
self, project: Project, members: list[ProjectMemberWithRole]
):
"""
Set group members for a group (by name)
"""
print('@TODO')
# group_id = await self.gtable.get_group_name_from_id(group_name)
# await self.gtable.set_group_members(
# group_id, members, audit_log_id=await self.audit_log_id()
# )

async with self.connection.transaction():

# Get existing rows so that we can keep the existing audit log ids
existing_rows = await self.connection.fetch_all(
"""
select project_id, member, role, audit_log_id
from project_member
where project_id = :project_id
""",
{'project_id': project.id},
)

audit_log_id_map: dict[Tuple[str, str], int | None] = {
(r['member'], r['role']): r['audit_log_id'] for r in existing_rows
}

# delete existing rows for project
await self.connection.execute(
"""
DELETE FROM project_member
WHERE project_id = :project_id
""",
{'project_id': project.id},
)

new_audit_log_id = await self.audit_log_id()

await self.connection.execute_many(
"""
INSERT INTO project_member
(project_id, member, role, audit_log_id)
VALUES (:project_id, :member, :role, :audit_log_id);
""",
[
{
'project_id': project.id,
'member': m['member'],
'role': m['role'],
'audit_log_id': audit_log_id_map.get(
(m['member'], m['role']), new_audit_log_id
),
}
for m in members
if m['role'] in project_member_role_names
],
)

# endregion CREATE / UPDATE

Expand Down
2 changes: 1 addition & 1 deletion models/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def is_test(self):
"""
return self.name == f'{self.dataset}-test'

@field_serializer("roles")
@field_serializer('roles')
def serialize_roles(self, roles: set[ProjectMemberRole], _info):
return [r.name for r in roles]

Expand Down

0 comments on commit 8a779ea

Please sign in to comment.