| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 |
- import { SupportedAction } from '~/interfaces/activity';
- import { AttachmentType } from '~/server/interfaces/attachment';
- import loggerFactory from '~/utils/logger';
- import { Attachment } from '../../models/attachment';
- import { validateImageContentType } from './image-content-type-validator';
- /* eslint-disable no-use-before-define */
- const logger = loggerFactory('growi:routes:attachment');
- const ApiResponse = require('../../util/apiResponse');
- /**
- * @swagger
- * tags:
- * name: Attachments
- */
- /**
- * @swagger
- *
- * components:
- * schemas:
- * Attachment:
- * description: Attachment
- * type: object
- * properties:
- * _id:
- * type: string
- * description: attachment ID
- * example: 5e0734e072560e001761fa67
- * __v:
- * type: number
- * description: attachment version
- * example: 0
- * fileFormat:
- * type: string
- * description: file format in MIME
- * example: text/plain
- * fileName:
- * type: string
- * description: file name
- * example: 601b7c59d43a042c0117e08dd37aad0aimage.txt
- * originalName:
- * type: string
- * description: original file name
- * example: file.txt
- * creator:
- * $ref: '#/components/schemas/User'
- * page:
- * type: string
- * description: page ID attached at
- * example: 5e07345972560e001761fa63
- * createdAt:
- * type: string
- * description: date created at
- * example: 2010-01-01T00:00:00.000Z
- * fileSize:
- * type: number
- * description: file size
- * example: 3494332
- * url:
- * type: string
- * description: attachment URL
- * example: http://localhost/files/5e0734e072560e001761fa67
- * filePathProxied:
- * type: string
- * description: file path proxied
- * example: "/attachment/5e0734e072560e001761fa67"
- * downloadPathProxied:
- * type: string
- * description: download path proxied
- * example: "/download/5e0734e072560e001761fa67"
- */
- /**
- * @swagger
- *
- * components:
- * schemas:
- * AttachmentProfile:
- * description: Attachment
- * type: object
- * properties:
- * id:
- * type: string
- * description: attachment ID
- * example: 5e0734e072560e001761fa67
- * _id:
- * type: string
- * description: attachment ID
- * example: 5e0734e072560e001761fa67
- * __v:
- * type: number
- * description: attachment version
- * example: 0
- * fileFormat:
- * type: string
- * description: file format in MIME
- * example: image/png
- * fileName:
- * type: string
- * description: file name
- * example: 601b7c59d43a042c0117e08dd37aad0a.png
- * originalName:
- * type: string
- * description: original file name
- * example: profile.png
- * creator:
- * $ref: '#/components/schemas/ObjectId'
- * page:
- * type: string
- * description: page ID attached at
- * example: null
- * createdAt:
- * type: string
- * description: date created at
- * example: 2010-01-01T00:00:00.000Z
- * fileSize:
- * type: number
- * description: file size
- * example: 3494332
- * filePathProxied:
- * type: string
- * description: file path proxied
- * example: "/attachment/5e0734e072560e001761fa67"
- * downloadPathProxied:
- * type: string
- * description: download path proxied
- * example: "/download/5e0734e072560e001761fa67"
- */
- /** @param {import('~/server/crowi').default} crowi Crowi instance */
- export const routesFactory = (crowi) => {
- const Page = crowi.model('Page');
- const User = crowi.model('User');
- const GlobalNotificationSetting = crowi.model('GlobalNotificationSetting');
- const { attachmentService, globalNotificationService } = crowi;
- const activityEvent = crowi.event('activity');
- /**
- * Check the user is accessible to the related page
- *
- * @param {User} user
- * @param {Attachment} attachment
- */
- async function isDeletableByUser(user, attachment) {
- // deletable if creator is null
- if (attachment.creator == null) {
- return true;
- }
- const ownerId = attachment.creator._id || attachment.creator;
- if (attachment.page == null) { // when profile image
- return user.id === ownerId.toString();
- }
- // eslint-disable-next-line no-return-await
- return await Page.isAccessiblePageByViewer(attachment.page, user);
- }
- const actions = {};
- const api = {};
- actions.api = api;
- // api.download = async function(req, res) {
- // const id = req.params.id;
- // const attachment = await Attachment.findById(id);
- // return responseForAttachment(req, res, attachment, true);
- // };
- /**
- * @swagger
- *
- * /attachments.uploadProfileImage:
- * post:
- * tags: [Attachments]
- * operationId: uploadProfileImage
- * summary: /attachments.uploadProfileImage
- * description: Upload profile image
- * requestBody:
- * content:
- * "multipart/form-data":
- * schema:
- * properties:
- * file:
- * type: string
- * format: binary
- * description: attachment data
- * user:
- * type: string
- * description: user to set profile image
- * encoding:
- * path:
- * contentType: application/x-www-form-urlencoded
- * "*\/*":
- * schema:
- * properties:
- * file:
- * type: string
- * format: binary
- * description: attachment data
- * user:
- * type: string
- * description: user to set profile
- * encoding:
- * path:
- * contentType: application/x-www-form-urlencoded
- * responses:
- * 200:
- * description: Succeeded to add attachment.
- * content:
- * application/json:
- * schema:
- * properties:
- * ok:
- * $ref: '#/components/schemas/V1ResponseOK'
- * attachment:
- * $ref: '#/components/schemas/AttachmentProfile'
- * 403:
- * $ref: '#/components/responses/403'
- * 500:
- * $ref: '#/components/responses/500'
- */
- /**
- * @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 == null) {
- return res.json(ApiResponse.error('File error.'));
- }
- if (!req.user) {
- return res.json(ApiResponse.error('param "user" must be set.'));
- }
- const file = req.file;
- // Validate file type
- const { isValid, error } = validateImageContentType(file.mimetype);
- if (!isValid) {
- return res.json(ApiResponse.error(error));
- }
- let attachment;
- try {
- const user = await User.findById(req.user._id);
- await user.deleteImage();
- attachment = await attachmentService.createAttachment(file, req.user, null, AttachmentType.PROFILE_IMAGE);
- await user.updateImage(attachment);
- }
- 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));
- };
- /**
- * @swagger
- *
- * /attachments.remove:
- * post:
- * tags: [Attachments]
- * operationId: removeAttachment
- * summary: /attachments.remove
- * description: Remove attachment
- * requestBody:
- * content:
- * application/json:
- * schema:
- * properties:
- * attachment_id:
- * $ref: '#/components/schemas/ObjectId'
- * required:
- * - attachment_id
- * responses:
- * 200:
- * description: Succeeded to remove attachment.
- * content:
- * application/json:
- * schema:
- * properties:
- * ok:
- * $ref: '#/components/schemas/V1ResponseOK'
- * 403:
- * $ref: '#/components/responses/403'
- * 500:
- * $ref: '#/components/responses/500'
- */
- /**
- * @api {post} /attachments.remove Remove attachments
- * @apiName RemoveAttachments
- * @apiGroup Attachment
- *
- * @apiParam {String} attachment_id
- */
- api.remove = async function(req, res) {
- const id = req.body.attachment_id;
- const attachment = await Attachment.findById(id);
- if (attachment == null) {
- return res.json(ApiResponse.error('attachment not found'));
- }
- const isDeletable = await isDeletableByUser(req.user, attachment);
- if (!isDeletable) {
- return res.json(ApiResponse.error(`Forbidden to remove the attachment '${attachment.id}'`));
- }
- try {
- await attachmentService.removeAttachment(attachment);
- }
- catch (err) {
- logger.error(err);
- return res.status(500).json(ApiResponse.error('Error while deleting file'));
- }
- activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ATTACHMENT_REMOVE });
- return res.json(ApiResponse.success({}));
- };
- /**
- * @swagger
- *
- * /attachments.removeProfileImage:
- * post:
- * tags: [Attachments]
- * operationId: removeProfileImage
- * summary: /attachments.removeProfileImage
- * description: Remove profile image
- * requestBody:
- * content:
- * application/json:
- * schema:
- * properties:
- * user:
- * type: string
- * description: user to remove profile image
- * responses:
- * 200:
- * description: Succeeded to add attachment.
- * content:
- * application/json:
- * schema:
- * properties:
- * ok:
- * $ref: '#/components/schemas/V1ResponseOK'
- * 403:
- * $ref: '#/components/responses/403'
- * 500:
- * $ref: '#/components/responses/500'
- */
- /**
- * @api {post} /attachments.removeProfileImage Remove profile image attachments
- * @apiGroup Attachment
- * @apiParam {String} attachment_id
- */
- api.removeProfileImage = async function(req, res) {
- const user = req.user;
- const attachment = await Attachment.findById(user.imageAttachment);
- if (attachment == null) {
- return res.json(ApiResponse.error('attachment not found'));
- }
- const isDeletable = await isDeletableByUser(user, attachment);
- if (!isDeletable) {
- return res.json(ApiResponse.error(`Forbidden to remove the attachment '${attachment.id}'`));
- }
- try {
- await user.deleteImage();
- }
- catch (err) {
- logger.error(err);
- return res.status(500).json(ApiResponse.error('Error while deleting image'));
- }
- return res.json(ApiResponse.success({}));
- };
- return actions;
- };
|