external-account.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. const debug = require('debug')('growi:models:external-account');
  2. const mongoose = require('mongoose');
  3. const mongoosePaginate = require('mongoose-paginate');
  4. const uniqueValidator = require('mongoose-unique-validator');
  5. const ObjectId = mongoose.Schema.Types.ObjectId;
  6. /*
  7. * define schema
  8. */
  9. const schema = new mongoose.Schema({
  10. providerType: { type: String, required: true },
  11. accountId: { type: String, required: true },
  12. user: { type: ObjectId, ref: 'User', required: true },
  13. createdAt: { type: Date, default: Date.now, required: true },
  14. });
  15. // compound index
  16. schema.index({ providerType: 1, accountId: 1}, { unique: true });
  17. // apply plugins
  18. schema.plugin(mongoosePaginate);
  19. schema.plugin(uniqueValidator);
  20. /**
  21. * ExternalAccount Class
  22. *
  23. * @class ExternalAccount
  24. */
  25. class ExternalAccount {
  26. /**
  27. * limit items num for pagination
  28. *
  29. * @readonly
  30. * @static
  31. * @memberof ExternalAccount
  32. */
  33. static get DEFAULT_LIMIT() {
  34. return 50;
  35. }
  36. static set crowi(crowi) {
  37. this._crowi = crowi;
  38. }
  39. static get crowi() {
  40. return this._crowi;
  41. }
  42. /**
  43. * get the populated user entity
  44. *
  45. * @returns Promise<User>
  46. * @memberof ExternalAccount
  47. */
  48. getPopulatedUser() {
  49. return this.populate('user').execPopulate()
  50. .then((account) => {
  51. return account.user;
  52. });
  53. }
  54. /**
  55. * find an account or register if not found
  56. *
  57. * @static
  58. * @param {string} providerType
  59. * @param {string} accountId
  60. * @param {object} usernameToBeRegistered the username of User entity that will be created when accountId is not found
  61. * @param {object} nameToBeRegistered the name of User entity that will be created when accountId is not found
  62. * @param {object} mailToBeRegistered the mail of User entity that will be created when accountId is not found
  63. * @returns {Promise<ExternalAccount>}
  64. * @memberof ExternalAccount
  65. */
  66. static findOrRegister(providerType, accountId, usernameToBeRegistered, nameToBeRegistered, mailToBeRegistered) {
  67. return this.findOne({ providerType, accountId })
  68. .then(account => {
  69. // ExternalAccount is found
  70. if (account != null) {
  71. debug(`ExternalAccount '${accountId}' is found `, account);
  72. return account;
  73. }
  74. const User = ExternalAccount.crowi.model('User');
  75. return User.findOne({username: usernameToBeRegistered})
  76. .then(user => {
  77. // when the User that have the same `username` exists
  78. if (user != null) {
  79. throw new DuplicatedUsernameException(`User '${usernameToBeRegistered}' already exists`, user);
  80. }
  81. if (nameToBeRegistered == null) {
  82. nameToBeRegistered = '';
  83. }
  84. // create a new User with STATUS_ACTIVE
  85. debug(`ExternalAccount '${accountId}' is not found, it is going to be registered.`);
  86. return User.createUser(nameToBeRegistered, usernameToBeRegistered, mailToBeRegistered, undefined, undefined, User.STATUS_ACTIVE);
  87. })
  88. .then(newUser => {
  89. return this.associate(providerType, accountId, newUser);
  90. });
  91. });
  92. }
  93. /**
  94. * Create ExternalAccount document and associate to existing User
  95. *
  96. * @param {string} providerType
  97. * @param {string} accountId
  98. * @param {object} user
  99. */
  100. static associate(providerType, accountId, user) {
  101. return this.create({ providerType, accountId, user: user._id });
  102. }
  103. /**
  104. * find all entities with pagination
  105. *
  106. * @see https://github.com/edwardhotchkiss/mongoose-paginate
  107. *
  108. * @static
  109. * @param {any} opts mongoose-paginate options object
  110. * @returns {Promise<any>} mongoose-paginate result object
  111. * @memberof ExternalAccount
  112. */
  113. static findAllWithPagination(opts) {
  114. const query = {};
  115. const options = Object.assign({ populate: 'user' }, opts);
  116. if (options.sort == null) {
  117. options.sort = {accountId: 1, createdAt: 1};
  118. }
  119. if (options.limit == null) {
  120. options.limit = ExternalAccount.DEFAULT_LIMIT;
  121. }
  122. return this.paginate(query, options)
  123. .catch((err) => {
  124. debug('Error on pagination:', err);
  125. });
  126. }
  127. }
  128. /**
  129. * The Exception class thrown when User.username is duplicated when creating user
  130. *
  131. * @class DuplicatedUsernameException
  132. */
  133. class DuplicatedUsernameException {
  134. constructor(message, user) {
  135. this.name = this.constructor.name;
  136. this.message = message;
  137. this.user = user;
  138. }
  139. }
  140. module.exports = function(crowi) {
  141. ExternalAccount.crowi = crowi;
  142. schema.loadClass(ExternalAccount);
  143. return mongoose.model('ExternalAccount', schema);
  144. };