Răsfoiți Sursa

refactor the route for uploading profile image

Yuki Takei 7 ani în urmă
părinte
comite
0b9a4b0357

+ 66 - 17
src/server/routes/attachment.js

@@ -57,6 +57,29 @@ module.exports = function(crowi, app) {
     }
   }
 
+  async function createAttachment(file, user, pageId = null) {
+    // check capacity
+    const isUploadable = await fileUploader.checkCapacity(file.size);
+    if (!isUploadable) {
+      throw new Error('File storage reaches limit');
+    }
+
+    const fileStream = fs.createReadStream(file.path, {flags: 'r', encoding: null, fd: null, mode: '0666', autoClose: true });
+
+    // create an Attachment document and upload file
+    let attachment;
+    try {
+      attachment = await Attachment.create(pageId, user, fileStream, file.originalname, file.mimetype, file.size);
+    }
+    catch (err) {
+      // delete temporary file
+      fs.unlink(file.path, function(err) { if (err) { logger.error('Error while deleting tmp file.') } });
+      throw err;
+    }
+
+    return attachment;
+  }
+
 
   const actions = {};
   const api = {};
@@ -166,7 +189,7 @@ module.exports = function(crowi, app) {
    * @apiParam {File} file
    */
   api.add = async function(req, res) {
-    const pageId = req.body.page_id || null;
+    let pageId = req.body.page_id || null;
     const pagePath = decodeURIComponent(req.body.path) || null;
     let pageCreated = false;
 
@@ -180,37 +203,26 @@ module.exports = function(crowi, app) {
 
     const file = req.file;
 
-    // check capacity
-    const isUploadable = await fileUploader.checkCapacity(file.size);
-    if (!isUploadable) {
-      return res.json(ApiResponse.error('MongoDB for uploading files reaches limit'));
-    }
-
     // TODO for GC-1359: consider restriction
     let page;
     if (pageId == null) {
-      debug('Create page before file upload');
+      logger.debug('Create page before file upload');
+
       page = await Page.create(path, '# '  + path, req.user, {grant: Page.GRANT_OWNER});
       pageCreated = true;
+      pageId = page._id;
     }
     else {
       page = await Page.findById(pageId);
     }
 
-    const fileStream = fs.createReadStream(file.path, {flags: 'r', encoding: null, fd: null, mode: '0666', autoClose: true });
-
-    // create an Attachment document and upload file
     let attachment;
     try {
-      attachment = await Attachment.create(pageId, req.user, fileStream, file.originalname, file.mimetype, file.size);
+      attachment = await createAttachment(file, req.user, pageId);
     }
     catch (err) {
       logger.error(err);
-
-      // delete anyway
-      fs.unlink(file.path, function(err) { if (err) { logger.error('Error while deleting tmp file.') } });
-
-      return res.json(ApiResponse.error('Error while uploading'));
+      return res.json(ApiResponse.error(err.message));
     }
 
     const result = {
@@ -222,6 +234,43 @@ module.exports = function(crowi, app) {
     return res.json(ApiResponse.success(result));
   };
 
+  /**
+   * @api {post} /attachments.uploadProfileImage Add attachment for profile image
+   * @apiName UploadProfileImage
+   * @apiGroup Attachment
+   *
+   * @apiParam {File} file
+   */
+  api.uploadProfileImage = async function(req, res) {
+    // check params
+    if (!req.file) {
+      return res.json(ApiResponse.error('File error.'));
+    }
+
+    const file = req.file;
+
+    // check type
+    const acceptableFileType = /image\/.+/;
+    if (!file.mimetype.match(acceptableFileType)) {
+      return res.json(ApiResponse.error('File type error. Only image files is allowed to set as user picture.'));
+    }
+
+    let attachment;
+    try {
+      attachment = await createAttachment(file, req.user);
+    }
+    catch (err) {
+      logger.error(err);
+      return res.json(ApiResponse.error(err.message));
+    }
+
+    const result = {
+      attachment: attachment.toObject({ virtuals: true }),
+    };
+
+    return res.json(ApiResponse.success(result));
+  };
+
   /**
    * @api {post} /attachments.remove Remove attachments
    * @apiName RemoveAttachments

+ 3 - 3
src/server/routes/index.js

@@ -184,7 +184,6 @@ module.exports = function(crowi, app) {
   app.get( '/_api/search'             , accessTokenParser , loginRequired(crowi, app, false) , search.api.search);
 
   app.get( '/_api/check_username'           , user.api.checkUsername);
-  app.post('/_api/me/picture/upload'        , loginRequired(crowi, app) , uploads.single('userPicture'), me.api.uploadPicture);
   app.get( '/_api/me/user-group-relations'  , accessTokenParser , loginRequired(crowi, app) , me.api.userGroupRelations);
   app.get( '/_api/user/bookmarks'           , loginRequired(crowi, app, false) , user.api.bookmarks);
 
@@ -212,9 +211,10 @@ module.exports = function(crowi, app) {
   app.post('/_api/likes.add'          , accessTokenParser , loginRequired(crowi, app) , csrf, page.api.like);
   app.post('/_api/likes.remove'       , accessTokenParser , loginRequired(crowi, app) , csrf, page.api.unlike);
   app.get( '/_api/attachments.list'   , accessTokenParser , loginRequired(crowi, app, false) , attachment.api.list);
-  app.post('/_api/attachments.add'    , uploads.single('file'), accessTokenParser, loginRequired(crowi, app) ,csrf, attachment.api.add);
+  app.post('/_api/attachments.add'                  , uploads.single('file'), accessTokenParser, loginRequired(crowi, app) ,csrf, attachment.api.add);
+  app.post('/_api/attachments.uploadProfileImage'   , uploads.single('file'), accessTokenParser, loginRequired(crowi, app) ,csrf, attachment.api.uploadProfileImage);
   app.post('/_api/attachments.remove' , accessTokenParser , loginRequired(crowi, app) , csrf, attachment.api.remove);
-  app.get( '/_api/attachments.limit' , accessTokenParser , loginRequired(crowi, app) , csrf, attachment.api.limit);
+  app.get( '/_api/attachments.limit'  , accessTokenParser , loginRequired(crowi, app) , csrf, attachment.api.limit);
 
   app.get( '/_api/revisions.get'      , accessTokenParser , loginRequired(crowi, app, false) , revision.api.get);
   app.get( '/_api/revisions.ids'      , accessTokenParser , loginRequired(crowi, app, false) , revision.api.ids);

+ 0 - 60
src/server/routes/me.js

@@ -16,66 +16,6 @@ module.exports = function(crowi, app) {
 
   actions.api = api;
 
-  api.uploadPicture = function(req, res) {
-    var fileUploader = require('../service/file-uploader')(crowi, app);
-    //var storagePlugin = new pluginService('storage');
-    //var storage = require('../service/storage').StorageService(config);
-
-    var tmpFile = req.file || null;
-    if (!tmpFile) {
-      return res.json({
-        'status': false,
-        'message': 'File type error.'
-      });
-    }
-
-    var tmpPath = tmpFile.path;
-    var filePath = User.createUserPictureFilePath(req.user, tmpFile.filename + tmpFile.originalname);
-    var acceptableFileType = /image\/.+/;
-
-    if (!tmpFile.mimetype.match(acceptableFileType)) {
-      return res.json({
-        'status': false,
-        'message': 'File type error. Only image files is allowed to set as user picture.',
-      });
-    }
-
-    //debug('tmpFile Is', tmpFile, tmpFile.constructor, tmpFile.prototype);
-    //var imageUrl = storage.writeSync(storage.tofs(tmpFile), filePath, {mime: tmpFile.mimetype});
-    //return return res.json({
-    //  'status': true,
-    //  'url': imageUrl,
-    //  'message': '',
-    //});
-    var tmpFileStream = fs.createReadStream(tmpPath, {flags: 'r', encoding: null, fd: null, mode: '0666', autoClose: true });
-
-    fileUploader.uploadFile(filePath, tmpFile.mimetype, tmpFileStream, {})
-    .then(function(data) {
-      var imageUrl = fileUploader.generateUrl(filePath);
-      req.user.updateImage(imageUrl, function(err, data) {
-        fs.unlink(tmpPath, function(err) {
-          // エラー自体は無視
-          if (err) {
-            debug('Error while deleting tmp file.', err);
-          }
-
-          return res.json({
-            'status': true,
-            'url': imageUrl,
-            'message': '',
-          });
-        });
-      });
-    }).catch(function(err) {
-      debug('Uploading error', err);
-
-      return res.json({
-        'status': false,
-        'message': 'Error while uploading to ',
-      });
-    });
-  };
-
   /**
    * retrieve user-group-relation documents
    * @param {object} req

+ 30 - 22
src/server/views/me/index.html

@@ -172,8 +172,9 @@
           </label>
           <div class="col-sm-8">
             {% if isUploadable() %}
-            <form action="/_api/me/picture/upload" id="pictureUploadForm" method="post" class="form-horizontal" role="form" enctype="multipart/form-data">
-              <input name="userPicture" type="file" accept="image/*">
+            <form action="/_api/attachments.uploadProfileImage" id="pictureUploadForm" method="post" class="form-horizontal" role="form">
+              <input type="hidden" name="_csrf" value="{{ csrf() }}">
+              <input type="file" name="profileImage" accept="image/*">
               <div id="pictureUploadFormProgress" class="d-flex align-items-center">
               </div>
             </form>
@@ -196,39 +197,46 @@
   </div><!-- /.form-box -->
 
   <script>
-  $(function()
-  {
-    $("#pictureUploadForm input[name=userPicture]").on('change', function(){
-      var $form = $('#pictureUploadForm');
-      var fd = new FormData($form[0]);
+    $("#pictureUploadForm input[name=profileImage]").on('change', function(){
       if ($(this).val() == '') {
         return false;
       }
 
+      var $form = $('#pictureUploadForm');
+      var formData = new FormData();
+      formData.append('file', this.files[0]);
+      formData.append('_csrf', document.getElementsByName("_csrf")[0].value);
+
       $('#pictureUploadFormProgress').html('<div class="speeding-wheel-sm m-r-5"></div> アップロード中...');
       $.ajax($form.attr("action"), {
         type: 'post',
         processData: false,
         contentType: false,
-        data: fd,
-        dataType: 'json',
-        success: function(data){
-          if (data.status) {
-            $('#settingUserPicture').attr('src', data.url + '?time=' + (new Date()));
-            $('#pictureUploadFormMessage')
-              .addClass('alert alert-success')
-              .html('変更しました');
-          } else {
-            $('#pictureUploadFormMessage')
-              .addClass('alert alert-danger')
-              .html('変更中にエラーが発生しました。');
-          }
-          $('#pictureUploadFormProgress').html('');
+        data: formData
+      })
+      .then(function(data) {
+        if (data.ok) {
+          var attachment = data.attachment;
+          $('#settingUserPicture').attr('src', attachment.filePathProxied + '?time=' + (new Date()));
+          $('#pictureUploadFormMessage')
+            .addClass('alert alert-success')
+            .html('変更しました');
+        }
+        else {
+          throw new Error('statis is invalid');
         }
+      })
+      .catch(function(err) {
+        $('#pictureUploadFormMessage')
+          .addClass('alert alert-danger')
+          .html('変更中にエラーが発生しました。');
+      })
+      // finally
+      .then(function() {
+        $('#pictureUploadFormProgress').html('');
       });
       return false;
     });
-  });
   </script>
 
   {% if googleLoginEnabled() %}