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

Use v2 update project access #349

Merged
merged 6 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
1 change: 1 addition & 0 deletions server/mergin/sync/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ class ProjectAccessDetail:
username: str
name: Optional[str]
project_permission: str
project_role: Optional[ProjectRole]
type: str


Expand Down
8 changes: 8 additions & 0 deletions server/mergin/sync/private_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,14 @@ components:
- writer
- editor
- reader
project_role:
varmar05 marked this conversation as resolved.
Show resolved Hide resolved
type: string
nullable: true
enum:
- owner
- writer
- editor
- reader
invitation:
description: Present only for type `invitation`
type: object
Expand Down
1 change: 0 additions & 1 deletion 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
1 change: 1 addition & 0 deletions server/mergin/sync/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ class ProjectAccessDetailSchema(Schema):
username = fields.String()
name = fields.String()
project_permission = fields.String()
project_role = fields.String()
varmar05 marked this conversation as resolved.
Show resolved Hide resolved
type = fields.String()
invitation = fields.Nested(ProjectInvitationAccessSchema())

Expand Down
9 changes: 6 additions & 3 deletions server/mergin/sync/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,17 +323,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,
name=dm.profile.name(),
email=dm.email,
project_permission=project_role and project_role.value,
project_permission=project_permission and project_permission.value,
project_role=project_role.value if project_role else None,
type="member",
)
result.append(member)
Expand All @@ -347,6 +349,7 @@ def project_access(self, project: Project) -> List[ProjectAccessDetail]:
email=gm.email,
role=global_role,
project_permission=global_role,
project_role=None,
type="member",
)
result.append(member)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ const changeStatusDialog = () => {
await adminStore.updateUser({
username: user.value.username,
data: {
active: !user.value.active
active: !user.value.active,
is_admin: user.value.is_admin
}
})
}
Expand Down
18 changes: 7 additions & 11 deletions web-app/packages/lib/src/common/permission_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export enum WorkspaceRole {
}

export enum ProjectRole {
none,
reader,
editor,
writer,
Expand All @@ -37,9 +36,10 @@ export type WorkspaceRoleName =
| 'admin'
| 'owner'

export type ProjectRoleName =
| Extract<WorkspaceRoleName, 'reader' | 'editor' | 'writer' | 'owner'>
| 'none'
export type ProjectRoleName = Extract<
WorkspaceRoleName,
'reader' | 'editor' | 'writer' | 'owner'
>

export type ProjectPermissionName = 'owner' | 'write' | 'edit' | 'read'

Expand All @@ -63,15 +63,13 @@ export const USER_ROLE_BY_NAME: Record<WorkspaceRoleName, WorkspaceRole> = {
}

export const PROJECT_ROLE_NAME_BY_ROLE: Record<ProjectRole, ProjectRoleName> = {
[ProjectRole.none]: 'none',
varmar05 marked this conversation as resolved.
Show resolved Hide resolved
[ProjectRole.reader]: 'reader',
[ProjectRole.editor]: 'editor',
[ProjectRole.writer]: 'writer',
[ProjectRole.owner]: 'owner'
}

export const PROJECT_ROLE_BY_NAME: Record<ProjectRoleName, ProjectRole> = {
none: ProjectRole.none,
reader: ProjectRole.reader,
editor: ProjectRole.editor,
writer: ProjectRole.writer,
Expand Down Expand Up @@ -191,21 +189,19 @@ export function getProjectAccessKeyByRoleName(
owner: 'ownersnames',
writer: 'writersnames',
editor: 'editorsnames',
reader: 'readersnames',
none: undefined
reader: 'readersnames'
}
return mapper[roleName]
}

export function getProjectPermissionByRoleName(
roleName: ProjectRoleName
): ProjectPermissionName {
const mapper: Record<ProjectRoleName, ProjectPermissionName | undefined> = {
const mapper: Record<ProjectRoleName, ProjectPermissionName> = {
owner: 'owner',
writer: 'write',
editor: 'edit',
reader: 'read',
none: undefined
reader: 'read'
}
return mapper[roleName]
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ export default defineComponent({
await this.acceptProjectAccessRequest({
data,
itemId: request.id,
namespace: this.namespace
workspace: this.namespace
})
await this.updatePaginationOrFetch()
} catch (err) {
Expand All @@ -200,7 +200,7 @@ export default defineComponent({
async cancelRequest(request) {
await this.cancelProjectAccessRequest({
itemId: request.id,
namespace: this.namespace
workspace: this.namespace
})
await this.updatePaginationOrFetch()
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export default defineComponent({
await this.acceptProjectAccessRequest({
data,
itemId: request.id,
namespace: this.project.namespace
workspace: this.project.namespace
})
await this.updatePaginationOrFetch()
} catch (err) {
Expand All @@ -173,7 +173,7 @@ export default defineComponent({
async cancelRequest(request) {
await this.cancelProjectAccessRequest({
itemId: request.id,
namespace: this.project.namespace
workspace: this.project.namespace
})
await this.updatePaginationOrFetch()
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ function removeMember(item: ProjectAccessDetail) {
function roleUpdate(item: ProjectAccessDetail, value: ProjectRoleName) {
projectStore.updateProjectAccess({
projectId: projectStore.project.id,
userId: item.id,
access: item,
data: { role: value }
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,6 @@ export default defineComponent({
default: false
},
namespace: String,
asAdmin: {
type: Boolean,
default: false
},
public: {
type: Boolean,
default: true
Expand Down Expand Up @@ -136,9 +132,6 @@ export default defineComponent({
if (projectGridState.namespace) {
params.only_namespace = projectGridState.namespace
}
if (this.asAdmin) {
params.as_admin = true
}
if (!this.public) {
params.public = false
}
Expand Down
37 changes: 25 additions & 12 deletions web-app/packages/lib/src/modules/project/projectApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ import {
ProjectAccessDetail,
ProjectAccess,
ProjectVersionFileChange,
UpdateProjectPayload,
UpdatePublicFlagParams
UpdateProjectCollaboratorPayload,
UpdatePublicFlagParams,
ProjectCollaborator,
AddProjectCollaboratorPayload
} from '@/modules/project/types'

export const ProjectApi = {
Expand Down Expand Up @@ -174,17 +176,29 @@ export const ProjectApi = {
)
},

async updateProjectAccess(
async addProjectCollaborator(
id: string,
data: AddProjectCollaboratorPayload
): Promise<AxiosResponse<ProjectCollaborator>> {
return ProjectModule.httpService.post(
`/v2/projects/${id}/collaborators`,
data,
{
validateStatus
}
)
},

async updateProjectCollaborator(
id: string,
userId: number,
data: UpdateProjectPayload,
withRetry?: boolean
): Promise<AxiosResponse<ProjectAccess>> {
data: UpdateProjectCollaboratorPayload
): Promise<AxiosResponse<ProjectCollaborator>> {
return ProjectModule.httpService.patch(
`/v2/projects/${id}/collaborators/${userId}`,
data,
{
...(withRetry ? getDefaultRetryOptions() : {})
validateStatus
}
)
},
Expand All @@ -199,15 +213,14 @@ export const ProjectApi = {
})
},

async removeProjectAccess(
async removeProjectCollaborator(
id: string,
userId: number,
withRetry?: boolean
): Promise<AxiosResponse<ProjectAccess>> {
userId: number
): Promise<AxiosResponse<void>> {
return ProjectModule.httpService.delete(
`/v2/projects/${id}/collaborators/${userId}`,
{
...(withRetry ? getDefaultRetryOptions() : {})
validateStatus
}
)
},
Expand Down
49 changes: 29 additions & 20 deletions web-app/packages/lib/src/modules/project/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,9 @@ import {
SaveProjectSettings,
ErrorCodes,
ProjectAccessDetail,
UpdateProjectAccessParams,
ProjectVersionFileChange,
ProjectVersionListItem,
UpdateProjectPayload,
UpdateProjectCollaboratorPayload,
UpdatePublicFlagParams
} from '@/modules/project/types'
import { useUserStore } from '@/modules/user/store'
Expand Down Expand Up @@ -757,15 +756,14 @@ export const useProjectStore = defineStore('projectModule', {
async removeProjectAccess(
item: Pick<ProjectAccessDetail, 'id' | 'username'>
) {
const notificationStore = useNotificationStore()
this.accessLoading = true
const notificationStore = useNotificationStore()
try {
const response = await ProjectApi.removeProjectAccess(
await ProjectApi.removeProjectCollaborator(
this.project.id,
item.id
Number(item.id)
)
this.access = this.access.filter((access) => access.id !== item.id)
this.project.access = response.data
} catch {
notificationStore.error({
text: `Failed to update project access for user ${item.username}`
Expand All @@ -783,33 +781,44 @@ export const useProjectStore = defineStore('projectModule', {
*/
async updateProjectAccess(payload: {
projectId: string
userId: number
data: UpdateProjectPayload
access: ProjectAccessDetail
data: UpdateProjectCollaboratorPayload
}) {
const notificationStore = useNotificationStore()
this.accessLoading = true
try {
const response = await ProjectApi.updateProjectAccess(
payload.projectId,
payload.userId,
payload.data
)
if (!payload.access.project_role) {
await ProjectApi.addProjectCollaborator(payload.projectId, {
...payload.data,
username: payload.access.username
})
} else {
await ProjectApi.updateProjectCollaborator(
payload.projectId,
Number(payload.access.id),
payload.data
)
}
this.access = this.access.map((access) => {
if (access.id === payload.userId) {
if (access.id === payload.access.id) {
access.project_permission = payload.data.role
access.project_role = payload.data.role
}
return access
})
this.project.access = response.data
} catch {
notificationStore.error({
text: `Failed to update project access`
})
} catch (err) {
this.handleProjectAccessError(err, 'Failed to update project access')
} finally {
this.accessLoading = false
}
},

handleProjectAccessError(err: unknown, defaultMessage: string) {
const notificationStore = useNotificationStore()
notificationStore.error({
text: getErrorMessage(err, defaultMessage)
})
},

async updatePublicFlag(payload: {
projectId: string
data: UpdatePublicFlagParams
Expand Down
Loading
Loading