Skip to content

Commit

Permalink
More fixes for project access rework
Browse files Browse the repository at this point in the history
  • Loading branch information
varmar05 committed Nov 20, 2024
1 parent 75deca7 commit dcc7b86
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 30 deletions.
32 changes: 32 additions & 0 deletions server/mergin/sync/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ def __init__(
self.public = kwargs.get("public", False)
latest_files = LatestProjectFiles(project=self)
db.session.add(latest_files)
self.set_role(creator.id, ProjectRole.OWNER)

@property
def storage(self):
Expand Down Expand Up @@ -284,6 +285,29 @@ def members_by_role(self, role: ProjectRole) -> List[int]:
"""Project members' ids with at least required role (or higher)"""
return [u.user_id for u in self.project_users if ProjectRole(u.role) >= role]

def bulk_roles_update(self, access: Dict) -> Set[int]:
"""Update roles from access lists and return users ids of those affected by any action"""
id_diffs = []
for role in list(ProjectRole.__reversed__()):
# we might not want to modify all roles
if role not in access:
continue

for user_id in access.get(role):
if self.get_role(user_id) != role:
self.set_role(user_id, role)
id_diffs.append(user_id)

# make sure we do not have other user ids than in the list at this role
for user in self.project_users:
if ProjectRole(user.role) == role and user.user_id not in access.get(
role
):
self.unset_role(user.user_id)
id_diffs.append(user.user_id)

return set(id_diffs)


class ProjectRole(Enum):
"""Project roles ordered by rank (do not change)"""
Expand All @@ -298,6 +322,14 @@ def __ge__(self, other):
members = list(ProjectRole.__members__)
return members.index(self.name) >= members.index(other.name)

def __gt__(self, other):
members = list(ProjectRole.__members__)
return members.index(self.name) > members.index(other.name)

def __lt__(self, other):
members = list(ProjectRole.__members__)
return members.index(self.name) < members.index(other.name)


@dataclass
class ProjectAccessDetail:
Expand Down
8 changes: 5 additions & 3 deletions server/mergin/sync/public_api_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,9 +686,11 @@ def update_project(namespace, project_name): # noqa: E501 # pylint: disable=W0
:rtype: ProjectDetail
"""
project = require_project(namespace, project_name, ProjectPermissions.Update)
access = request.json.get("access", {})

id_diffs, error = current_app.ws_handler.update_project_members(project, access)
parsed_access = parse_project_access_update_request(request.json.get("access", {}))
# get set of modified user_ids and possible (custom) errors
id_diffs, error = current_app.ws_handler.update_project_members(
project, parsed_access
)

if not id_diffs and error:
# nothing was done but there are errors
Expand Down
30 changes: 5 additions & 25 deletions server/mergin/sync/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@
ProjectAccessDetail,
ProjectVersion,
ProjectUser,
ProjectRole,
)
from .permissions import projects_query, ProjectPermissions
from .public_api_controller import parse_project_access_update_request
from ..app import db
from ..auth.models import User
from ..config import Configuration
Expand Down Expand Up @@ -277,33 +275,15 @@ def update_project_members(
) -> Tuple[Set[int], Optional[UpdateProjectAccessError]]:
"""Update project members doing bulk access update"""
error = None
parsed_access = parse_project_access_update_request(access)
id_diffs = []
for role in list(ProjectRole.__reversed__()):
# we might not want to modify all roles
if role not in parsed_access:
continue

for user_id in parsed_access.get(role):
if project.get_role(user_id) != role:
project.set_role(user_id, role)
id_diffs.append(user_id)

# make sure we do not have other user ids than in the list at this role
for user in project.project_users:
if ProjectRole(
user.role
) == role and user.user_id not in parsed_access.get(role):
project.unset_role(user.user_id)
id_diffs.append(user.user_id)

id_diffs = project.bulk_roles_update(access)
db.session.add(project)
db.session.commit()
if parsed_access.get("invalid_usernames") or parsed_access.get("invalid_ids"):

if access.get("invalid_usernames") or access.get("invalid_ids"):
error = UpdateProjectAccessError(
parsed_access["invalid_usernames"], parsed_access["invalid_ids"]
access["invalid_usernames"], access["invalid_ids"]
)
return set(id_diffs), error
return id_diffs, error

@staticmethod
def access_requests_query():
Expand Down
4 changes: 2 additions & 2 deletions server/mergin/tests/test_project_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def test_get_paginated_projects(client):
resp_data = json.loads(resp.data)
assert len(resp_data.get("projects")) == 10
assert resp_data.get("count") == 15
assert "foo8" in resp_data.get("projects")[9]["name"]
assert "foo7" in resp_data.get("projects")[9]["name"]
assert "v0" == resp_data.get("projects")[9]["version"]

resp = client.get(
Expand All @@ -199,7 +199,7 @@ def test_get_paginated_projects(client):
)
resp_data = json.loads(resp.data)
assert len(resp_data.get("projects")) == 5
assert "foo13" in resp_data.get("projects")[-1]["name"]
assert "foo12" in resp_data.get("projects")[-1]["name"]
# tests backward compatibility sort
resp_alt = client.get(
"/v1/project/paginated?page=2&per_page=10&order_by=namespace&descending=false"
Expand Down

0 comments on commit dcc7b86

Please sign in to comment.