From 2fa24b947818073b3c09d10d781df53b734da2d9 Mon Sep 17 00:00:00 2001 From: lesion Date: Thu, 10 Mar 2022 13:51:24 +0100 Subject: [PATCH] more test --- .gitignore | 9 ++++---- server/api/controller/event.js | 7 ++++++ server/api/index.js | 2 +- tests/app.test.js | 40 ++++++++++++++++++++++----------- tests/seeds/config.json | 21 +++++++++++++++++ tests/seeds/starter.sqlite | Bin 0 -> 159744 bytes 6 files changed, 61 insertions(+), 18 deletions(-) create mode 100644 tests/seeds/config.json create mode 100644 tests/seeds/starter.sqlite diff --git a/.gitignore b/.gitignore index f1a48207..c10afaf8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,14 @@ # Created by .ignore support plugin (hsz.mobi) ### Gancio dev configuration -*.sqlite +gancio.sqlite +db.sqlite releases wp-plugin/wpgancio config/development.json -gancio_config.json -config.json -db.sqlite +/gancio_config.json +/config.json +/assets/config.json thumb docs/_site .vscode diff --git a/server/api/controller/event.js b/server/api/controller/event.js index ac0d44d5..a65229e2 100644 --- a/server/api/controller/event.js +++ b/server/api/controller/event.js @@ -290,6 +290,13 @@ const eventController = { res.sendStatus(200) }, + async isAnonEventAllowed (req, res, next) { + if (!res.locals.settings.allow_anon_event) { + return res.sendStatus(403) + } + next() + }, + async add (req, res) { // req.err comes from multer streaming error if (req.err) { diff --git a/server/api/index.js b/server/api/index.js index 8622a84f..1ad30dfe 100644 --- a/server/api/index.js +++ b/server/api/index.js @@ -101,7 +101,7 @@ if (config.status !== 'READY') { */ // allow anyone to add an event (anon event has to be confirmed, TODO: flood protection) - api.post('/event', upload.single('image'), eventController.add) + api.post('/event', eventController.isAnonEventAllowed, upload.single('image'), eventController.add) api.put('/event', isAuth, upload.single('image'), eventController.update) api.get('/event/import', isAuth, helpers.importURL) diff --git a/tests/app.test.js b/tests/app.test.js index cdb2fca6..0b3d8d31 100644 --- a/tests/app.test.js +++ b/tests/app.test.js @@ -1,6 +1,7 @@ const request = require('supertest') +const fs = require('fs') -const admin = { username: 'admin', password: 'SsJOn5l0JpBE', grant_type: 'password', client_id: 'self' } +const admin = { username: 'admin', password: 'JqFuXEnkTyOR', grant_type: 'password', client_id: 'self' } let token // - event list should be empty // - try to write without auth @@ -11,6 +12,7 @@ let token // - should login with correct authentication let app beforeAll( async () => { + fs.copyFileSync('./starter.sqlite', './testdb.sqlite') await require('../server/initialize.server.js')() app = require('../server/routes.js') }) @@ -61,17 +63,29 @@ describe('Authentication / Authorization', () => { .expect(403) }) - // test('should create anon event only when allowed', async () => { - // let response - // response = await request(app) - // .post('/api/settings') // auth._token.local - // .send({ key: 'allow_anon_event', value: false }) - // .auth(token.access_token, { type: 'bearer' }) - // .expect(200) - // // expect(response.statusCode).toBe(200) - // // response = await request(app).post('/api/settings') - // // .send({ key: 'allow_anon_event', value: false }) - // }) + test('should create anon event only when allowed', async () => { + let response + response = await request(app).post('/api/settings') + .send({ key: 'allow_anon_event', value: false }) + .auth(token.access_token, { type: 'bearer' }) + .expect(200) + + response = await request(app).post('/api/event') + .expect(403) + + response = await request(app).post('/api/settings') + .send({ key: 'allow_anon_event', value: true }) + .auth(token.access_token, { type: 'bearer' }) + .expect(200) + + response = await request(app).post('/api/event') + .send({ title: 'test title', place_name: 'place name', start_datetime: new Date().getTime() * 1000 }) + .expect(200) + + // expect(response.statusCode).toBe(200) + // response = await request(app).post('/api/settings') + // .send({ key: 'allow_anon_event', value: false }) + }) }) @@ -87,7 +101,7 @@ describe('Events', () => { const promises = Object.keys(required_fields).map(async field => { const response = await request(app).post('/api/event').send(required_fields[field]) - expect(response.statusCode).toBe(400) + .expect(400) expect(response.text).toBe(`${field} is required`) return }) diff --git a/tests/seeds/config.json b/tests/seeds/config.json new file mode 100644 index 00000000..06cfa7e5 --- /dev/null +++ b/tests/seeds/config.json @@ -0,0 +1,21 @@ +{ + "baseurl": "http://localhost:13120", + "hostname": "127.0.0.1", + "server": { + "host": "0.0.0.0", + "port": 13120 + }, + "log_level": "error", + "log_path": "./logs", + "db": { + "dialect": "sqlite", + "storage": "./testdb.sqlite", + "host": "localhost", + "database": "gancio", + "logging": false, + "dialectOptions": { + "autoJsonMap": false + } + }, + "upload_path": "./uploads" +} diff --git a/tests/seeds/starter.sqlite b/tests/seeds/starter.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..052d7ba902b10de444832f49aa383eeb15ece111 GIT binary patch literal 159744 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 U00;m9AOHk_01yBIUswYF9}c=!QUCw| literal 0 HcmV?d00001