user-group.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import type { IUserGroup } from '@growi/core';
  2. import type { Document, Model } from 'mongoose';
  3. import { Schema } from 'mongoose';
  4. import mongoosePaginate from 'mongoose-paginate-v2';
  5. import { getOrCreateModel } from '../util/mongoose-utils';
  6. export interface UserGroupDocument extends IUserGroup, Document {}
  7. export interface UserGroupModel extends Model<UserGroupDocument> {
  8. [x: string]: any; // for old methods
  9. PAGE_ITEMS: 10;
  10. findGroupsWithDescendantsRecursively: (
  11. groups: UserGroupDocument[],
  12. descendants?: UserGroupDocument[],
  13. ) => Promise<UserGroupDocument[]>;
  14. }
  15. /*
  16. * define schema
  17. */
  18. const schema = new Schema<UserGroupDocument, UserGroupModel>(
  19. {
  20. name: { type: String, required: true, unique: true },
  21. parent: { type: Schema.Types.ObjectId, ref: 'UserGroup', index: true },
  22. description: { type: String, default: '' },
  23. },
  24. {
  25. timestamps: true,
  26. },
  27. );
  28. schema.plugin(mongoosePaginate);
  29. const PAGE_ITEMS = 10;
  30. schema.statics.findWithPagination = function (opts) {
  31. const query = { parent: null };
  32. const options = Object.assign({}, opts);
  33. if (options.page == null) {
  34. options.page = 1;
  35. }
  36. if (options.limit == null) {
  37. options.limit = PAGE_ITEMS;
  38. }
  39. return this.paginate(query, options).catch((err) => {
  40. // debug('Error on pagination:', err); TODO: add logger
  41. });
  42. };
  43. schema.statics.findChildrenByParentIds = async function (
  44. parentIds: string[],
  45. includeGrandChildren = false,
  46. ) {
  47. const childUserGroups = await this.find({ parent: { $in: parentIds } });
  48. let grandChildUserGroups: UserGroupDocument[] | null = null;
  49. if (includeGrandChildren) {
  50. const childUserGroupIds = childUserGroups.map((group) => group._id);
  51. grandChildUserGroups = await this.find({
  52. parent: { $in: childUserGroupIds },
  53. });
  54. }
  55. return {
  56. childUserGroups,
  57. grandChildUserGroups,
  58. };
  59. };
  60. schema.statics.countUserGroups = function () {
  61. return this.estimatedDocumentCount();
  62. };
  63. schema.statics.createGroup = async function (name, description, parentId) {
  64. let parent: UserGroupDocument | null = null;
  65. if (parentId != null) {
  66. parent = await this.findOne({ _id: parentId });
  67. if (parent == null) {
  68. throw Error('Parent does not exist.');
  69. }
  70. }
  71. return this.create({ name, description, parent });
  72. };
  73. /**
  74. * Find all ancestor groups starting from the UserGroup of the initial "group".
  75. * Set "ancestors" as "[]" if the initial group is unnecessary as result.
  76. * @param groups UserGroupDocument
  77. * @param ancestors UserGroupDocument[]
  78. * @returns UserGroupDocument[]
  79. */
  80. schema.statics.findGroupsWithAncestorsRecursively = async function (
  81. group,
  82. ancestors = [group],
  83. ) {
  84. if (group == null) {
  85. return ancestors;
  86. }
  87. const parent = await this.findOne({ _id: group.parent });
  88. if (parent == null) {
  89. return ancestors;
  90. }
  91. ancestors.unshift(parent);
  92. return this.findGroupsWithAncestorsRecursively(parent, ancestors);
  93. };
  94. /**
  95. * TODO: use $graphLookup
  96. * Find all descendant groups starting from the UserGroups in the initial groups in "groups".
  97. * Set "descendants" as "[]" if the initial groups are unnecessary as result.
  98. * @param groups UserGroupDocument[] including at least one UserGroup
  99. * @param descendants UserGroupDocument[]
  100. * @returns UserGroupDocument[]
  101. */
  102. schema.statics.findGroupsWithDescendantsRecursively = async function (
  103. groups: UserGroupDocument[],
  104. descendants: UserGroupDocument[] = groups,
  105. ): Promise<UserGroupDocument[]> {
  106. const nextGroups = await this.find({
  107. parent: { $in: groups.map((g) => g._id) },
  108. });
  109. if (nextGroups.length === 0) {
  110. return descendants;
  111. }
  112. return this.findGroupsWithDescendantsRecursively(
  113. nextGroups,
  114. descendants.concat(nextGroups),
  115. );
  116. };
  117. schema.statics.findGroupsWithDescendantsById = async function (groupId) {
  118. const root = await this.findOne({ _id: groupId });
  119. if (root == null) {
  120. throw Error('The root user group does not exist');
  121. }
  122. return this.findGroupsWithDescendantsRecursively([root]);
  123. };
  124. export default getOrCreateModel<UserGroupDocument, UserGroupModel>(
  125. 'UserGroup',
  126. schema,
  127. );