Răsfoiți Sursa

Merge branch 'invitation-user-apiV3' into confirmationPasswordModal

itizawa 6 ani în urmă
părinte
comite
643ed2cd77

+ 1 - 0
package.json

@@ -130,6 +130,7 @@
     "swig-templates": "^2.0.2",
     "swig-templates": "^2.0.2",
     "uglifycss": "^0.0.29",
     "uglifycss": "^0.0.29",
     "url-join": "^4.0.0",
     "url-join": "^4.0.0",
+    "validator": "^11.1.0",
     "xss": "^1.0.6"
     "xss": "^1.0.6"
   },
   },
   "devDependencies": {
   "devDependencies": {

+ 8 - 1
src/client/js/components/Admin/Users/UserInviteModal.jsx

@@ -32,10 +32,17 @@ class UserInviteModal extends React.Component {
   async handleSubmit() {
   async handleSubmit() {
     const { appContainer } = this.props;
     const { appContainer } = this.props;
 
 
+    const array = this.state.emailInputValue.split('\n');
+    const emailList = array.filter((element) => { return element.match(/.+@.+\..+/) });
+    const shapedEmailList = emailList.map((email) => { return email.trim() });
+
     try {
     try {
       // TODO GW-230 use emailList client side
       // TODO GW-230 use emailList client side
       // eslint-disable-next-line no-unused-vars
       // eslint-disable-next-line no-unused-vars
-      const emailList = await appContainer.apiPost('/admin/user/invite', { emailInputValue: this.state.emailInputValue, sendEmail: this.state.sendEmail });
+      const emailList = await appContainer.apiv3.post('/users/invite', {
+        shapedEmailList,
+        sendEmail: this.state.sendEmail,
+      });
       this.props.onToggleModal();
       this.props.onToggleModal();
       this.props.showConfirmationPasswordModal(emailList);
       this.props.showConfirmationPasswordModal(emailList);
       toastSuccess('Inviting user success');
       toastSuccess('Inviting user success');

+ 0 - 8
src/server/form/admin/userInvite.js

@@ -1,8 +0,0 @@
-const form = require('express-form');
-
-const field = form.field;
-
-module.exports = form(
-  field('inviteForm[emailList]', '招待メールアドレス').trim().required(),
-  field('inviteForm[sendEmail]').trim(),
-);

+ 0 - 1
src/server/form/index.js

@@ -36,7 +36,6 @@ module.exports = {
     customlayout: require('./admin/customlayout'),
     customlayout: require('./admin/customlayout'),
     customfeatures: require('./admin/customfeatures'),
     customfeatures: require('./admin/customfeatures'),
     customhighlightJsStyle: require('./admin/customhighlightJsStyle'),
     customhighlightJsStyle: require('./admin/customhighlightJsStyle'),
-    userInvite: require('./admin/userInvite'),
     slackIwhSetting: require('./admin/slackIwhSetting'),
     slackIwhSetting: require('./admin/slackIwhSetting'),
     slackSetting: require('./admin/slackSetting'),
     slackSetting: require('./admin/slackSetting'),
     userGroupCreate: require('./admin/userGroupCreate'),
     userGroupCreate: require('./admin/userGroupCreate'),

+ 2 - 0
src/server/routes/apiv3/index.js

@@ -13,6 +13,8 @@ module.exports = (crowi) => {
 
 
   router.use('/healthcheck', require('./healthcheck')(crowi));
   router.use('/healthcheck', require('./healthcheck')(crowi));
 
 
+  router.use('/users', require('./users')(crowi));
+
   router.use('/user-groups', require('./user-group')(crowi));
   router.use('/user-groups', require('./user-group')(crowi));
 
 
   router.use('/user-group-relations', require('./user-group-relation')(crowi));
   router.use('/user-group-relations', require('./user-group-relation')(crowi));

+ 92 - 0
src/server/routes/apiv3/users.js

@@ -0,0 +1,92 @@
+const loggerFactory = require('@alias/logger');
+
+const logger = loggerFactory('growi:routes:apiv3:user-group'); // eslint-disable-line no-unused-vars
+
+const express = require('express');
+
+const router = express.Router();
+
+const { body } = require('express-validator/check');
+
+const { isEmail } = require('validator');
+
+const validator = {};
+
+module.exports = (crowi) => {
+  const {
+    ErrorV3,
+    User,
+  } = crowi.models;
+
+  const { ApiV3FormValidator } = crowi.middlewares;
+
+  const {
+    loginRequired,
+    adminRequired,
+    csrfVerify: csrf,
+  } = require('../../util/middlewares')(crowi);
+
+  validator.inviteEmail = [
+    // isEmail prevents line breaks, so use isString
+    body('shapedEmailList').custom((value) => {
+      const array = value.filter((value) => { return isEmail(value) });
+      if (array.length === 0) {
+        throw new Error('At least one valid email address is required');
+      }
+      return array;
+    }),
+  ];
+
+  /**
+   * @swagger
+   *
+   *  paths:
+   *    /_api/v3/users/invite:
+   *      post:
+   *        tags: [Users]
+   *        description: Create new users and send Emails
+   *        produces:
+   *          - application/json
+   *        parameters:
+   *          - name: shapedEmailList
+   *            in: query
+   *            description: Invitation emailList
+   *            schema:
+   *              type: array
+   *          - name: sendEmail
+   *            in: query
+   *            description: Whether to send mail
+   *            schema:
+   *              type: boolean
+   *        responses:
+   *          200:
+   *            description: Inviting user success
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    createdUserList:
+   *                      type: array
+   *                      email:
+   *                        type: string
+   *                      password:
+   *                        type: string
+   *                      description: Users successfully created
+   *                    existingEmailList:
+   *                      type: array
+   *                      email:
+   *                        type: string
+   *                      description: Users email that already exists
+   */
+  router.post('/invite', loginRequired(), adminRequired, csrf, validator.inviteEmail, ApiV3FormValidator, async(req, res) => {
+    try {
+      const emailList = await User.createUsersByInvitation(req.body.shapedEmailList, req.body.sendEmail);
+      return res.apiv3({ emailList });
+    }
+    catch (err) {
+      return res.apiv3Err(new ErrorV3(err));
+    }
+  });
+
+  return router;
+};

+ 0 - 1
src/server/routes/index.js

@@ -118,7 +118,6 @@ module.exports = function(crowi, app) {
   app.post('/admin/global-notification/:id/remove', loginRequired() , adminRequired , admin.globalNotification.remove);
   app.post('/admin/global-notification/:id/remove', loginRequired() , adminRequired , admin.globalNotification.remove);
 
 
   app.get('/admin/users'                , loginRequired() , adminRequired , admin.user.index);
   app.get('/admin/users'                , loginRequired() , adminRequired , admin.user.index);
-  app.post('/_api/admin/user/invite'         , form.admin.userInvite ,  loginRequired() , adminRequired , csrf, admin.user.api.validators.inviteEmail, admin.user.invite);
   app.post('/admin/user/:id/makeAdmin'  , loginRequired() , adminRequired , csrf, admin.user.makeAdmin);
   app.post('/admin/user/:id/makeAdmin'  , loginRequired() , adminRequired , csrf, admin.user.makeAdmin);
   app.post('/admin/user/:id/removeFromAdmin', loginRequired() , adminRequired , admin.user.removeFromAdmin);
   app.post('/admin/user/:id/removeFromAdmin', loginRequired() , adminRequired , admin.user.removeFromAdmin);
   app.post('/admin/user/:id/activate'   , loginRequired() , adminRequired , csrf, admin.user.activate);
   app.post('/admin/user/:id/activate'   , loginRequired() , adminRequired , csrf, admin.user.activate);

+ 1 - 1
yarn.lock

@@ -12266,7 +12266,7 @@ validator@^10.0.0:
   resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228"
   resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228"
   integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==
   integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==
 
 
-validator@^11.0.0:
+validator@^11.0.0, validator@^11.1.0:
   version "11.1.0"
   version "11.1.0"
   resolved "https://registry.yarnpkg.com/validator/-/validator-11.1.0.tgz#ac18cac42e0aa5902b603d7a5d9b7827e2346ac4"
   resolved "https://registry.yarnpkg.com/validator/-/validator-11.1.0.tgz#ac18cac42e0aa5902b603d7a5d9b7827e2346ac4"
   integrity sha512-qiQ5ktdO7CD6C/5/mYV4jku/7qnqzjrxb3C/Q5wR3vGGinHTgJZN/TdFT3ZX4vXhX2R1PXx42fB1cn5W+uJ4lg==
   integrity sha512-qiQ5ktdO7CD6C/5/mYV4jku/7qnqzjrxb3C/Q5wR3vGGinHTgJZN/TdFT3ZX4vXhX2R1PXx42fB1cn5W+uJ4lg==