Skip to content

Commit

Permalink
feat: closes #9048, tests for topic thumbs routes, write API schema
Browse files Browse the repository at this point in the history
  • Loading branch information
julianlam committed Dec 9, 2020
1 parent ef10b6b commit 5950683
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 16 deletions.
2 changes: 2 additions & 0 deletions public/openapi/write.yaml
Expand Up @@ -76,6 +76,8 @@ paths:
$ref: 'write/topics/tid/ignore.yaml'
/topics/{tid}/tags:
$ref: 'write/topics/tid/tags.yaml'
/topics/{tid}/thumbs:
$ref: 'write/topics/tid/thumbs.yaml'
/posts/{pid}:
$ref: 'write/posts/pid.yaml'
/posts/{pid}/state:
Expand Down
146 changes: 146 additions & 0 deletions public/openapi/write/topics/tid/thumbs.yaml
@@ -0,0 +1,146 @@
get:
tags:
- topics
summary: get topic thumbnails
description: This operation retrieves a topic's uploaded thumbnails
parameters:
- in: path
name: tid
schema:
type: string
required: true
description: a valid topic id
example: 1
responses:
'200':
description: Thumbnails successfully retrieved
content:
application/json:
schema:
type: object
properties:
status:
$ref: ../../../components/schemas/Status.yaml#/Status
response:
type: object
properties: {}
post:
tags:
- topics
summary: add topic thumbnail
description: This operation adds a thumbnail to an existing topic or a draft (via a composer `uuid`)
parameters:
- in: path
name: tid
schema:
type: string
required: true
description: a valid topic id
example: 1
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
files:
type: array
items:
type: string
format: binary
responses:
'200':
description: Thumbnail successfully added
content:
application/json:
schema:
type: array
items:
type: object
properties:
url:
type: string
path:
type: string
name:
type: string
put:
tags:
- topics
summary: migrate topic thumbnail
description: This operation migrates a thumbnails from a topic or draft, to another tid or draft.
parameters:
- in: path
name: tid
schema:
type: string
required: true
description: a valid topic id or draft uuid
example: 1
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
tid:
type: string
description: a valid topic id or draft uuid
example: '1'
responses:
'200':
description: Topic thumbnails migrated
content:
application/json:
schema:
type: object
properties:
status:
$ref: ../../../components/schemas/Status.yaml#/Status
response:
type: object
properties: {}
delete:
tags:
- topics
summary: remove topic thumbnail
description: This operation removes a topic thumbnail.
parameters:
- in: path
name: tid
schema:
type: string
required: true
description: a valid topic id
example: 1
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
path:
type: string
description: Relative path to the topic thumbnail
example: files/test.png
responses:
'200':
description: Topic thumbnail removed
content:
application/json:
schema:
type: object
properties:
status:
$ref: ../../../components/schemas/Status.yaml#/Status
response:
type: array
description: A list of the topic thumbnails that still remain
items:
type: object
properties:
url:
type: string
description: Path to a topic thumbnail
2 changes: 1 addition & 1 deletion src/controllers/uploads.js
Expand Up @@ -16,10 +16,10 @@ const uploadsController = module.exports;
uploadsController.upload = async function (req, res, filesIterator) {
let files = req.files.files;

// These checks added because of odd behaviour by request: https://github.com/request/request/issues/2445
if (!Array.isArray(files)) {
return res.status(500).json('invalid files');
}

if (Array.isArray(files[0])) {
files = files[0];
}
Expand Down
54 changes: 39 additions & 15 deletions test/api.js
Expand Up @@ -99,6 +99,7 @@ describe('API', async () => {
timestamp: Date.now(),
}],
});
meta.config.allowTopicsThumbnail = 1;

// Create a category
const testCategory = await categories.create({ name: 'test' });
Expand All @@ -123,8 +124,9 @@ describe('API', async () => {
// Create a new chat room
await messaging.newRoom(1, [2]);

// Create an empty file to test DELETE /files
// Create an empty file to test DELETE /files and thumb deletion
fs.closeSync(fs.openSync(path.resolve(nconf.get('upload_path'), 'files/test.txt'), 'w'));
fs.closeSync(fs.openSync(path.resolve(nconf.get('upload_path'), 'files/test.png'), 'w'));

const socketUser = require('../src/socket.io/user');
const socketAdmin = require('../src/socket.io/admin');
Expand Down Expand Up @@ -172,6 +174,7 @@ describe('API', async () => {

function generateTests(api, paths, prefix) {
// Iterate through all documented paths, make a call to it, and compare the result body with what is defined in the spec
const pathLib = path; // for calling path module from inside this forEach
paths.forEach((path) => {
const context = api.paths[path];
let schema;
Expand Down Expand Up @@ -224,13 +227,20 @@ describe('API', async () => {
url = nconf.get('url') + (prefix || '') + testPath;
});

it('should contain a valid request body (if present) with application/json type if POST/PUT/DELETE', () => {
it('should contain a valid request body (if present) with application/json or multipart/form-data type if POST/PUT/DELETE', () => {
if (['post', 'put', 'delete'].includes(method) && context[method].hasOwnProperty('requestBody')) {
assert(context[method].requestBody);
assert(context[method].requestBody.content);
assert(context[method].requestBody.content['application/json']);
assert(context[method].requestBody.content['application/json'].schema);
assert(context[method].requestBody.content['application/json'].schema.properties);

if (context[method].requestBody.content.hasOwnProperty('application/json')) {
assert(context[method].requestBody.content['application/json']);
assert(context[method].requestBody.content['application/json'].schema);
assert(context[method].requestBody.content['application/json'].schema.properties);
} else if (context[method].requestBody.content.hasOwnProperty('multipart/form-data')) {
assert(context[method].requestBody.content['multipart/form-data']);
assert(context[method].requestBody.content['multipart/form-data'].schema);
assert(context[method].requestBody.content['multipart/form-data'].schema.properties);
}
}
});

Expand All @@ -242,20 +252,34 @@ describe('API', async () => {
}

let body = {};
if (context[method].hasOwnProperty('requestBody')) {
let type = 'json';
if (context[method].hasOwnProperty('requestBody') && context[method].requestBody.content['application/json']) {
body = buildBody(context[method].requestBody.content['application/json'].schema.properties);
} else if (context[method].hasOwnProperty('requestBody') && context[method].requestBody.content['multipart/form-data']) {
type = 'form';
}

try {
// console.log(`calling ${method} ${url} with`, body);
response = await request(url, {
method: method,
jar: !unauthenticatedRoutes.includes(path) ? jar : undefined,
json: true,
headers: headers,
qs: qs,
body: body,
});
if (type === 'json') {
// console.log(`calling ${method} ${url} with`, body);
response = await request(url, {
method: method,
jar: !unauthenticatedRoutes.includes(path) ? jar : undefined,
json: true,
headers: headers,
qs: qs,
body: body,
});
} else if (type === 'form') {
response = await new Promise((resolve, reject) => {
helpers.uploadFile(url, pathLib.join(__dirname, './files/test.png'), {}, jar, csrfToken, function (err, res, body) {
if (err) {
return reject(err);
}
resolve(body);
});
});
}
} catch (e) {
assert(!e, `${method.toUpperCase()} ${path} resolved with ${e.message}`);
}
Expand Down

0 comments on commit 5950683

Please sign in to comment.