me.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /**
  2. * @swagger
  3. *
  4. * components:
  5. * schemas:
  6. * UserGroup:
  7. * description: UserGroup
  8. * type: object
  9. * properties:
  10. * __v:
  11. * type: number
  12. * description: record version
  13. * example: 0
  14. * _id:
  15. * type: string
  16. * description: user group ID
  17. * example: 5e2d56c1e35da4004ef7e0b0
  18. * createdAt:
  19. * type: string
  20. * description: date created at
  21. * example: 2010-01-01T00:00:00.000Z
  22. */
  23. /**
  24. * @swagger
  25. *
  26. * components:
  27. * schemas:
  28. * UserGroupRelation:
  29. * description: UserGroupRelation
  30. * type: object
  31. * properties:
  32. * __v:
  33. * type: number
  34. * description: record version
  35. * example: 0
  36. * _id:
  37. * type: string
  38. * description: user group relation ID
  39. * example: 5e2d56cbe35da4004ef7e0b1
  40. * relatedGroup:
  41. * $ref: '#/components/schemas/UserGroup'
  42. * relatedUser:
  43. * $ref: '#/components/schemas/User/properties/_id'
  44. * createdAt:
  45. * type: string
  46. * description: date created at
  47. * example: 2010-01-01T00:00:00.000Z
  48. */
  49. module.exports = function(crowi, app) {
  50. const debug = require('debug')('growi:routes:me');
  51. const logger = require('@alias/logger')('growi:routes:me');
  52. const models = crowi.models;
  53. const UserGroupRelation = models.UserGroupRelation;
  54. const ExternalAccount = models.ExternalAccount;
  55. const ApiResponse = require('../util/apiResponse');
  56. // , pluginService = require('../service/plugin')
  57. const actions = {};
  58. const api = {};
  59. actions.api = api;
  60. /**
  61. * @swagger
  62. *
  63. * /me/user-group-relations:
  64. * get:
  65. * tags: [Me, CrowiCompatibles]
  66. * operationId: getUserGroupRelations
  67. * summary: /me/user-group-relations
  68. * description: Get user group relations
  69. * responses:
  70. * 200:
  71. * description: Succeeded to get user group relations.
  72. * content:
  73. * application/json:
  74. * schema:
  75. * properties:
  76. * ok:
  77. * $ref: '#/components/schemas/V1Response/properties/ok'
  78. * userGroupRelations:
  79. * type: array
  80. * items:
  81. * $ref: '#/components/schemas/UserGroupRelation'
  82. * 403:
  83. * $ref: '#/components/responses/403'
  84. * 500:
  85. * $ref: '#/components/responses/500'
  86. */
  87. /**
  88. * retrieve user-group-relation documents
  89. * @param {object} req
  90. * @param {object} res
  91. */
  92. api.userGroupRelations = function(req, res) {
  93. UserGroupRelation.findAllRelationForUser(req.user)
  94. .then((userGroupRelations) => {
  95. return res.json(ApiResponse.success({ userGroupRelations }));
  96. });
  97. };
  98. actions.index = function(req, res) {
  99. return res.render('me/index');
  100. };
  101. actions.imagetype = function(req, res) {
  102. if (req.method !== 'POST') {
  103. // do nothing
  104. return;
  105. }
  106. if (!req.form.isValid) {
  107. req.flash('errorMessage', req.form.errors.join('\n'));
  108. return;
  109. }
  110. const imagetypeForm = req.body.imagetypeForm;
  111. const userData = req.user;
  112. const isGravatarEnabled = imagetypeForm.isGravatarEnabled;
  113. userData.updateIsGravatarEnabled(isGravatarEnabled, (err, userData) => {
  114. if (err) {
  115. /* eslint-disable no-restricted-syntax, no-prototype-builtins */
  116. for (const e in err.errors) {
  117. if (err.errors.hasOwnProperty(e)) {
  118. req.form.errors.push(err.errors[e].message);
  119. }
  120. }
  121. /* eslint-enable no-restricted-syntax, no-prototype-builtins */
  122. return res.render('me/index', {});
  123. }
  124. req.flash('successMessage', req.t('Updated'));
  125. return res.redirect('/me');
  126. });
  127. };
  128. actions.externalAccounts = {};
  129. actions.externalAccounts.list = function(req, res) {
  130. const userData = req.user;
  131. const renderVars = {};
  132. ExternalAccount.find({ user: userData })
  133. .then((externalAccounts) => {
  134. renderVars.externalAccounts = externalAccounts;
  135. return;
  136. })
  137. .then(() => {
  138. if (req.method === 'POST' && req.form.isValid) {
  139. // TODO impl
  140. return res.render('me/external-accounts', renderVars);
  141. }
  142. // method GET
  143. return res.render('me/external-accounts', renderVars);
  144. });
  145. };
  146. actions.externalAccounts.disassociate = function(req, res) {
  147. const userData = req.user;
  148. const redirectWithFlash = (type, msg) => {
  149. req.flash(type, msg);
  150. return res.redirect('/me/external-accounts');
  151. };
  152. if (req.body == null) {
  153. redirectWithFlash('errorMessage', 'Invalid form.');
  154. }
  155. // make sure password set or this user has two or more ExternalAccounts
  156. new Promise((resolve, reject) => {
  157. if (userData.password != null) {
  158. resolve(true);
  159. }
  160. else {
  161. ExternalAccount.count({ user: userData })
  162. .then((count) => {
  163. resolve(count > 1);
  164. });
  165. }
  166. })
  167. .then((isDisassociatable) => {
  168. if (!isDisassociatable) {
  169. const e = new Error();
  170. e.name = 'couldntDisassociateError';
  171. throw e;
  172. }
  173. const providerType = req.body.providerType;
  174. const accountId = req.body.accountId;
  175. return ExternalAccount.findOneAndRemove({ providerType, accountId, user: userData });
  176. })
  177. .then((account) => {
  178. if (account == null) {
  179. return redirectWithFlash('errorMessage', 'ExternalAccount not found.');
  180. }
  181. return redirectWithFlash('successMessage', 'Successfully disassociated.');
  182. })
  183. .catch((err) => {
  184. if (err) {
  185. if (err.name === 'couldntDisassociateError') {
  186. return redirectWithFlash('couldntDisassociateError', true);
  187. }
  188. return redirectWithFlash('errorMessage', err.message);
  189. }
  190. });
  191. };
  192. actions.externalAccounts.associateLdap = function(req, res) {
  193. const passport = require('passport');
  194. const passportService = crowi.passportService;
  195. const redirectWithFlash = (type, msg) => {
  196. req.flash(type, msg);
  197. return res.redirect('/me/external-accounts');
  198. };
  199. if (!passportService.isLdapStrategySetup) {
  200. debug('LdapStrategy has not been set up');
  201. return redirectWithFlash('warning', 'LdapStrategy has not been set up');
  202. }
  203. passport.authenticate('ldapauth', (err, user, info) => {
  204. if (res.headersSent) { // dirty hack -- 2017.09.25
  205. return; // cz: somehow passport.authenticate called twice when ECONNREFUSED error occurred
  206. }
  207. if (err) { // DB Error
  208. logger.error('LDAP Server Error: ', err);
  209. return redirectWithFlash('warningMessage', 'LDAP Server Error occured.');
  210. }
  211. if (info && info.message) {
  212. return redirectWithFlash('warningMessage', info.message);
  213. }
  214. if (user) {
  215. // create ExternalAccount
  216. const ldapAccountId = passportService.getLdapAccountIdFromReq(req);
  217. const user = req.user;
  218. ExternalAccount.associate('ldap', ldapAccountId, user)
  219. .then(() => {
  220. return redirectWithFlash('successMessage', 'Successfully added.');
  221. })
  222. .catch((err) => {
  223. return redirectWithFlash('errorMessage', err.message);
  224. });
  225. }
  226. })(req, res, () => {});
  227. };
  228. actions.password = function(req, res) {
  229. return res.render('me/password');
  230. };
  231. actions.apiToken = function(req, res) {
  232. const userData = req.user;
  233. if (req.method === 'POST' && req.form.isValid) {
  234. userData.updateApiToken()
  235. .then((userData) => {
  236. req.flash('successMessage', 'API Token updated');
  237. return res.redirect('/me/apiToken');
  238. })
  239. .catch((err) => {
  240. // req.flash('successMessage',);
  241. req.form.errors.push('Failed to update API Token');
  242. return res.render('me/api_token', {
  243. });
  244. });
  245. }
  246. else {
  247. return res.render('me/api_token', {
  248. });
  249. }
  250. };
  251. actions.updates = function(req, res) {
  252. res.render('me/update', {
  253. });
  254. };
  255. return actions;
  256. };