From 1d63fc469ad0ea0f664f12f16faa27f90e1b4172 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 20 Sep 2022 13:56:53 -0400 Subject: [PATCH] chore: remove deprecated old routes for user data exports [breaking] --- public/openapi/read.yaml | 8 --- .../read/user/userslug/export/posts.yaml | 20 ------- .../read/user/userslug/export/profile.yaml | 20 ------- .../read/user/userslug/export/uploads.yaml | 20 ------- src/api/users.js | 5 +- src/controllers/user.js | 37 ------------- src/routes/api.js | 11 ---- test/controllers.js | 55 ++++++++++++------- 8 files changed, 37 insertions(+), 139 deletions(-) delete mode 100644 public/openapi/read/user/userslug/export/posts.yaml delete mode 100644 public/openapi/read/user/userslug/export/profile.yaml delete mode 100644 public/openapi/read/user/userslug/export/uploads.yaml diff --git a/public/openapi/read.yaml b/public/openapi/read.yaml index 31b446d351..91bbfe7176 100644 --- a/public/openapi/read.yaml +++ b/public/openapi/read.yaml @@ -180,14 +180,6 @@ paths: $ref: 'read/user/username/username.yaml' "/api/user/email/{email}": $ref: 'read/user/email/email.yaml' - "/api/user/{userslug}/export/posts": - $ref: 'read/user/userslug/export/posts.yaml' - "/api/user/{userslug}/export/uploads": - $ref: 'read/user/userslug/export/uploads.yaml' - "/api/user/{userslug}/export/profile": - $ref: 'read/user/userslug/export/profile.yaml' - "/api/user/uid/{userslug}/export/{type}": - $ref: 'read/user/uid/userslug/export/type.yaml' /api/categories: $ref: 'read/categories.yaml' "/api/categories/{cid}/moderators": diff --git a/public/openapi/read/user/userslug/export/posts.yaml b/public/openapi/read/user/userslug/export/posts.yaml deleted file mode 100644 index 80132ab8ad..0000000000 --- a/public/openapi/read/user/userslug/export/posts.yaml +++ /dev/null @@ -1,20 +0,0 @@ -get: - tags: - - users - summary: Export a user's posts (.csv) - description: This route retrieves an existing export of user's posts. To create one go to `/user/{userslug}/consent` - parameters: - - name: userslug - in: path - required: true - schema: - type: string - example: admin - responses: - "200": - description: "A CSV file containing a user's posts" - content: - text/csv: - schema: - type: string - format: binary \ No newline at end of file diff --git a/public/openapi/read/user/userslug/export/profile.yaml b/public/openapi/read/user/userslug/export/profile.yaml deleted file mode 100644 index da0b6bec45..0000000000 --- a/public/openapi/read/user/userslug/export/profile.yaml +++ /dev/null @@ -1,20 +0,0 @@ -get: - tags: - - users - summary: Export a user's profile data (.json) - description: This route retrieves an existing export of user's profile data. To create one go to `/user/{userslug}/consent` - parameters: - - name: userslug - in: path - required: true - schema: - type: string - example: admin - responses: - "200": - description: "A JSON file containing the user profile" - content: - text/json: - schema: - type: string - format: binary \ No newline at end of file diff --git a/public/openapi/read/user/userslug/export/uploads.yaml b/public/openapi/read/user/userslug/export/uploads.yaml deleted file mode 100644 index cbe7a9aefa..0000000000 --- a/public/openapi/read/user/userslug/export/uploads.yaml +++ /dev/null @@ -1,20 +0,0 @@ -get: - tags: - - users - summary: Export a user's uploads (.zip) - description: This route retrieves an existing export of user's profile data. To create one go to `/user/{userslug}/consent` - parameters: - - name: userslug - in: path - required: true - schema: - type: string - example: admin - responses: - "200": - description: Successful export of user uploads - content: - application/zip: - schema: - type: string - format: binary \ No newline at end of file diff --git a/src/api/users.js b/src/api/users.js index c23f2c04d6..c0bdf57cd6 100644 --- a/src/api/users.js +++ b/src/api/users.js @@ -459,11 +459,10 @@ usersAPI.generateExport = async (caller, { uid, type }) => { }); child.on('exit', async () => { await db.deleteObjectField('locks', `export:${uid}${type}`); - const userData = await user.getUserFields(uid, ['username', 'userslug']); - const { displayname } = userData; + const { displayname } = await user.getUserFields(uid, ['username']); const n = await notifications.create({ bodyShort: `[[notifications:${type}-exported, ${displayname}]]`, - path: `/api/user/${userData.userslug}/export/${type}`, + path: `/api/v3/users/${uid}/exports/${type}`, nid: `${type}:export:${uid}`, from: uid, }); diff --git a/src/controllers/user.js b/src/controllers/user.js index df71aa0b18..6c924acf87 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -1,8 +1,5 @@ 'use strict'; -const path = require('path'); -const winston = require('winston'); - const user = require('../user'); const privileges = require('../privileges'); const accountHelpers = require('./accounts/helpers'); @@ -79,40 +76,6 @@ userController.getUserDataByUID = async function (callerUid, uid) { return userData; }; -userController.exportPosts = async function (req, res, next) { - sendExport(`${res.locals.uid}_posts.csv`, 'text/csv', res, next); -}; - -userController.exportUploads = function (req, res, next) { - sendExport(`${res.locals.uid}_uploads.zip`, 'application/zip', res, next); -}; - -userController.exportProfile = async function (req, res, next) { - sendExport(`${res.locals.uid}_profile.json`, 'application/json', res, next); -}; - -// DEPRECATED; Remove in NodeBB v3.0.0 -function sendExport(filename, type, res, next) { - winston.warn(`[users/export] Access via page API is deprecated, use GET /api/v3/users/:uid/exports/:type instead.`); - - res.sendFile(filename, { - root: path.join(__dirname, '../../build/export'), - headers: { - 'Content-Type': type, - 'Content-Disposition': `attachment; filename=${filename}`, - }, - }, (err) => { - if (err) { - if (err.code === 'ENOENT') { - res.locals.isAPI = false; - return next(); - } - return next(err); - } - }); -} - require('../promisify')(userController, [ 'getCurrentUser', 'getUserByUID', 'getUserByUsername', 'getUserByEmail', - 'exportPosts', 'exportUploads', 'exportProfile', ]); diff --git a/src/routes/api.js b/src/routes/api.js index caab9c66a3..7f4afdc801 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -1,7 +1,6 @@ 'use strict'; const express = require('express'); -const winston = require('winston'); const uploadsController = require('../controllers/uploads'); const helpers = require('./helpers'); @@ -18,16 +17,6 @@ module.exports = function (app, middleware, controllers) { router.get('/user/username/:username', [...middlewares, middleware.canViewUsers], helpers.tryRoute(controllers.user.getUserByUsername)); router.get('/user/email/:email', [...middlewares, middleware.canViewUsers], helpers.tryRoute(controllers.user.getUserByEmail)); - router.get('/user/:userslug/export/posts', [...middlewares, middleware.authenticateRequest, middleware.ensureLoggedIn, middleware.checkAccountPermissions, middleware.exposeUid], helpers.tryRoute(controllers.user.exportPosts)); - router.get('/user/:userslug/export/uploads', [...middlewares, middleware.authenticateRequest, middleware.ensureLoggedIn, middleware.checkAccountPermissions, middleware.exposeUid], helpers.tryRoute(controllers.user.exportUploads)); - router.get('/user/:userslug/export/profile', [...middlewares, middleware.authenticateRequest, middleware.ensureLoggedIn, middleware.checkAccountPermissions, middleware.exposeUid], helpers.tryRoute(controllers.user.exportProfile)); - - // Deprecated, remove in v1.20.0 - router.get('/user/uid/:userslug/export/:type', (req, res) => { - winston.warn(`[router] \`/api/user/uid/${req.params.userslug}/export/${req.params.type}\` is deprecated, call it \`/api/user/${req.params.userslug}/export/${req.params.type}\`instead.`); - res.redirect(`/api/user/${req.params.userslug}/export/${req.params.type}`); - }); - router.get('/categories/:cid/moderators', [...middlewares], helpers.tryRoute(controllers.api.getModerators)); router.get('/recent/posts/:term?', [...middlewares], helpers.tryRoute(controllers.posts.getRecentPosts)); router.get('/unread/total', [...middlewares, middleware.ensureLoggedIn], helpers.tryRoute(controllers.unread.unreadTotal)); diff --git a/test/controllers.js b/test/controllers.js index bb7cdedc7b..f6c642a00b 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -7,8 +7,10 @@ const request = require('request'); const requestAsync = require('request-promise-native'); const fs = require('fs'); const path = require('path'); +const util = require('util'); const db = require('./mocks/databasemock'); +const api = require('../src/api'); const categories = require('../src/categories'); const topics = require('../src/topics'); const posts = require('../src/posts'); @@ -21,6 +23,8 @@ const plugins = require('../src/plugins'); const utils = require('../src/utils'); const helpers = require('./helpers'); +const sleep = util.promisify(setTimeout); + describe('Controllers', () => { let tid; let cid; @@ -1476,30 +1480,41 @@ describe('Controllers', () => { }); }); - it('should export users posts', (done) => { - request(`${nconf.get('url')}/api/user/foo/export/posts`, { jar: jar }, (err, res, body) => { - assert.ifError(err); - assert.equal(res.statusCode, 200); - assert(body); - done(); + describe('user data export routes', () => { + before(async () => { + const types = ['profile', 'uploads', 'posts']; + await Promise.all(types.map(async (type) => { + await api.users.generateExport({ uid: fooUid, ip: '127.0.0.1' }, { uid: fooUid, type }); + })); + await sleep(5000); }); - }); - it('should export users uploads', (done) => { - request(`${nconf.get('url')}/api/user/foo/export/uploads`, { jar: jar }, (err, res, body) => { - assert.ifError(err); - assert.equal(res.statusCode, 200); - assert(body); - done(); + it('should export users posts', (done) => { + console.log(`${nconf.get('url')}/api/v3/users/${fooUid}/exports/posts`); + request(`${nconf.get('url')}/api/v3/users/${fooUid}/exports/posts`, { jar: jar }, (err, res, body) => { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); }); - }); - it('should export users profile', (done) => { - request(`${nconf.get('url')}/api/user/foo/export/profile`, { jar: jar }, (err, res, body) => { - assert.ifError(err); - assert.equal(res.statusCode, 200); - assert(body); - done(); + it('should export users uploads', (done) => { + request(`${nconf.get('url')}/api/v3/users/${fooUid}/exports/uploads`, { jar: jar }, (err, res, body) => { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); + + it('should export users profile', (done) => { + request(`${nconf.get('url')}/api/v3/users/${fooUid}/exports/profile`, { jar: jar }, (err, res, body) => { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); }); });