Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion server/mergin/sync/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ def unset_role(self, user_id: int) -> None:

def get_member(self, user_id: int) -> Optional[ProjectMember]:
"""Get project member"""
from .permissions import ProjectPermissions

member = self._member(user_id)
if member:
return ProjectMember(
Expand All @@ -291,6 +293,7 @@ def get_member(self, user_id: int) -> Optional[ProjectMember]:
email=member.user.email,
project_role=ProjectRole(member.role),
workspace_role=self.workspace.get_user_role(member.user),
role=ProjectPermissions.get_user_project_role(self, member.user),
)

def members_by_role(self, role: ProjectRole) -> List[int]:
Expand Down Expand Up @@ -350,6 +353,7 @@ class ProjectMember:
username: str
workspace_role: WorkspaceRole
project_role: Optional[ProjectRole]
role: ProjectRole


@dataclass
Expand All @@ -359,7 +363,8 @@ class ProjectAccessDetail:
role: str
username: str
name: Optional[str]
project_permission: str
workspace_role: str
project_role: Optional[ProjectRole]
type: str


Expand Down
74 changes: 39 additions & 35 deletions server/mergin/sync/private_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ paths:
required: true
schema:
type: string
# // Kept for EE (collaborators + invitation) access, TODO: remove when a separate invitation endpoint is implemented
get:
tags:
- project
Expand All @@ -350,34 +351,29 @@ paths:
"404":
$ref: "#/components/responses/NotFoundResp"
x-openapi-router-controller: mergin.sync.private_api_controller
/project/{id}/public:
parameters:
- name: id
in: path
description: Project uuid
required: true
schema:
type: string
patch:
summary: Update direct project access (sharing)
operationId: update_project_access
summary: Update public project flag
operationId: update_project_public_flag
requestBody:
description: Request data
required: true
content:
application/json:
schema:
type: object
properties:
user_id:
type: integer
public:
type: boolean
nullable: true
role:
type: string
enum:
- owner
- writer
- editor
- reader
- none
example: writer
responses:
"200":
$ref: "#/components/schemas/ProjectAccessUpdated"
"204":
description: OK
"400":
$ref: "#/components/responses/BadStatusResp"
"401":
Expand Down Expand Up @@ -551,8 +547,7 @@ components:
- id
- type
- email
- project_permission
- role
- workspace_role
properties:
id:
description: User/Invitation (uu)id
Expand All @@ -569,16 +564,9 @@ components:
type: string
format: email
example: john.doe@example.com
role:
workspace_role:
description: Workspace role
type: string
enum:
- owner
- admin
- writer
- editor
- reader
- guest
$ref: "#/components/schemas/WorkspaceRole"
username:
description: Present only for type `member`
type: string
Expand All @@ -587,13 +575,13 @@ components:
description: Present only for type `member`
type: string
example: John Doe
project_permission:
type: string
enum:
- owner
- writer
- editor
- reader
role:
description: Project role defined as combination of project and workspace roles
$ref: "#/components/schemas/ProjectRole"
project_role:
nullable: true
description: Project role defined in database, not calculated version
$ref: "#/components/schemas/ProjectRole"
invitation:
description: Present only for type `invitation`
type: object
Expand Down Expand Up @@ -658,3 +646,19 @@ components:
items:
type: integer
example: [1]
WorkspaceRole:
type: string
enum:
- owner
- admin
- writer
- editor
- reader
- guest
ProjectRole:
type: string
enum:
- owner
- writer
- editor
- reader
21 changes: 4 additions & 17 deletions server/mergin/sync/private_api_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
AdminProjectSchema,
ProjectAccessSchema,
ProjectAccessDetailSchema,
ProjectVersionListSchema,
)
from .permissions import (
require_project_by_uuid,
Expand Down Expand Up @@ -304,28 +303,16 @@ def unsubscribe_project(id): # pylint: disable=W0612


@auth_required
def update_project_access(id: str):
"""Modify shared project access
def update_project_public_flag(id: str):
"""Modify the project's public flag

:param id: Project uuid
"""
project = require_project_by_uuid(id, ProjectPermissions.Update)

if "public" in request.json:
project.public = request.json["public"]

if "user_id" in request.json and "role" in request.json:
user = User.query.filter_by(
id=request.json["user_id"], active=True
).first_or_404("User does not exist")

if request.json["role"] == "none":
project.unset_role(user.id)
else:
project.set_role(user.id, ProjectRole(request.json["role"]))
project_access_granted.send(project, user_id=user.id)
project.public = request.json.get("public", False)
db.session.commit()
return ProjectAccessSchema().dump(project), 200
return NoContent, 204


@auth_required
Expand Down
7 changes: 7 additions & 0 deletions server/mergin/sync/public_api_v2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,11 @@ components:
- reader
- guest
example: writer
Role:
allOf:
- $ref: '#/components/schemas/ProjectRole'
nullable: false
description: combination of workspace role and project role
ProjectMember:
type: object
properties:
Expand All @@ -282,3 +287,5 @@ components:
$ref: '#/components/schemas/WorkspaceRole'
project_role:
$ref: '#/components/schemas/ProjectRole'
role:
$ref: '#/components/schemas/Role'
1 change: 1 addition & 0 deletions server/mergin/sync/public_api_v2_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def get_project_collaborators(id):
email=user.email,
project_role=project_role,
workspace_role=workspace_role,
role=ProjectPermissions.get_user_project_role(project, user),
)
)

Expand Down
6 changes: 4 additions & 2 deletions server/mergin/sync/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,10 +358,11 @@ def _deserialize(self, value, attr, data, **kwargs):
class ProjectAccessDetailSchema(Schema):
id = StrOrInt()
email = fields.String()
role = fields.String()
role = fields.Enum(enum=ProjectRole, by_value=True)
username = fields.String()
name = fields.String()
project_permission = fields.String()
project_role = fields.Enum(enum=ProjectRole, by_value=True)
workspace_role = fields.Enum(enum=WorkspaceRole, by_value=True)
type = fields.String()
invitation = fields.Nested(ProjectInvitationAccessSchema())

Expand Down Expand Up @@ -404,3 +405,4 @@ class ProjectMemberSchema(Schema):
email = fields.Email()
project_role = fields.Enum(enum=ProjectRole, by_value=True)
workspace_role = fields.Enum(enum=WorkspaceRole, by_value=True)
role = fields.Enum(enum=ProjectRole, by_value=True)
14 changes: 9 additions & 5 deletions server/mergin/sync/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ def access_requests_query():
"""Project access base query"""
return AccessRequest.query.join(Project)

# not used in CE, TODO: remove together with EE when it's replaced there
def project_access(self, project: Project) -> List[ProjectAccessDetail]:
"""
Project access users overview
Expand All @@ -323,17 +324,19 @@ def project_access(self, project: Project) -> List[ProjectAccessDetail]:

direct_members_ids = [u.user_id for u in project.project_users]
users = User.query.filter(User.active.is_(True)).order_by(User.email)
direct_members = users.filter(User.id.in_(direct_members_ids)).all()
direct_members: list[User] = users.filter(User.id.in_(direct_members_ids)).all()

for dm in direct_members:
project_role = ProjectPermissions.get_user_project_role(project, dm)
project_permission = ProjectPermissions.get_user_project_role(project, dm)
project_role = project.get_role(dm.id)
member = ProjectAccessDetail(
id=dm.id,
username=dm.username,
role=ws.get_user_role(dm).value,
workspace_role=ws.get_user_role(dm).value,
name=dm.profile.name(),
email=dm.email,
project_permission=project_role and project_role.value,
role=project_permission and project_permission.value,
project_role=project_role.value if project_role else None,
type="member",
)
result.append(member)
Expand All @@ -345,8 +348,9 @@ def project_access(self, project: Project) -> List[ProjectAccessDetail]:
username=gm.username,
name=gm.profile.name(),
email=gm.email,
workspace_role=global_role,
role=global_role,
project_permission=global_role,
project_role=None,
type="member",
)
result.append(member)
Expand Down
Loading