From ff8ca201c16ab4a7ab806cc9ab7748ca47f02d1f Mon Sep 17 00:00:00 2001
From: "L. Ellenbeck" <ellenbeck@itc.rwth-aachen.de>
Date: Tue, 30 May 2023 15:07:39 +0200
Subject: [PATCH] WIP: working project role management (coscine/issues#2436)

---
 src/modules/project/pages/Members.vue         | 95 ++++++++++---------
 .../project/pages/components/MembersList.vue  | 13 +--
 .../pages/components/UserSearchRow.vue        | 29 +++---
 .../components/modals/ImportUserModal.vue     | 18 ++--
 src/modules/project/store.ts                  | 16 +++-
 5 files changed, 90 insertions(+), 81 deletions(-)

diff --git a/src/modules/project/pages/Members.vue b/src/modules/project/pages/Members.vue
index 75b23c4c..9d21feec 100644
--- a/src/modules/project/pages/Members.vue
+++ b/src/modules/project/pages/Members.vue
@@ -129,7 +129,7 @@ import useProjectStore from "../store";
 import useUserStore from "@/modules/user/store";
 import useNotificationStore from "@/store/notification";
 
-import type { ProjectDto, ProjectInvitationDto, ProjectInvitationForProjectManipulationDto, ProjectRoleDto, RoleDto } from "@coscine/api-client/dist/types/Coscine.Api/api";
+import type { ProjectDto, ProjectInvitationDto, ProjectInvitationForProjectManipulationDto, ProjectRoleDto, ProjectRoleForProjectCreationDto, ProjectRoleForProjectManipulationDto, RoleDto } from "@coscine/api-client/dist/types/Coscine.Api/api";
 import type { ExtendedProjectInvitationDto } from "../types";
 
 export default defineComponent({
@@ -361,34 +361,35 @@ export default defineComponent({
     },
 
     async setRole(projectRole: ProjectRoleDto) {
-      if (this.project) {
+      if (this.project && this.project.id && projectRole.id) {
         projectRole.projectId = this.project.id;
-      }
-      if (projectRole.role) {
-        projectRole.role.displayName =
-          projectRole.role.displayName === this.roleStrings.member
-            ? this.roleStrings.owner
-            : this.roleStrings.member;
-      }
+      
+        if (projectRole.role) {
+          projectRole.role.displayName =
+            projectRole.role.displayName === this.roleStrings.member
+              ? this.roleStrings.owner
+              : this.roleStrings.member;
+        }
 
-      const text = this.$t("page.members.changedRole", {
-        project: this.projectName,
-        role:
-          projectRole.role && projectRole.role.id
-            ? this.getRoleNameFromId(projectRole.role.id)
-            : "",
-        user:
-          projectRole.user && projectRole.user.displayName
-            ? projectRole.user.displayName
-            : "",
-      }).toString();
+        const text = this.$t("page.members.changedRole", {
+          project: this.projectName,
+          role:
+            projectRole.role && projectRole.role.id
+              ? this.getRoleNameFromId(projectRole.role.id)
+              : "",
+          user:
+            projectRole.user && projectRole.user.displayName
+              ? projectRole.user.displayName
+              : "",
+        }).toString();
 
-      await this.projectStore.storeProjectRole(projectRole);
-      await this.getProjectRoles();
-      this.notificationStore.postNotification({
-        title: this.$t("page.members.userManagement").toString(),
-        body: text,
-      });
+        await this.projectStore.updateMembershipOfProject(this.project.id, projectRole.id, { roleId: projectRole.role?.id} as ProjectRoleForProjectManipulationDto);
+        await this.getProjectRoles();
+        this.notificationStore.postNotification({
+          title: this.$t("page.members.userManagement").toString(),
+          body: text,
+        });
+    }
     },
 
     getRoleNameFromId(roleId: string): string | null | undefined {
@@ -404,30 +405,30 @@ export default defineComponent({
     },
 
     async addUser(projectRole: ProjectRoleDto, callback?: () => void) {
-      if (this.project) {
+      if (this.project && this.project.id) {
         projectRole.projectId = this.project.id;
-      }
 
-      const text = this.$t("page.members.addedUser", {
-        project: this.projectName,
-        role:
-          projectRole.role && projectRole.role.id
-            ? this.getRoleNameFromId(projectRole.role.id)
-            : "",
-        user:
-          projectRole.user && projectRole.user.displayName
-            ? projectRole.user.displayName
-            : "",
-      }).toString();
+        const text = this.$t("page.members.addedUser", {
+          project: this.projectName,
+          role:
+            projectRole.role && projectRole.role.id
+              ? this.getRoleNameFromId(projectRole.role.id)
+              : "",
+          user:
+            projectRole.user && projectRole.user.displayName
+              ? projectRole.user.displayName
+              : "",
+        }).toString();
 
-      await this.projectStore.storeProjectRole(projectRole);
-      await this.getProjectRoles();
-      this.notificationStore.postNotification({
-        title: this.$t("page.members.userManagement").toString(),
-        body: text,
-      });
-      if (callback) {
-        callback();
+        await this.projectStore.addMembershipToProject(this.project.id, {roleId: projectRole.role?.id, userId: projectRole.user?.userId} as ProjectRoleForProjectCreationDto);
+        await this.getProjectRoles();
+        this.notificationStore.postNotification({
+          title: this.$t("page.members.userManagement").toString(),
+          body: text,
+        });
+        if (callback) {
+          callback();
+        }
       }
     },
 
diff --git a/src/modules/project/pages/components/MembersList.vue b/src/modules/project/pages/components/MembersList.vue
index 2820f553..ab0694d7 100644
--- a/src/modules/project/pages/components/MembersList.vue
+++ b/src/modules/project/pages/components/MembersList.vue
@@ -21,7 +21,7 @@
                 v-if="
                   projectRole.user &&
                   currentUser &&
-                  projectRole.user.id === currentUser.id
+                  projectRole.user.userId === currentUser.id
                 "
                 class="badge badge-pill badge-primary ml-2"
               >
@@ -62,7 +62,7 @@
                 v-if="
                   projectRole.user &&
                   currentUser &&
-                  projectRole.user.id === currentUser.id
+                  projectRole.user.userId === currentUser.id
                 "
                 class="float-right"
                 variant="primary"
@@ -128,14 +128,13 @@
 import { defineComponent } from "vue";
 
 import type {
-  ProjectRoleObject,
   UserObject,
 } from "@coscine/api-client/dist/types/Coscine.Api.Project";
 
 // import the store for current module
 import useProjectStore from "../../store";
 import useUserStore from "@/modules/user/store";
-import type { ProjectDto } from "@coscine/api-client/dist/types/Coscine.Api/api";
+import type { ProjectDto, ProjectRoleDto } from "@coscine/api-client/dist/types/Coscine.Api/api";
 
 export default defineComponent({
   setup() {
@@ -159,7 +158,7 @@ export default defineComponent({
     project(): ProjectDto | null {
       return this.projectStore.currentProject;
     },
-    projectRoles(): ProjectRoleObject[] | null {
+    projectRoles(): ProjectRoleDto[] | null {
       return this.projectStore.currentProjectRolesSorted;
     },
     isOwner(): boolean | undefined {
@@ -180,7 +179,9 @@ export default defineComponent({
 
   methods: {
     leaveProject() {
-      this.projectStore.deleteProjectAssociation(this.project);
+      if(this.project) {
+        this.projectStore.deleteProjectAssociation(this.project, null);
+      }
     },
   },
 });
diff --git a/src/modules/project/pages/components/UserSearchRow.vue b/src/modules/project/pages/components/UserSearchRow.vue
index edcf54e6..ff6e64ca 100644
--- a/src/modules/project/pages/components/UserSearchRow.vue
+++ b/src/modules/project/pages/components/UserSearchRow.vue
@@ -143,19 +143,15 @@ Vue.component("VSelect", vSelect);
 
 import useUserStore from "@/modules/user/store";
 
-import type {
-  ProjectRoleObject,
-  RoleObject,
-} from "@coscine/api-client/dist/types/Coscine.Api.Project";
 import type { UserObject } from "@coscine/api-client/dist/types/Coscine.Api.User";
-import type { ProjectDto } from "@coscine/api-client/dist/types/Coscine.Api/api";
+import type { ProjectDto, ProjectRoleDto, ProjectRoleUserDto, RoleDto } from "@coscine/api-client/dist/types/Coscine.Api/api";
 
 export default defineComponent({
   props: {
     memberRole: {
       default: null,
       type: [Object, null, undefined] as PropType<
-        RoleObject | null | undefined
+        RoleDto | null | undefined
       >,
     },
     project: {
@@ -164,7 +160,7 @@ export default defineComponent({
     },
     roles: {
       default: null,
-      type: [Array, null] as PropType<RoleObject[] | null>,
+      type: [Array, null] as PropType<RoleDto[] | null>,
     },
     isOwner: {
       default: false,
@@ -185,10 +181,10 @@ export default defineComponent({
           displayName: "",
         },
         user: {
-          id: "",
+          userId: "",
           emailAddress: "",
         },
-      } as ProjectRoleObject,
+      } as ProjectRoleDto,
       queryTimer: 0,
       queriedUsers: [] as UserObject[],
       searchString: "",
@@ -218,7 +214,7 @@ export default defineComponent({
         this.newUserRole.role &&
         this.newUserRole.role.id &&
         this.newUserRole.user &&
-        !this.newUserRole.user.id &&
+        !this.newUserRole.user.userId &&
         this.newUserRole.user.emailAddress
       ) {
         return true;
@@ -230,7 +226,7 @@ export default defineComponent({
         this.newUserRole &&
         this.newUserRole.projectId &&
         this.newUserRole.user &&
-        this.newUserRole.user.id &&
+        this.newUserRole.user.userId &&
         this.newUserRole.role &&
         this.newUserRole.role.id
       ) {
@@ -252,7 +248,7 @@ export default defineComponent({
     }
   },
   methods: {
-    addUser(projectRole: ProjectRoleObject) {
+    addUser(projectRole: ProjectRoleDto) {
       this.searchString = "";
       this.$emit("addUser", projectRole, () => {
         this.newUserRole.user = undefined;
@@ -263,14 +259,19 @@ export default defineComponent({
     filterMock(option: unknown, label: string, search: string) {
       return search.length > 0;
     },
-    prepareInvitation(projectRole: ProjectRoleObject) {
+    prepareInvitation(projectRole: ProjectRoleDto) {
       this.$emit("prepareInvitation", projectRole);
     },
     setFilter(filter: string) {
       this.$emit("setFilter", filter);
     },
     setNewUser(value: UserObject) {
-      this.newUserRole.user = value;
+      this.newUserRole.user = { 
+        userId: value.id, 
+        displayName: value.displayName, 
+        emailAddress: value.emailAddress
+      } as  ProjectRoleUserDto;
+      
       if (this.project) {
         this.newUserRole.projectId = this.project.id;
       }
diff --git a/src/modules/project/pages/components/modals/ImportUserModal.vue b/src/modules/project/pages/components/modals/ImportUserModal.vue
index 263d257d..ec2773e4 100644
--- a/src/modules/project/pages/components/modals/ImportUserModal.vue
+++ b/src/modules/project/pages/components/modals/ImportUserModal.vue
@@ -74,11 +74,7 @@ import useProjectStore from "../../../store";
 
 import MembersTable from "../MembersTable.vue";
 
-import type {
-  ProjectRoleObject,
-  RoleObject,
-} from "@coscine/api-client/dist/types/Coscine.Api.Project";
-import type { ProjectDto } from "@coscine/api-client/dist/types/Coscine.Api/api";
+import type { ProjectDto, ProjectRoleDto, RoleDto } from "@coscine/api-client/dist/types/Coscine.Api/api";
 
 export default defineComponent({
   components: {
@@ -92,7 +88,7 @@ export default defineComponent({
     memberRole: {
       default: null,
       type: [Object, null, undefined] as PropType<
-        RoleObject | null | undefined
+        RoleDto | null | undefined
       >,
     },
     project: {
@@ -101,11 +97,11 @@ export default defineComponent({
     },
     projectRoles: {
       default: null,
-      type: [Array, null] as PropType<ProjectRoleObject[] | null>,
+      type: [Array, null] as PropType<ProjectRoleDto[] | null>,
     },
     roles: {
       default: null,
-      type: [Array, null] as PropType<RoleObject[] | null>,
+      type: [Array, null] as PropType<RoleDto[] | null>,
     },
   },
   setup() {
@@ -115,7 +111,7 @@ export default defineComponent({
   },
   data() {
     return {
-      additionalMembers: [] as ProjectRoleObject[],
+      additionalMembers: [] as ProjectRoleDto[],
       isBusy: false,
       selectedProject: null as string | null,
     };
@@ -142,7 +138,7 @@ export default defineComponent({
         (projectRole) =>
           !this.projectRoles?.some(
             (currentProjectRole) =>
-              projectRole.user?.id === currentProjectRole.user?.id
+              projectRole.user?.userId === currentProjectRole.user?.userId
           )
       );
       this.additionalMembers.forEach((additionalMember) => {
@@ -166,7 +162,7 @@ export default defineComponent({
       this.$bvModal.hide("importUserModal");
       this.additionalMembers = [];
     },
-    removeSelectedRow(projectRole: ProjectRoleObject) {
+    removeSelectedRow(projectRole: ProjectRoleDto) {
       const index = this.additionalMembers.indexOf(projectRole);
       this.additionalMembers.splice(index, 1);
     },
diff --git a/src/modules/project/store.ts b/src/modules/project/store.ts
index 1ab002dd..1467c1cc 100644
--- a/src/modules/project/store.ts
+++ b/src/modules/project/store.ts
@@ -24,7 +24,7 @@ import type { Route } from "vue-router";
 import useNotificationStore from "@/store/notification";
 import useUserStore from "../user/store";
 import type { AxiosError } from "axios";
-import type { ProjectDto, ProjectForCreationDto, ProjectForUpdateDto, ProjectInvitationDto, ProjectInvitationForProjectManipulationDto, ProjectQuotaDto, ProjectQuotaForUpdateDto, ProjectRoleDto, ResourceDto, RoleDto } from "@coscine/api-client/dist/types/Coscine.Api/api";
+import type { ProjectDto, ProjectForCreationDto, ProjectForUpdateDto, ProjectInvitationDto, ProjectInvitationForProjectManipulationDto, ProjectQuotaDto, ProjectQuotaForUpdateDto, ProjectRoleDto, ProjectRoleForProjectCreationDto, ProjectRoleForProjectManipulationDto, ResourceDto, RoleDto } from "@coscine/api-client/dist/types/Coscine.Api/api";
 
 /*  
   Store variable name is "this.<id>Store"
@@ -665,12 +665,22 @@ export const useProjectStore = defineStore({
         notificationStore.postApiErrorNotification(error as AxiosError);
         return false;
       }
+    },    
+
+    async addMembershipToProject(projectId: string, projectRoleForProjectCreationDto: ProjectRoleForProjectCreationDto) {
+      const notificationStore = useNotificationStore();
+      try {
+        await ProjectMemberApi.addMembership(projectId, projectRoleForProjectCreationDto)
+      } catch (error) {
+        // Handle other Status Codes
+        notificationStore.postApiErrorNotification(error as AxiosError);
+      }
     },
 
-    async storeProjectRole(projectRole: ProjectRoleDto) {
+    async updateMembershipOfProject(projectId: string, membershipId: string, projectRoleForProjectManipulationDto: ProjectRoleForProjectManipulationDto) {
       const notificationStore = useNotificationStore();
       try {
-        await ProjectRoleApi.projectRoleSet(projectRole);
+        await ProjectMemberApi.updateMembership(projectId, membershipId, projectRoleForProjectManipulationDto)
       } catch (error) {
         // Handle other Status Codes
         notificationStore.postApiErrorNotification(error as AxiosError);
-- 
GitLab