Jelajahi Sumber

Implemented create

Taichi Masuyama 4 tahun lalu
induk
melakukan
e8ea4dcdb6

+ 1 - 4
packages/app/src/components/Admin/UserGroupDetail/UserGroupDetailPage.tsx

@@ -105,10 +105,7 @@ const UserGroupDetailPage: FC = () => {
   }, [searchType, isAlsoMailSearched, isAlsoNameSearched]);
 
   const addUserByUsername = useCallback(async(username: string) => {
-    const res = await apiv3Post(`/user-groups/${userGroup._id}/users/${username}`);
-
-    // do not add users for ducaplicate
-    if (res.data.userGroupRelation == null) { return }
+    await apiv3Post(`/user-groups/${userGroup._id}/users/${username}`);
 
     await sync();
   }, [userGroup, sync]);

+ 12 - 0
packages/app/src/server/models/user-group-relation.js

@@ -240,6 +240,18 @@ class UserGroupRelation {
     });
   }
 
+  static createRelations(userGroupIds, user) {
+    const documentsToInsertMany = userGroupIds.map((groupId) => {
+      return {
+        relatedGroup: groupId,
+        relatedUser: user._id,
+        createdAt: new Date(),
+      };
+    });
+
+    return this.insertMany(documentsToInsertMany);
+  }
+
   /**
    * remove all relation for UserGroup
    *

+ 7 - 7
packages/app/src/server/models/user-group.js

@@ -136,19 +136,19 @@ class UserGroup {
     return this.create({ name, description, parent });
   }
 
-  static async findAllAncestorGroups(parent, ancestors = [parent]) {
-    if (parent == null) {
+  static async findGroupsWithAncestorsRecursively(group, ancestors = [group]) {
+    if (group == null) {
       return ancestors;
     }
 
-    const nextParent = await this.findOne({ _id: parent.parent });
-    if (nextParent == null) {
+    const parent = await this.findOne({ _id: group.parent });
+    if (parent == null) {
       return ancestors;
     }
 
-    ancestors.push(nextParent);
+    ancestors.push(parent);
 
-    return this.findAllAncestorGroups(nextParent, ancestors);
+    return this.findGroupsWithAncestorsRecursively(parent, ancestors);
   }
 
   static async findGroupsWithDescendantsRecursively(groups, descendants = groups) {
@@ -193,7 +193,7 @@ class UserGroup {
     const usersBelongsToTargetButNotParent = targetGroupUsers.filter(user => !parentGroupUsers.includes(user));
     // add the target group's users to all ancestors
     if (forceUpdateParents) {
-      const ancestorGroups = await this.findAllAncestorGroups(parent);
+      const ancestorGroups = await this.findGroupsWithAncestorsRecursively(parent);
       const ancestorGroupIds = ancestorGroups.map(group => group._id);
 
       await UserGroupRelation.createByGroupIdsAndUserIds(ancestorGroupIds, usersBelongsToTargetButNotParent);

+ 12 - 10
packages/app/src/server/routes/apiv3/user-group.js

@@ -1,4 +1,5 @@
 import loggerFactory from '~/utils/logger';
+import { filterIdsByIds } from '~/server/util/compare-objectId';
 
 const logger = loggerFactory('growi:routes:apiv3:user-group'); // eslint-disable-line no-unused-vars
 
@@ -255,7 +256,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      description: A result of `UserGroup.updateName`
    */
-  router.put('/:id', loginRequiredStrictly, adminRequired, csrf, validator.update, apiV3FormValidator, async(req, res) => {
+  router.put('/:id', /*loginRequiredStrictly, adminRequired, csrf,*/ validator.update, apiV3FormValidator, async(req, res) => {
     const { id } = req.params;
     const {
       name, description, parentId, forceUpdateParents = false,
@@ -435,18 +436,19 @@ module.exports = (crowi) => {
         User.findUserByUsername(username),
       ]);
 
+      const userGroups = await UserGroup.findGroupsWithAncestorsRecursively(userGroup);
+      const userGroupIds = userGroups.map(g => g._id);
+
       // check for duplicate users in groups
-      const isRelatedUserForGroup = await UserGroupRelation.isRelatedUserForGroup(userGroup, user);
+      const existingRelations = await UserGroupRelation.find({ relatedGroup: { $in: userGroupIds }, relatedUser: user._id });
+      const existingGroupIds = existingRelations.map(r => r.relatedGroup);
 
-      if (isRelatedUserForGroup) {
-        logger.warn('The user is already joined');
-        return res.apiv3();
-      }
+      const groupIdsOfRelationToCreate = filterIdsByIds(userGroupIds, existingGroupIds);
 
-      const userGroupRelation = await UserGroupRelation.createRelation(userGroup, user);
+      const insertedRelations = await UserGroupRelation.createRelations(groupIdsOfRelationToCreate, user);
       const serializedUser = serializeUserSecurely(user);
 
-      return res.apiv3({ user: serializedUser, userGroup, userGroupRelation });
+      return res.apiv3({ user: serializedUser, createdRelationCount: insertedRelations.length });
     }
     catch (err) {
       const msg = `Error occurred in adding the user "${username}" to group "${id}"`;
@@ -507,10 +509,10 @@ module.exports = (crowi) => {
       const groupsOfRelationsToDelete = await UserGroup.findGroupsWithDescendantsRecursively([userGroup]);
       const relatedGroupIdsToDelete = groupsOfRelationsToDelete.map(g => g._id);
 
-      const res = await UserGroupRelation.deleteMany({ relatedUser: user._id, relatedGroup: { $in: relatedGroupIdsToDelete } });
+      const deleteManyRes = await UserGroupRelation.deleteMany({ relatedUser: user._id, relatedGroup: { $in: relatedGroupIdsToDelete } });
       const serializedUser = serializeUserSecurely(user);
 
-      return res.apiv3({ user: serializedUser, deletedGroupsCount: res.deletedCount });
+      return res.apiv3({ user: serializedUser, deletedGroupsCount: deleteManyRes.deletedCount });
     }
     catch (err) {
       const msg = 'Error occurred while removing the user from groups.';

+ 16 - 0
packages/app/src/server/util/compare-objectId.ts

@@ -0,0 +1,16 @@
+import mongoose from 'mongoose';
+
+type TObjectId = mongoose.Types.ObjectId;
+const ObjectId = mongoose.Types.ObjectId;
+
+export const filterIdsByIds = (_arr1: TObjectId[], _arr2: TObjectId[]): TObjectId[] => {
+  // cast to string
+  const arr1 = _arr1.map(e => e.toString());
+  const arr2 = _arr2.map(e => e.toString());
+
+  // filter
+  const filtered = arr1.filter(e => !arr2.includes(e));
+
+  // cast to ObjectId
+  return filtered.map(e => new ObjectId(e));
+};