user-group.ts 4.0 KB

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