From 5b7905e86a929575c07418dd3d0b741007e13d87 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Mon, 24 May 2021 17:06:02 +0200 Subject: [PATCH 01/15] cjs > esm imports --- server/app.js | 43 +++++++++++++------------ server/classes/EventTimer.js | 12 +++---- server/classes/Timer.js | 6 ++-- server/config.js | 15 +++++++++ server/config.json | 15 --------- server/controllers/OscController.js | 8 ++--- server/controllers/eventController.js | 24 +++++++------- server/controllers/eventsController.js | 28 +++++++++------- server/data/dataModel.js | 4 +-- server/data/eventsDefinition.js | 8 ++--- server/data/playbackData.json | 8 ----- server/package.json | 2 +- server/routes/eventRouter.js | 39 ++++++++++++++--------- server/routes/eventsRouter.js | 36 +++++++++++++-------- server/routes/playbackRouter.js | 6 ++-- server/yarn.lock | 44 ++++++-------------------- 16 files changed, 138 insertions(+), 160 deletions(-) create mode 100644 server/config.js delete mode 100644 server/config.json delete mode 100644 server/data/playbackData.json diff --git a/server/app.js b/server/app.js index 3210ded28..6064b1251 100644 --- a/server/app.js +++ b/server/app.js @@ -1,27 +1,33 @@ // get config -const config = require('./config.json'); +import { config } from './config.js'; // init database -const low = require('lowdb'); -const FileSync = require('lowdb/adapters/FileSync'); +import { Low, JSONFile } from 'lowdb'; -const adapter = new FileSync(config.database.filename); -const db = low(adapter); +const adapter = new JSONFile(config.database.filename); +export const db = new Low(adapter); // dependencies -const express = require('express'); -const http = require('http'); -const cors = require('cors'); -const { dbModel } = require('./data/dataModel.js'); +import express from 'express'; +import http from 'http'; +import cors from 'cors'; +import { dbModel } from './data/dataModel.js'; -db.defaults(dbModel).write(); +// Read data from JSON file, this will set db.data content +await db.read(); -// export db -module.exports.db = db; +// If file.json doesn't exist, db.data will be null +// Set default data +// db.data ||= { posts: [] }; +if (!db.data) db.data = { dbModel }; + +// get data +const { events } = db.data; // Import Routes -const eventsRouter = require('./routes/eventsRouter.js'); -const eventRouter = require('./routes/eventRouter.js'); +import { router as eventsRouter } from './routes/eventsRouter.js'; +import { router as eventRouter } from './routes/eventRouter.js'; + // No settings yet // const settingsRouter = require('./routes/settingsRouter.js'); @@ -29,7 +35,7 @@ const eventRouter = require('./routes/eventRouter.js'); const port = process.env.PORT || config.server.port; // Global Objects -const EventTimer = require('./classes/EventTimer.js'); +import { EventTimer } from './classes/EventTimer.js'; // Create express APP const app = express(); @@ -62,12 +68,9 @@ app.use((err, req, res, next) => { // create HTTP server const server = http.createServer(app); -// get data (if any) -const eventlist = db.get('events').value(); - // init timer global.timer = new EventTimer(server, config); -global.timer.setupWithEventList(eventlist); +global.timer.setupWithEventList(events); // Start server server.listen(port, () => @@ -75,6 +78,6 @@ server.listen(port, () => ); // Start OSC server -const { initiateOSC } = require('./controllers/OscController.js'); +import { initiateOSC } from './controllers/OscController.js'; initiateOSC(config.osc); diff --git a/server/classes/EventTimer.js b/server/classes/EventTimer.js index 6059a7a18..a81ee4388 100644 --- a/server/classes/EventTimer.js +++ b/server/classes/EventTimer.js @@ -1,5 +1,5 @@ -const Timer = require('./Timer'); -const socketIo = require('socket.io'); +import { Timer } from './Timer.js'; +import { Server } from 'socket.io'; /* * EventTimer adds functions specific to APP @@ -9,7 +9,7 @@ const socketIo = require('socket.io'); * */ -class EventTimer extends Timer { +export class EventTimer extends Timer { // AUX DAYMS = 86400000; @@ -57,12 +57,12 @@ class EventTimer extends Timer { numEvents = null; _eventlist = null; - constructor(server, config) { + constructor(httpServer, config) { // call super constructor super(); // initialise socketIO server - this.io = socketIo(server, { + this.io = new Server(httpServer, { cors: { origin: '*', methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', @@ -797,5 +797,3 @@ class EventTimer extends Timer { this.loadEvent(this.selectedEventIndex); } } - -module.exports = EventTimer; diff --git a/server/classes/Timer.js b/server/classes/Timer.js index 6fd83e5e3..3a402ccd7 100644 --- a/server/classes/Timer.js +++ b/server/classes/Timer.js @@ -4,7 +4,7 @@ * */ -class Timer { +export class Timer { clock = null; duration = null; current = null; @@ -210,6 +210,4 @@ class Timer { this._finishedAt = null; } } -} - -module.exports = Timer; +} \ No newline at end of file diff --git a/server/config.js b/server/config.js new file mode 100644 index 000000000..64ef4ef2b --- /dev/null +++ b/server/config.js @@ -0,0 +1,15 @@ +export const config = { + timer: { + refresh: 1000, + }, + server: { + port: 4001, + }, + database: { + filename: 'db.json', + tablename: 'events', + }, + osc: { + port: 8888, + }, +}; diff --git a/server/config.json b/server/config.json deleted file mode 100644 index 40d18e4a8..000000000 --- a/server/config.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "timer": { - "refresh": 1000 - }, - "server": { - "port": 4001 - }, - "database": { - "filename": "db.json", - "tablename": "events" - }, - "osc": { - "port": 8888 - } -} \ No newline at end of file diff --git a/server/controllers/OscController.js b/server/controllers/OscController.js index 288e5ee5e..89b1010f2 100644 --- a/server/controllers/OscController.js +++ b/server/controllers/OscController.js @@ -1,7 +1,7 @@ -const osc = require('node-osc'); +import { Server } from 'node-osc'; -const initiateOSC = (config) => { - const oscServer = new osc.Server(config.port, '0.0.0.0', () => { +export const initiateOSC = (config) => { + const oscServer = new Server(config.port, '0.0.0.0', () => { console.log(`OSC Server is listening on port ${config.port}`); }); @@ -83,5 +83,3 @@ const initiateOSC = (config) => { } }); }; - -module.exports = { initiateOSC }; diff --git a/server/controllers/eventController.js b/server/controllers/eventController.js index f78e4204e..23988490b 100644 --- a/server/controllers/eventController.js +++ b/server/controllers/eventController.js @@ -1,5 +1,5 @@ // get database -const { db } = require('../app.js'); +import { db } from '../app.js'; const table = 'event'; @@ -9,7 +9,7 @@ function getSettings() { // Create controller for GET request to 'event' // Returns ACK message -exports.getAll = async (req, res) => { +export const getAll = async (req, res) => { const settings = getSettings(); if (settings) res.json(settings); else res.sendStatus(400); @@ -17,7 +17,7 @@ exports.getAll = async (req, res) => { // Create controller for POST request to 'event' // Returns ACK message -exports.post = async (req, res) => { +export const post = async (req, res) => { if (!req.body) { res.status(400).send('No object found in request'); return; @@ -35,7 +35,7 @@ exports.post = async (req, res) => { // Create controller for GET request to 'event/title' // Returns ACK message -exports.titleGet = async (req, res) => { +export const titleGet = async (req, res) => { const settings = getSettings(); if (settings) res.json(settings.title); @@ -44,7 +44,7 @@ exports.titleGet = async (req, res) => { // Create controller for POST request to 'event/title' // Returns ACK message -exports.titlePost = async (req, res) => { +export const titlePost = async (req, res) => { if (!req.body) { res.status(400).send('No object found in request'); return; @@ -61,7 +61,7 @@ exports.titlePost = async (req, res) => { // Create controller for GET request to '/event/url' // Returns ACK message -exports.urlGet = async (req, res) => { +export const urlGet = async (req, res) => { const event = getSettings(); if (event) res.json(event.url); @@ -70,7 +70,7 @@ exports.urlGet = async (req, res) => { // Create controller for POST request to '/event/url' // Returns ACK message -exports.urlPost = async (req, res) => { +export const urlPost = async (req, res) => { if (!req.body) { res.status(400).send('No object found in request'); return; @@ -87,7 +87,7 @@ exports.urlPost = async (req, res) => { // Create controller for GET request to 'event/publicInfo' // Returns ACK message -exports.publicInfoGet = async (req, res) => { +export const publicInfoGet = async (req, res) => { const settings = getSettings(); if (settings) res.json(settings.publicInfo); @@ -96,7 +96,7 @@ exports.publicInfoGet = async (req, res) => { // Create controller for POST request to '/event/publicInfo' // Returns ACK message -exports.publicInfoPost = async (req, res) => { +export const publicInfoPost = async (req, res) => { if (!req.body) { res.status(400).send('No object found in request'); return; @@ -113,7 +113,7 @@ exports.publicInfoPost = async (req, res) => { // Create controller for GET request to 'event/backstageInfo' // Returns ACK message -exports.backstageInfoGet = async (req, res) => { +export const backstageInfoGet = async (req, res) => { const settings = getSettings(); if (settings) res.json(settings.backstageInfo); @@ -122,7 +122,7 @@ exports.backstageInfoGet = async (req, res) => { // Create controller for POST request to '/event/info' // Returns ACK message -exports.backstageInfoPost = async (req, res) => { +export const backstageInfoPost = async (req, res) => { if (!req.body) { res.status(400).send('No object found in request'); return; @@ -139,6 +139,6 @@ exports.backstageInfoPost = async (req, res) => { // Create controller for GET request to 'event/osc' // Returns ACK message -exports.osc = async (req, res) => { +export const osc = async (req, res) => { res.send('Not yet implemented').status(500); }; diff --git a/server/controllers/eventsController.js b/server/controllers/eventsController.js index 5f3973121..4768eeb16 100644 --- a/server/controllers/eventsController.js +++ b/server/controllers/eventsController.js @@ -1,10 +1,14 @@ // get database -const db = require('../app.js').db; +import { db } from '../app.js'; // utils -const customAlphabet = require('nanoid').customAlphabet; +import { customAlphabet } from 'nanoid'; const nanoid = customAlphabet('1234567890abcdef', 4); -const eventDefs = require('../data/eventsDefinition.js'); +import { + event as eventDef, + block as blockDef, + delay as delayDEf, +} from '../data/eventsDefinition.js'; function _getEventsCount() { return db.get('events').size().value(); @@ -68,21 +72,21 @@ function _deleteTimerId(entryId) { // Create controller for GET request to '/events' // Returns - -exports.eventsGetAll = async (req, res) => { +export const eventsGetAll = async (req, res) => { const results = db.get('events').value(); res.json(results); }; // Create controller for GET request to '/events/:eventId' // Returns - -exports.eventsGetById = async (req, res) => { +export const eventsGetById = async (req, res) => { const e = db.get('events').find({ id: req.params.eventId }).value(); res.json(e); }; // Create controller for POST request to '/events/' // Returns - -exports.eventsPost = async (req, res) => { +export const eventsPost = async (req, res) => { // TODO: Validate event if (!req.body) { res.status(400).send(`No object found in request`); @@ -131,7 +135,7 @@ exports.eventsPost = async (req, res) => { // Create controller for PUT request to '/events/' // Returns - -exports.eventsPut = async (req, res) => { +export const eventsPut = async (req, res) => { // no valid params if (!req.body) { res.status(400).send(`No object found`); @@ -162,12 +166,12 @@ exports.eventsPut = async (req, res) => { // Create controller for PATCH request to '/events/' // Returns - -exports.eventsPatch = async (req, res) => { +export const eventsPatch = async (req, res) => { // Code is the same as put, call that this.eventsPut(req, res); }; -exports.eventsReorder = async (req, res) => { +export const eventsReorder = async (req, res) => { // TODO: Validate event if (!req.body) { res.status(400).send(`No object found in request`); @@ -209,7 +213,7 @@ exports.eventsReorder = async (req, res) => { // Create controller for PATCH request to '/events/applydelay/:eventId' // Returns - -exports.eventsApplyDelay = async (req, res) => { +export const eventsApplyDelay = async (req, res) => { // no valid params if (!req.params.eventId) { res.status(400).send(`No id found in request`); @@ -274,7 +278,7 @@ exports.eventsApplyDelay = async (req, res) => { // Create controller for DELETE request to '/events/:eventId' // Returns - -exports.eventsDelete = async (req, res) => { +export const eventsDelete = async (req, res) => { // no valid params if (!req.params.eventId) { res.status(400).send(`No id found in request`); @@ -298,7 +302,7 @@ exports.eventsDelete = async (req, res) => { // Create controller for DELETE request to '/events/:eventId' // Returns - -exports.eventsDeleteAll = async (req, res) => { +export const eventsDeleteAll = async (req, res) => { try { // set with nothing db.set('events', []).write(); diff --git a/server/data/dataModel.js b/server/data/dataModel.js index cc6f67470..cbe964153 100644 --- a/server/data/dataModel.js +++ b/server/data/dataModel.js @@ -1,4 +1,4 @@ -const dbModel = { +export const dbModel = { events: [], event: { title: '', @@ -14,5 +14,3 @@ const dbModel = { lock: false, }, }; - -module.exports = { dbModel }; diff --git a/server/data/eventsDefinition.js b/server/data/eventsDefinition.js index d98f968f8..f1f326ee8 100644 --- a/server/data/eventsDefinition.js +++ b/server/data/eventsDefinition.js @@ -1,4 +1,4 @@ -const event = { +export const event = { title: '', subtitle: '', presenter: '', @@ -10,14 +10,12 @@ const event = { revision: 0, }; -const delay = { +export const delay = { duration: 0, type: 'delay', revision: 0, }; -const block = { +export const block = { type: 'block', }; - -module.exports = { event, delay, block }; diff --git a/server/data/playbackData.json b/server/data/playbackData.json deleted file mode 100644 index 0337f8752..000000000 --- a/server/data/playbackData.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "current": null, - "next": null, - "currentTimer": null, - "numEvents": 0, - "state": "pause", - "prevState": "pause" -} \ No newline at end of file diff --git a/server/package.json b/server/package.json index 45025a56a..243cd0fa3 100644 --- a/server/package.json +++ b/server/package.json @@ -6,7 +6,7 @@ "body-parser": "~1.19.0", "express": "~4.17.1", "express-session": "~1.17.1", - "lowdb": "^1.0.0", + "lowdb": "2.1.0", "nanoid": "^3.1.22", "node-osc": "^6.0.1", "passport": "~0.4.1", diff --git a/server/routes/eventRouter.js b/server/routes/eventRouter.js index 327fe30b5..99a6b5054 100644 --- a/server/routes/eventRouter.js +++ b/server/routes/eventRouter.js @@ -1,37 +1,46 @@ -const express = require('express'); -const router = express.Router(); +import express from 'express'; +export const router = express.Router(); // import event controller -const eventController = require('../controllers/eventController'); +import { + getAll, + post, + titleGet, + titlePost, + publicInfoGet, + publicInfoPost, + backstageInfoGet, + backstageInfoPost, + urlGet, + urlPost, +} from '../controllers/eventController.js'; // create route between controller and '/settings' endpoint -router.get('/', eventController.getAll); +router.get('/', getAll); // create route between controller and '/settings' endpoint -router.post('/', eventController.post); +router.post('/', post); // create route between controller and '/event/title' endpoint -router.get('/title', eventController.titleGet); +router.get('/title', titleGet); // create route between controller and '/event/title' endpoint -router.post('/title', eventController.titlePost); +router.post('/title', titlePost); // create route between controller and '/event/info' endpoint -router.get('/publicInfo', eventController.publicInfoGet); +router.get('/publicInfo', publicInfoGet); // create route between controller and '/event/info' endpoint -router.post('/publicInfo', eventController.publicInfoPost); +router.post('/publicInfo', publicInfoPost); // create route between controller and '/event/info' endpoint -router.get('/backstageInfo', eventController.backstageInfoGet); +router.get('/backstageInfo', backstageInfoGet); // create route between controller and '/event/info' endpoint -router.post('/backstageInfo', eventController.backstageInfoPost); +router.post('/backstageInfo', backstageInfoPost); // create route between controller and '/event/url' endpoint -router.get('/url', eventController.urlGet); +router.get('/url', urlGet); // create route between controller and '/event/url' endpoint -router.post('/url', eventController.urlPost); - -module.exports = router; +router.post('/url', urlPost); diff --git a/server/routes/eventsRouter.js b/server/routes/eventsRouter.js index b8bf90cd9..9ea280c45 100644 --- a/server/routes/eventsRouter.js +++ b/server/routes/eventsRouter.js @@ -1,34 +1,42 @@ -const express = require('express'); -const router = express.Router(); +import express from 'express'; +export const router = express.Router(); // import events controller -const eventsController = require('../controllers/eventsController'); +import { + eventsGetAll, + eventsGetById, + eventsPost, + eventsPut, + eventsPatch, + eventsReorder, + eventsApplyDelay, + eventsDeleteAll, + eventsDelete, +} from '../controllers/eventsController.js'; // create route between controller and '/events/' endpoint -router.get('/', eventsController.eventsGetAll); +router.get('/', eventsGetAll); // create route between controller and '/events/:eventId' endpoint -router.get('/:eventId', eventsController.eventsGetById); +router.get('/:eventId', eventsGetById); // create route between controller and '/events/' endpoint -router.post('/', eventsController.eventsPost); +router.post('/', eventsPost); // create route between controller and '/events/' endpoint -router.put('/', eventsController.eventsPut); +router.put('/', eventsPut); // create route between controller and '/events/' endpoint -router.patch('/', eventsController.eventsPatch); +router.patch('/', eventsPatch); // create route between controller and '/events/reorder' endpoint -router.patch('/reorder/', eventsController.eventsReorder); +router.patch('/reorder/', eventsReorder); // create route between controller and '/events/applydelay/:eventId' endpoint -router.patch('/applydelay/:eventId', eventsController.eventsApplyDelay); +router.patch('/applydelay/:eventId', eventsApplyDelay); // create route between controller and '/events/all' endpoint -router.delete('/all', eventsController.eventsDeleteAll); +router.delete('/all', eventsDeleteAll); // create route between controller and '/events/:eventId' endpoint -router.delete('/:eventId', eventsController.eventsDelete); - -module.exports = router; +router.delete('/:eventId', eventsDelete); diff --git a/server/routes/playbackRouter.js b/server/routes/playbackRouter.js index e767a3156..3b71b9c86 100644 --- a/server/routes/playbackRouter.js +++ b/server/routes/playbackRouter.js @@ -1,5 +1,5 @@ -const express = require('express'); -const router = express.Router(); +import express from 'express'; +export const router = express.Router(); // import event controller const playbackController = require('../controllers/playbackController'); @@ -30,5 +30,3 @@ router.get('/unload', playbackController.pbUnload); // create route between controller and '/playback/reload' endpoint router.get('/reload', playbackController.pbReload); - -module.exports = router; diff --git a/server/yarn.lock b/server/yarn.lock index 4b7da8610..7ef514f68 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -253,11 +253,6 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= -graceful-fs@^4.1.3: - version "4.2.6" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" - integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== - http-errors@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" @@ -302,26 +297,12 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -is-promise@^2.1.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" - integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== - -lodash@4: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -lowdb@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowdb/-/lowdb-1.0.0.tgz#5243be6b22786ccce30e50c9a33eac36b20c8064" - integrity sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ== +lowdb@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lowdb/-/lowdb-2.1.0.tgz#c8063e228b5ab3e082ece90e0512537ecb6e1e2a" + integrity sha512-F4Go8/V37gAidTR3c5poyjprOpZSDNSLJVOmI0ny4D4q9rC37OkBhlzX0bqj7LZlT3UIj4FchmZrrSw7qY+eGQ== dependencies: - graceful-fs "^4.1.3" - is-promise "^2.1.0" - lodash "4" - pify "^3.0.0" - steno "^0.4.1" + steno "^1.0.0" media-typer@0.3.0: version "0.3.0" @@ -446,11 +427,6 @@ pause@0.0.1: resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" integrity sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10= -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - proxy-addr@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" @@ -567,12 +543,10 @@ socket.io@^4.0.0: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= -steno@^0.4.1: - version "0.4.4" - resolved "https://registry.yarnpkg.com/steno/-/steno-0.4.4.tgz#071105bdfc286e6615c0403c27e9d7b5dcb855cb" - integrity sha1-BxEFvfwobmYVwEA8J+nXtdy4Vcs= - dependencies: - graceful-fs "^4.1.3" +steno@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/steno/-/steno-1.0.0.tgz#475e32c6066ec9760229eaaf1550601764fbecba" + integrity sha512-C/KgCvEa1yWnpHmaPjAXrz1yWxh6hs+HvhqqPa71euaQmNi1wr4+WFo57VQxjKKuFl2KqS7gtlrN0oxj2noQLw== toidentifier@1.0.0: version "1.0.0" From bb1f063c6a86b68c0fb6eec27aee4f77c7fa89fe Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Mon, 24 May 2021 18:22:29 +0200 Subject: [PATCH 02/15] migrate event logic --- server/app.js | 9 +++-- server/controllers/eventController.js | 47 ++++++++------------------- server/data/dataModel.js | 2 +- 3 files changed, 21 insertions(+), 37 deletions(-) diff --git a/server/app.js b/server/app.js index 6064b1251..8244342a3 100644 --- a/server/app.js +++ b/server/app.js @@ -18,11 +18,14 @@ await db.read(); // If file.json doesn't exist, db.data will be null // Set default data -// db.data ||= { posts: [] }; -if (!db.data) db.data = { dbModel }; +// db.data ||= { events: [] }; +if (db.data == null) { + db.data = dbModel; + db.write(); +} // get data -const { events } = db.data; +export const data = db.data; // Import Routes import { router as eventsRouter } from './routes/eventsRouter.js'; diff --git a/server/controllers/eventController.js b/server/controllers/eventController.js index 23988490b..c003e4086 100644 --- a/server/controllers/eventController.js +++ b/server/controllers/eventController.js @@ -1,18 +1,10 @@ // get database -import { db } from '../app.js'; - -const table = 'event'; - -function getSettings() { - return db.get(table).value(); -} +import { db, data } from '../app.js'; // Create controller for GET request to 'event' // Returns ACK message export const getAll = async (req, res) => { - const settings = getSettings(); - if (settings) res.json(settings); - else res.sendStatus(400); + res.json(data.event); }; // Create controller for POST request to 'event' @@ -24,22 +16,20 @@ export const post = async (req, res) => { } // TODO: validate data try { - db.get(table) - .assign({ ...req.body }) - .write(); + data.event = { ...data.event, ...req.body }; + db.write(); + // data.event.push({ ...req.body }).write(); res.sendStatus(200); } catch (error) { res.status(400).send(error); + console.log(error); } }; // Create controller for GET request to 'event/title' // Returns ACK message export const titleGet = async (req, res) => { - const settings = getSettings(); - - if (settings) res.json(settings.title); - else res.sendStatus(400); + res.json(data.event.title); }; // Create controller for POST request to 'event/title' @@ -52,7 +42,7 @@ export const titlePost = async (req, res) => { // TODO: validate data try { - db.get(table).assign({ title: req.body.title }).write(); + data.event.assign({ title: req.body.title }).write(); res.sendStatus(200); } catch (error) { res.status(400).send(error); @@ -62,10 +52,7 @@ export const titlePost = async (req, res) => { // Create controller for GET request to '/event/url' // Returns ACK message export const urlGet = async (req, res) => { - const event = getSettings(); - - if (event) res.json(event.url); - else res.sendStatus(400); + res.json(data.event.url); }; // Create controller for POST request to '/event/url' @@ -78,7 +65,7 @@ export const urlPost = async (req, res) => { // TODO: validate data try { - db.get(table).assign({ url: req.body.url }).write(); + data.event.assign({ url: req.body.url }).write(); res.sendStatus(200); } catch (error) { res.status(400).send(error); @@ -88,10 +75,7 @@ export const urlPost = async (req, res) => { // Create controller for GET request to 'event/publicInfo' // Returns ACK message export const publicInfoGet = async (req, res) => { - const settings = getSettings(); - - if (settings) res.json(settings.publicInfo); - else res.sendStatus(400); + res.json(data.event.publicInfo); }; // Create controller for POST request to '/event/publicInfo' @@ -104,7 +88,7 @@ export const publicInfoPost = async (req, res) => { // TODO: validate data try { - db.get(table).assign({ publicInfo: req.body.publicInfo }).write(); + data.event.assign({ publicInfo: req.body.publicInfo }).write(); res.sendStatus(200); } catch (error) { res.status(400).send(error); @@ -114,10 +98,7 @@ export const publicInfoPost = async (req, res) => { // Create controller for GET request to 'event/backstageInfo' // Returns ACK message export const backstageInfoGet = async (req, res) => { - const settings = getSettings(); - - if (settings) res.json(settings.backstageInfo); - else res.sendStatus(400); + res.json(data.event.backstageInfo); }; // Create controller for POST request to '/event/info' @@ -130,7 +111,7 @@ export const backstageInfoPost = async (req, res) => { // TODO: validate data try { - db.get(table).assign({ backstageInfo: req.body.backstageInfo }).write(); + data.event.assign({ backstageInfo: req.body.backstageInfo }).write(); res.sendStatus(200); } catch (error) { res.status(400).send(error); diff --git a/server/data/dataModel.js b/server/data/dataModel.js index cbe964153..39e781b87 100644 --- a/server/data/dataModel.js +++ b/server/data/dataModel.js @@ -4,7 +4,7 @@ export const dbModel = { title: '', url: '', publicInfo: '', - backStageInfo: '', + backstageInfo: '', }, settings: { app: 'ontime', From 7406d5447295dd8b02ac551054facd9fab5b853a Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Mon, 24 May 2021 23:15:53 +0200 Subject: [PATCH 03/15] refract: delete unused code --- server/controllers/eventController.js | 105 +------------------------- server/routes/eventRouter.js | 45 ++--------- 2 files changed, 8 insertions(+), 142 deletions(-) diff --git a/server/controllers/eventController.js b/server/controllers/eventController.js index c003e4086..938e412b7 100644 --- a/server/controllers/eventController.js +++ b/server/controllers/eventController.js @@ -3,13 +3,13 @@ import { db, data } from '../app.js'; // Create controller for GET request to 'event' // Returns ACK message -export const getAll = async (req, res) => { +export const getEvent = async (req, res) => { res.json(data.event); }; // Create controller for POST request to 'event' // Returns ACK message -export const post = async (req, res) => { +export const postEvent = async (req, res) => { if (!req.body) { res.status(400).send('No object found in request'); return; @@ -17,109 +17,10 @@ export const post = async (req, res) => { // TODO: validate data try { data.event = { ...data.event, ...req.body }; - db.write(); - // data.event.push({ ...req.body }).write(); + await db.write(); res.sendStatus(200); } catch (error) { res.status(400).send(error); console.log(error); } }; - -// Create controller for GET request to 'event/title' -// Returns ACK message -export const titleGet = async (req, res) => { - res.json(data.event.title); -}; - -// Create controller for POST request to 'event/title' -// Returns ACK message -export const titlePost = async (req, res) => { - if (!req.body) { - res.status(400).send('No object found in request'); - return; - } - - // TODO: validate data - try { - data.event.assign({ title: req.body.title }).write(); - res.sendStatus(200); - } catch (error) { - res.status(400).send(error); - } -}; - -// Create controller for GET request to '/event/url' -// Returns ACK message -export const urlGet = async (req, res) => { - res.json(data.event.url); -}; - -// Create controller for POST request to '/event/url' -// Returns ACK message -export const urlPost = async (req, res) => { - if (!req.body) { - res.status(400).send('No object found in request'); - return; - } - - // TODO: validate data - try { - data.event.assign({ url: req.body.url }).write(); - res.sendStatus(200); - } catch (error) { - res.status(400).send(error); - } -}; - -// Create controller for GET request to 'event/publicInfo' -// Returns ACK message -export const publicInfoGet = async (req, res) => { - res.json(data.event.publicInfo); -}; - -// Create controller for POST request to '/event/publicInfo' -// Returns ACK message -export const publicInfoPost = async (req, res) => { - if (!req.body) { - res.status(400).send('No object found in request'); - return; - } - - // TODO: validate data - try { - data.event.assign({ publicInfo: req.body.publicInfo }).write(); - res.sendStatus(200); - } catch (error) { - res.status(400).send(error); - } -}; - -// Create controller for GET request to 'event/backstageInfo' -// Returns ACK message -export const backstageInfoGet = async (req, res) => { - res.json(data.event.backstageInfo); -}; - -// Create controller for POST request to '/event/info' -// Returns ACK message -export const backstageInfoPost = async (req, res) => { - if (!req.body) { - res.status(400).send('No object found in request'); - return; - } - - // TODO: validate data - try { - data.event.assign({ backstageInfo: req.body.backstageInfo }).write(); - res.sendStatus(200); - } catch (error) { - res.status(400).send(error); - } -}; - -// Create controller for GET request to 'event/osc' -// Returns ACK message -export const osc = async (req, res) => { - res.send('Not yet implemented').status(500); -}; diff --git a/server/routes/eventRouter.js b/server/routes/eventRouter.js index 99a6b5054..9b929f95d 100644 --- a/server/routes/eventRouter.js +++ b/server/routes/eventRouter.js @@ -2,45 +2,10 @@ import express from 'express'; export const router = express.Router(); // import event controller -import { - getAll, - post, - titleGet, - titlePost, - publicInfoGet, - publicInfoPost, - backstageInfoGet, - backstageInfoPost, - urlGet, - urlPost, -} from '../controllers/eventController.js'; +import { getEvent, postEvent } from '../controllers/eventController.js'; -// create route between controller and '/settings' endpoint -router.get('/', getAll); +// create route between controller and 'GET /event' endpoint +router.get('/', getEvent); -// create route between controller and '/settings' endpoint -router.post('/', post); - -// create route between controller and '/event/title' endpoint -router.get('/title', titleGet); - -// create route between controller and '/event/title' endpoint -router.post('/title', titlePost); - -// create route between controller and '/event/info' endpoint -router.get('/publicInfo', publicInfoGet); - -// create route between controller and '/event/info' endpoint -router.post('/publicInfo', publicInfoPost); - -// create route between controller and '/event/info' endpoint -router.get('/backstageInfo', backstageInfoGet); - -// create route between controller and '/event/info' endpoint -router.post('/backstageInfo', backstageInfoPost); - -// create route between controller and '/event/url' endpoint -router.get('/url', urlGet); - -// create route between controller and '/event/url' endpoint -router.post('/url', urlPost); +// create route between controller and 'POST /event' endpoint +router.post('/', postEvent); From 7fe3a28a7611da5b5734646a02168bbcdaddefc2 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Mon, 24 May 2021 23:16:19 +0200 Subject: [PATCH 04/15] migrate logic --- server/app.js | 4 +- server/controllers/eventsController.js | 67 +++++++++++++++----------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/server/app.js b/server/app.js index 8244342a3..034e11e90 100644 --- a/server/app.js +++ b/server/app.js @@ -18,7 +18,7 @@ await db.read(); // If file.json doesn't exist, db.data will be null // Set default data -// db.data ||= { events: [] }; +// db.data ||= { events: [] }; NODE v15 - v16 if (db.data == null) { db.data = dbModel; db.write(); @@ -73,7 +73,7 @@ const server = http.createServer(app); // init timer global.timer = new EventTimer(server, config); -global.timer.setupWithEventList(events); +global.timer.setupWithEventList(data.events); // Start server server.listen(port, () => diff --git a/server/controllers/eventsController.js b/server/controllers/eventsController.js index 4768eeb16..bbb2dcb51 100644 --- a/server/controllers/eventsController.js +++ b/server/controllers/eventsController.js @@ -1,26 +1,26 @@ // get database -import { db } from '../app.js'; +import { db, data } from '../app.js'; // utils import { customAlphabet } from 'nanoid'; const nanoid = customAlphabet('1234567890abcdef', 4); import { event as eventDef, + delay as delayDef, block as blockDef, - delay as delayDEf, } from '../data/eventsDefinition.js'; function _getEventsCount() { - return db.get('events').size().value(); + return Array.from(data.events).length; } function _pushNew(entry) { - return db.get('events').push(entry).write(); + return data.events.push(entry).write(); } -function _insertAt(entry, index) { +async function _insertAt(entry, index) { // get events - let events = db.get('events').value(); + let events = data.events; let count = events.length; let order = entry.order; @@ -43,15 +43,18 @@ function _insertAt(entry, index) { } // save events - db.set('events', events).write(); + data.events = events; + await db.write(); } -function _removeById(eventId) { - return db.get('events').remove({ id: eventId }).write(); +async function _removeById(eventId) { + data.events = Array.from(data.events).filter((e) => e.id != eventId); + await db.write(); } function getEventEvents() { - return db.get('events').chain().filter({ type: 'event' }).value(); + // return data.events.filter((e) => e.type === 'event'); + return Array.from(data.events).filter((e) => e.type === 'event'); } // Updates timer object @@ -73,14 +76,14 @@ function _deleteTimerId(entryId) { // Create controller for GET request to '/events' // Returns - export const eventsGetAll = async (req, res) => { - const results = db.get('events').value(); - res.json(results); + res.json(data.events); }; // Create controller for GET request to '/events/:eventId' // Returns - export const eventsGetById = async (req, res) => { - const e = db.get('events').find({ id: req.params.eventId }).value(); + const e = data.events.find({ id: req.params.eventId }).value(); + console.log('event by id', e); res.json(e); }; @@ -99,13 +102,13 @@ export const eventsPost = async (req, res) => { switch (req.body.type) { case 'event': - newEvent = { ...eventDefs.event, ...req.body }; + newEvent = { ...eventDef, ...req.body }; break; case 'delay': - newEvent = { ...eventDefs.delay, ...req.body }; + newEvent = { ...delayDef, ...req.body }; break; case 'block': - newEvent = { ...eventDefs.block, ...req.body }; + newEvent = { ...blockDef, ...req.body }; break; default: @@ -149,17 +152,23 @@ export const eventsPut = async (req, res) => { } try { - db.get('events') - .find({ id: req.body.id }) - .assign({ ...req.body }) - .update('revision', (n) => n + 1) - .write(); + const eventIndex = data.events.findIndex((e) => e.id === req.body.id); + if (eventIndex === -1) { + res.status(400).send(`No Id found found`); + return; + } + + const e = data.events[eventIndex]; + data.events[eventIndex] = { ...e, ...req.body }; + data.events[eventIndex].revision++; + db.write(); // update timer _updateTimersSingle(req.body.id, req.body); res.sendStatus(200); } catch (error) { + console.log(error); res.status(400).send(error); } }; @@ -168,7 +177,7 @@ export const eventsPut = async (req, res) => { // Returns - export const eventsPatch = async (req, res) => { // Code is the same as put, call that - this.eventsPut(req, res); + eventsPut(req, res); }; export const eventsReorder = async (req, res) => { @@ -181,7 +190,7 @@ export const eventsReorder = async (req, res) => { const { index, from, to } = req.body; // get events - let events = db.get('events').value(); + let events = data.events; let idx = events.findIndex((e) => e.id === index, from); // Check if item is at given index @@ -198,7 +207,8 @@ export const eventsReorder = async (req, res) => { events.splice(to, 0, reorderedItem); // save events - db.set('events', events).write(); + data.events = events; + db.write(); // TODO: would it be more efficient to reorder at timer? // update timer @@ -222,7 +232,7 @@ export const eventsApplyDelay = async (req, res) => { try { // get events - let events = db.get('events').value(); + let events = data.events; // AUX let delayIndex = null; @@ -263,7 +273,8 @@ export const eventsApplyDelay = async (req, res) => { if (blockIndex) events.splice(blockIndex - 1, 1); // update events - db.set('events', events).write(); + data.events = events; + db.write(); // update timer _updateTimers(); @@ -305,14 +316,14 @@ export const eventsDelete = async (req, res) => { export const eventsDeleteAll = async (req, res) => { try { // set with nothing - db.set('events', []).write(); + data.events = []; + db.write(); // update timer object _updateTimersSingle(); res.sendStatus(201); } catch (error) { - console.log('debug:', error); res.status(400).send(error); } }; From 250946fdc6a94d0fe879c71f643048b0f5d01567 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Tue, 25 May 2021 09:39:28 +0200 Subject: [PATCH 05/15] type module --- server/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/server/package.json b/server/package.json index 243cd0fa3..5597927f8 100644 --- a/server/package.json +++ b/server/package.json @@ -2,6 +2,7 @@ "name": "passport-example", "version": "0.0.1", "description": "Example with Passport (http://www.passportjs.org/)", + "type": "module", "dependencies": { "body-parser": "~1.19.0", "express": "~4.17.1", From b61a82627e8aeac13906df6dabf16424e7837a52 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Wed, 26 May 2021 23:10:00 +0200 Subject: [PATCH 06/15] feat: download - able to download file from express --- client/src/app/api/eventsApi.js | 15 +++++++++++++++ .../components/buttons/DownloadIconBtn.jsx | 18 ++++++++++++++++++ client/src/features/editors/Editor.jsx | 8 ++++++++ client/src/features/editors/Editor.module.css | 6 ++++++ server/controllers/ontimeController.js | 11 +++++++++++ server/routes/ontimeRouter.js | 5 +++++ 6 files changed, 63 insertions(+) create mode 100644 client/src/common/components/buttons/DownloadIconBtn.jsx create mode 100644 server/controllers/ontimeController.js create mode 100644 server/routes/ontimeRouter.js diff --git a/client/src/app/api/eventsApi.js b/client/src/app/api/eventsApi.js index 17a2ada40..a185a54be 100644 --- a/client/src/app/api/eventsApi.js +++ b/client/src/app/api/eventsApi.js @@ -1,6 +1,21 @@ import axios from 'axios'; import { eventsURL } from '../api/apiConstants'; +export const downloadEvents = async () => { + await axios({ + url: eventsURL + '/download', + method: 'GET', + responseType: 'blob', // important + }).then((response) => { + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', 'events.json'); + document.body.appendChild(link); + link.click(); + }); +}; + export const fetchAllEvents = async () => { const res = await axios.get(eventsURL); return res.data; diff --git a/client/src/common/components/buttons/DownloadIconBtn.jsx b/client/src/common/components/buttons/DownloadIconBtn.jsx new file mode 100644 index 000000000..8b30023b4 --- /dev/null +++ b/client/src/common/components/buttons/DownloadIconBtn.jsx @@ -0,0 +1,18 @@ +import { IconButton } from '@chakra-ui/button'; +import { FiDownload } from 'react-icons/fi'; + +export default function DownloadIconBtn(props) { + const { clickhandler, ...rest } = props; + return ( + } + isRound + variant='outline' + onClick={clickhandler} + _focus={{ boxShadow: 'none' }} + colorScheme='whiteAlpha' + {...rest} + /> + ); +} diff --git a/client/src/features/editors/Editor.jsx b/client/src/features/editors/Editor.jsx index bc727071b..c25a67f11 100644 --- a/client/src/features/editors/Editor.jsx +++ b/client/src/features/editors/Editor.jsx @@ -9,6 +9,8 @@ import { useDisclosure } from '@chakra-ui/hooks'; import SettingsModal from '../modals/SettingsModal'; import SettingsIconBtn from 'common/components/buttons/SettingsIconBtn'; import { useEffect } from 'react'; +import DownloadIconBtn from 'common/components/buttons/DownloadIconBtn'; +import { downloadEvents } from 'app/api/eventsApi'; export default function Editor() { const { isOpen, onOpen, onClose } = useDisclosure(); @@ -18,6 +20,11 @@ export default function Editor() { document.title = 'ontime - Editor'; }, []); + const handleDownload = () => { + console.log('debug download'); + downloadEvents(); + }; + return ( <> @@ -67,6 +74,7 @@ export default function Editor() {
+
diff --git a/client/src/features/editors/Editor.module.css b/client/src/features/editors/Editor.module.css index 3e20053c6..d29ab4a52 100644 --- a/client/src/features/editors/Editor.module.css +++ b/client/src/features/editors/Editor.module.css @@ -101,6 +101,12 @@ padding-top: 1.5em; } +.settings > .content { + display: flex; + flex-direction: column; + gap: 1em; +} + .cornerButtonContainer { position: relative; top: -4.5em; diff --git a/server/controllers/ontimeController.js b/server/controllers/ontimeController.js new file mode 100644 index 000000000..c7f3a55d2 --- /dev/null +++ b/server/controllers/ontimeController.js @@ -0,0 +1,11 @@ +// Create controller for GET request to '/ontime/download' +// Returns - +export const eventsDownload = async (req, res) => { + res.download('db.json', 'ontime events.json', (err) => { + if (err) { + res.status(500).send({ + message: 'Could not download the file. ' + err, + }); + } + }); +}; diff --git a/server/routes/ontimeRouter.js b/server/routes/ontimeRouter.js new file mode 100644 index 000000000..c45d1b3d7 --- /dev/null +++ b/server/routes/ontimeRouter.js @@ -0,0 +1,5 @@ +import express from 'express'; +export const router = express.Router(); + +// create route between controller and '/ontime/download' endpoint +router.get('/download', eventsDownload); From f887817a68592bc90c93ce1368c396e19d9bc825 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Thu, 27 May 2021 22:56:49 +0200 Subject: [PATCH 07/15] setup router + tidy up --- client/src/app/api/apiConstants.js | 1 + client/src/app/api/eventsApi.js | 15 --------------- client/src/app/api/ontimeApi.js | 17 +++++++++++++++++ server/app.js | 11 +++++++---- server/controllers/ontimeController.js | 9 +++++++-- server/routes/ontimeRouter.js | 6 ++++-- 6 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 client/src/app/api/ontimeApi.js diff --git a/client/src/app/api/apiConstants.js b/client/src/app/api/apiConstants.js index 33a92277f..ba1a35c67 100644 --- a/client/src/app/api/apiConstants.js +++ b/client/src/app/api/apiConstants.js @@ -10,3 +10,4 @@ export const serverURL = calculateServer(); export const eventURL = serverURL + EVENT_TABLE; export const eventsURL = serverURL + EVENTS_TABLE; export const playbackURL = serverURL + 'playback'; +export const ontimeURL = serverURL + 'ontime'; diff --git a/client/src/app/api/eventsApi.js b/client/src/app/api/eventsApi.js index a185a54be..17a2ada40 100644 --- a/client/src/app/api/eventsApi.js +++ b/client/src/app/api/eventsApi.js @@ -1,21 +1,6 @@ import axios from 'axios'; import { eventsURL } from '../api/apiConstants'; -export const downloadEvents = async () => { - await axios({ - url: eventsURL + '/download', - method: 'GET', - responseType: 'blob', // important - }).then((response) => { - const url = window.URL.createObjectURL(new Blob([response.data])); - const link = document.createElement('a'); - link.href = url; - link.setAttribute('download', 'events.json'); - document.body.appendChild(link); - link.click(); - }); -}; - export const fetchAllEvents = async () => { const res = await axios.get(eventsURL); return res.data; diff --git a/client/src/app/api/ontimeApi.js b/client/src/app/api/ontimeApi.js new file mode 100644 index 000000000..188981ddb --- /dev/null +++ b/client/src/app/api/ontimeApi.js @@ -0,0 +1,17 @@ +import axios from 'axios'; +import { ontimeURL } from './apiConstants'; + +export const downloadEvents = async () => { + await axios({ + url: ontimeURL + '/db', + method: 'GET', + responseType: 'blob', // important + }).then((response) => { + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', 'events.json'); + document.body.appendChild(link); + link.click(); + }); +}; diff --git a/server/app.js b/server/app.js index 034e11e90..c8e3bace4 100644 --- a/server/app.js +++ b/server/app.js @@ -11,6 +11,7 @@ export const db = new Low(adapter); import express from 'express'; import http from 'http'; import cors from 'cors'; +import multer from 'multer'; import { dbModel } from './data/dataModel.js'; // Read data from JSON file, this will set db.data content @@ -30,9 +31,7 @@ export const data = db.data; // Import Routes import { router as eventsRouter } from './routes/eventsRouter.js'; import { router as eventRouter } from './routes/eventRouter.js'; - -// No settings yet -// const settingsRouter = require('./routes/settingsRouter.js'); +import { router as ontimeRouter } from './routes/ontimeRouter.js'; // Setup default port const port = process.env.PORT || config.server.port; @@ -50,12 +49,16 @@ app.use(cors()); app.options('*', cors()); // Implement middleware +app.use(express.static('./public')); +app.use('/uploads', express.static('uploads')); + app.use(express.urlencoded({ extended: true })); -app.use(express.json()); +app.use(express.json({ limit: '1mb' })); // Implement route endpoints app.use('/events', eventsRouter); app.use('/event', eventRouter); +app.use('/ontime', ontimeRouter); // implement general router app.get('/', (req, res) => { diff --git a/server/controllers/ontimeController.js b/server/controllers/ontimeController.js index c7f3a55d2..4778e7e21 100644 --- a/server/controllers/ontimeController.js +++ b/server/controllers/ontimeController.js @@ -1,7 +1,12 @@ // Create controller for GET request to '/ontime/download' +import { db, data } from '../app.js'; +function getEventTitle() { + return data.event.title; +} // Returns - -export const eventsDownload = async (req, res) => { - res.download('db.json', 'ontime events.json', (err) => { +export const dbDownload = async (req, res) => { + const fileTitle = getEventTitle() || 'ontime events'; + res.download('db.json', `${fileTitle}.json`, (err) => { if (err) { res.status(500).send({ message: 'Could not download the file. ' + err, diff --git a/server/routes/ontimeRouter.js b/server/routes/ontimeRouter.js index c45d1b3d7..d07d9867f 100644 --- a/server/routes/ontimeRouter.js +++ b/server/routes/ontimeRouter.js @@ -1,5 +1,7 @@ import express from 'express'; export const router = express.Router(); -// create route between controller and '/ontime/download' endpoint -router.get('/download', eventsDownload); +import { dbDownload, dbUpload } from '../controllers/ontimeController.js'; + +// create route between controller and '/ontime/db' endpoint +router.get('/db', dbDownload); From e891e7a5385367c992097ab7748c6017c8a427fd Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Thu, 27 May 2021 23:00:32 +0200 Subject: [PATCH 08/15] feat: upload file --- client/src/app/api/ontimeApi.js | 14 +++ client/src/features/editors/Editor.jsx | 33 +++++- server/app.js | 2 - server/controllers/ontimeController.js | 60 +++++++++- server/package.json | 1 + server/routes/ontimeRouter.js | 4 + server/utils/upload.js | 23 ++++ server/yarn.lock | 147 ++++++++++++++++++++++++- 8 files changed, 272 insertions(+), 12 deletions(-) create mode 100644 server/utils/upload.js diff --git a/client/src/app/api/ontimeApi.js b/client/src/app/api/ontimeApi.js index 188981ddb..fa41a6bcf 100644 --- a/client/src/app/api/ontimeApi.js +++ b/client/src/app/api/ontimeApi.js @@ -15,3 +15,17 @@ export const downloadEvents = async () => { link.click(); }); }; + +export const uploadEvents = async (file) => { + console.log('uploading', file); + const formData = new FormData(); + formData.append('jsondb', file); // appending file + await axios + .post(ontimeURL + '/db', formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }) + .then((res) => console.log(res.data)) + .catch((err) => console.error(err)); +}; diff --git a/client/src/features/editors/Editor.jsx b/client/src/features/editors/Editor.jsx index c25a67f11..21b7a0a9c 100644 --- a/client/src/features/editors/Editor.jsx +++ b/client/src/features/editors/Editor.jsx @@ -8,12 +8,13 @@ import EventListWrapper from './list/EventListWrapper'; import { useDisclosure } from '@chakra-ui/hooks'; import SettingsModal from '../modals/SettingsModal'; import SettingsIconBtn from 'common/components/buttons/SettingsIconBtn'; -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import DownloadIconBtn from 'common/components/buttons/DownloadIconBtn'; -import { downloadEvents } from 'app/api/eventsApi'; +import { downloadEvents, uploadEvents } from 'app/api/ontimeApi'; export default function Editor() { const { isOpen, onOpen, onClose } = useDisclosure(); + const [file, setFile] = useState(null); // Set window title useEffect(() => { @@ -21,10 +22,22 @@ export default function Editor() { }, []); const handleDownload = () => { - console.log('debug download'); downloadEvents(); }; + const handleFile = (e) => { + setFile(e.target.files[0]); + }; + + const handleUpload = (e) => { + e.preventDefault(); + console.log('gonna upload', file); + + if (file && file.type === 'application/json') { + if (file.size < 1048576) uploadEvents(file); + } + }; + return ( <> @@ -68,7 +81,19 @@ export default function Editor() { Info -
+
+
+ + +
+
diff --git a/server/app.js b/server/app.js index c8e3bace4..6a1acc63e 100644 --- a/server/app.js +++ b/server/app.js @@ -11,7 +11,6 @@ export const db = new Low(adapter); import express from 'express'; import http from 'http'; import cors from 'cors'; -import multer from 'multer'; import { dbModel } from './data/dataModel.js'; // Read data from JSON file, this will set db.data content @@ -49,7 +48,6 @@ app.use(cors()); app.options('*', cors()); // Implement middleware -app.use(express.static('./public')); app.use('/uploads', express.static('uploads')); app.use(express.urlencoded({ extended: true })); diff --git a/server/controllers/ontimeController.js b/server/controllers/ontimeController.js index 4778e7e21..a87d9aebc 100644 --- a/server/controllers/ontimeController.js +++ b/server/controllers/ontimeController.js @@ -1,8 +1,30 @@ -// Create controller for GET request to '/ontime/download' +// get database import { db, data } from '../app.js'; +import fs from 'fs'; + function getEventTitle() { return data.event.title; } + +async function deleteFile(file) { + // delete a file + fs.unlink(file, (err) => { + if (err) { + console.log(err); + } + }); +} + +// parses version 1 of the data system +async function parsev1(jsonData) { + // loop through events + // doublecheck unique ids + // merge to an event definition + // merge event info + // merge settings +} + +// Create controller for GET request to '/ontime/db' // Returns - export const dbDownload = async (req, res) => { const fileTitle = getEventTitle() || 'ontime events'; @@ -14,3 +36,39 @@ export const dbDownload = async (req, res) => { } }); }; + +// Create controller for POST request to '/ontime/db' +// Returns - +export const dbUpload = async (req, res) => { + if (!req.file) { + res.status(400).send({ message: 'File not found' }); + return; + } + + const file = req.file.path; + if (!fs.existsSync(file)) { + res.status(500).send({ message: 'Upload failed' }); + return; + } + + try { + // get file + let rawdata = fs.readFileSync(file); + let uploadedJson = JSON.parse(rawdata); + + // delete file + deleteFile(file); + + // check version + if (uploadedJson.settings.version === 1) parsev1(uploadedJson); + else { + res.status(400).send({ message: 'Error parsing file, version unknown' }); + return; + } + + res.sendStatus(200); + } catch (error) { + console.log('Error parsing file', error); + res.status(400).send({ message: error }); + } +}; diff --git a/server/package.json b/server/package.json index 5597927f8..fbe1ad4ae 100644 --- a/server/package.json +++ b/server/package.json @@ -8,6 +8,7 @@ "express": "~4.17.1", "express-session": "~1.17.1", "lowdb": "2.1.0", + "multer": "^1.4.2", "nanoid": "^3.1.22", "node-osc": "^6.0.1", "passport": "~0.4.1", diff --git a/server/routes/ontimeRouter.js b/server/routes/ontimeRouter.js index d07d9867f..e5b5e5670 100644 --- a/server/routes/ontimeRouter.js +++ b/server/routes/ontimeRouter.js @@ -1,7 +1,11 @@ import express from 'express'; +import uploadJson from '../utils/upload.js'; export const router = express.Router(); import { dbDownload, dbUpload } from '../controllers/ontimeController.js'; // create route between controller and '/ontime/db' endpoint router.get('/db', dbDownload); + +// create route between controller and '/ontime/db' endpoint +router.post('/db', uploadJson, dbUpload); diff --git a/server/utils/upload.js b/server/utils/upload.js new file mode 100644 index 000000000..f53a492c0 --- /dev/null +++ b/server/utils/upload.js @@ -0,0 +1,23 @@ +import multer from 'multer'; + +const storage = multer.diskStorage({ + destination: function (req, file, cb) { + cb(null, './uploads'); + }, + filename: function (req, file, cb) { + cb(null, Date.now() + '--' + file.originalname); + }, +}); + +// filter only json +const filterJson = (req, file, cb) => { + if (file.mimetype.includes('application/json')) { + cb(null, true); + } else { + cb(null, false); + } +}; + +const uploadJson = multer({ storage: storage, fileFilter: filterJson }); + +export default uploadJson.single('jsondb'); diff --git a/server/yarn.lock b/server/yarn.lock index 7ef514f68..2e29b0705 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -30,6 +30,11 @@ accepts@~1.3.4, accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" +append-field@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" + integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY= + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -66,6 +71,19 @@ body-parser@1.19.0, body-parser@~1.19.0: raw-body "2.4.0" type-is "~1.6.17" +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +busboy@^0.2.11: + version "0.2.14" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" + integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM= + dependencies: + dicer "0.2.5" + readable-stream "1.1.x" + bytes@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -76,6 +94,16 @@ component-emitter@~1.3.0: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +concat-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -103,6 +131,11 @@ cookie@~0.4.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + cors@~2.8.5: version "2.8.5" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" @@ -140,6 +173,14 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +dicer@0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" + integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8= + dependencies: + readable-stream "1.1.x" + streamsearch "0.1.2" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -287,7 +328,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -inherits@2.0.4: +inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -297,6 +338,16 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + lowdb@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/lowdb/-/lowdb-2.1.0.tgz#c8063e228b5ab3e082ece90e0512537ecb6e1e2a" @@ -336,6 +387,18 @@ mime@1.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -351,6 +414,20 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +multer@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a" + integrity sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg== + dependencies: + append-field "^1.0.0" + busboy "^0.2.11" + concat-stream "^1.5.2" + mkdirp "^0.5.1" + object-assign "^4.1.1" + on-finished "^2.3.0" + type-is "^1.6.4" + xtend "^4.0.0" + nanoid@^3.1.22: version "3.1.22" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.22.tgz#b35f8fb7d151990a8aebd5aa5015c03cf726f844" @@ -368,12 +445,12 @@ node-osc@^6.0.1: dependencies: osc-min "^1.1.1" -object-assign@^4: +object-assign@^4, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -on-finished@~2.3.0: +on-finished@^2.3.0, on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= @@ -427,6 +504,11 @@ pause@0.0.1: resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" integrity sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10= +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + proxy-addr@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" @@ -460,7 +542,30 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -safe-buffer@5.1.2: +readable-stream@1.1.x: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.2.2: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -548,12 +653,29 @@ steno@^1.0.0: resolved "https://registry.yarnpkg.com/steno/-/steno-1.0.0.tgz#475e32c6066ec9760229eaaf1550601764fbecba" integrity sha512-C/KgCvEa1yWnpHmaPjAXrz1yWxh6hs+HvhqqPa71euaQmNi1wr4+WFo57VQxjKKuFl2KqS7gtlrN0oxj2noQLw== +streamsearch@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" + integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + toidentifier@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== -type-is@~1.6.17, type-is@~1.6.18: +type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== @@ -561,6 +683,11 @@ type-is@~1.6.17, type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + uid-safe@~2.1.5: version "2.1.5" resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a" @@ -573,6 +700,11 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -587,3 +719,8 @@ ws@~7.4.2: version "7.4.4" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.4.tgz#383bc9742cb202292c9077ceab6f6047b17f2d59" integrity sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw== + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== From 1491fbbb97e60fa9cdae7c4a8148c67d5f7a503c Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Fri, 28 May 2021 00:02:31 +0200 Subject: [PATCH 09/15] parse uploaded file --- server/controllers/ontimeController.js | 64 ++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/server/controllers/ontimeController.js b/server/controllers/ontimeController.js index a87d9aebc..7dabf952e 100644 --- a/server/controllers/ontimeController.js +++ b/server/controllers/ontimeController.js @@ -1,6 +1,12 @@ // get database import { db, data } from '../app.js'; import fs from 'fs'; +import { + event as eventDef, + delay as delayDef, + block as blockDef, +} from '../data/eventsDefinition.js'; +import { dbModel } from '../data/dataModel.js'; function getEventTitle() { return data.event.title; @@ -17,11 +23,59 @@ async function deleteFile(file) { // parses version 1 of the data system async function parsev1(jsonData) { - // loop through events - // doublecheck unique ids - // merge to an event definition - // merge event info - // merge settings + if ('events' in jsonData) { + let events = []; + let ids = []; + for (const e of jsonData.events) { + if (e.type === 'event') { + // doublecheck unique ids + if (e.id == null || ids.indexOf(e.id) !== -1) continue; + ids.push(e.id); + + // make sure all properties exits + // dont load any extra properties than the ones known + events.push({ + ...eventDef, + title: e.title, + subtitle: e.subtitle, + presenter: e.presenter, + note: e.note, + timeStart: e.timeStart, + timeEnd: e.timeEnd, + isPublic: e.isPublic, + id: e.id, + }); + } else if (e.type === 'delay') { + events.push({ ...delayDef, duration: e.duration }); + } else if (e.type === 'block') { + events.push({ ...blockDef }); + } + } + // write to db + db.data.events = events; + db.write(); + } + + if ('event' in jsonData) { + const e = jsonData.event; + // filter known properties + const event = { + ...dbModel.event, + title: e.title, + url: e.url, + publicInfo: e.publicInfo, + backstageInfo: e.backstageInfo, + }; + console.log(event); + // write to db + db.data.event = event; + db.write(); + } + + // Not handling settings yet + // let settings = {}; + // if ('settings' in jsonData) { + // } } // Create controller for GET request to '/ontime/db' From aa53f2c9cfa381de3e8f2d25d863688fc4c45f76 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Fri, 28 May 2021 13:16:34 +0200 Subject: [PATCH 10/15] folder restructure --- server/data/eventsData.json | 57 ------------------- server/jsconfig.json | 3 + server/{ => src}/app.js | 2 +- server/{ => src}/classes/EventTimer.js | 0 server/{ => src}/classes/Timer.js | 0 server/{ => src/config}/config.js | 0 server/{ => src}/controllers/OscController.js | 0 .../{ => src}/controllers/eventController.js | 0 .../{ => src}/controllers/eventsController.js | 0 .../{ => src}/controllers/ontimeController.js | 2 +- .../controllers/playbackController.js | 22 +++---- server/{ => src}/data/dataModel.js | 0 server/{ => src}/data/eventsDefinition.js | 0 server/{ => src}/routes/eventRouter.js | 0 server/{ => src}/routes/eventsRouter.js | 0 server/{ => src}/routes/ontimeRouter.js | 0 server/{ => src}/routes/playbackRouter.js | 0 server/{ => src}/utils/upload.js | 2 +- 18 files changed, 17 insertions(+), 71 deletions(-) delete mode 100644 server/data/eventsData.json create mode 100644 server/jsconfig.json rename server/{ => src}/app.js (97%) rename server/{ => src}/classes/EventTimer.js (100%) rename server/{ => src}/classes/Timer.js (100%) rename server/{ => src/config}/config.js (100%) rename server/{ => src}/controllers/OscController.js (100%) rename server/{ => src}/controllers/eventController.js (100%) rename server/{ => src}/controllers/eventsController.js (100%) rename server/{ => src}/controllers/ontimeController.js (99%) rename server/{ => src}/controllers/playbackController.js (71%) rename server/{ => src}/data/dataModel.js (100%) rename server/{ => src}/data/eventsDefinition.js (100%) rename server/{ => src}/routes/eventRouter.js (100%) rename server/{ => src}/routes/eventsRouter.js (100%) rename server/{ => src}/routes/ontimeRouter.js (100%) rename server/{ => src}/routes/playbackRouter.js (100%) rename server/{ => src}/utils/upload.js (94%) diff --git a/server/data/eventsData.json b/server/data/eventsData.json deleted file mode 100644 index f5aadad75..000000000 --- a/server/data/eventsData.json +++ /dev/null @@ -1,57 +0,0 @@ -[ - { - "id":"xxxxx0", - "duration": 300000, - "type": "delay" - }, - { - "id":"xxxxx1", - "title": "Is the internet a fad?", - "subtitle": "It is", - "presenter": "Carlos Valente", - "timeStart": 32400000, - "timeEnd": 34200000, - "type": "event" - }, - { - "id":"xxxxx2", - "duration": 1500000, - "type": "delay" - }, - { - "id":"xxxxx3", - "title": "Is reddit a dictatorship?", - "subtitle": "It is", - "presenter": "Carlos Valente", - "timeStart": 34200000, - "timeEnd": 36000000, - "type": "event" - }, - { - "id":"xxxxx4", - "title": "Out of words", - "subtitle": "", - "presenter": "Carlos Valente", - "timeStart": 36000000, - "timeEnd": 39600000, - "type": "event" - }, - { - "id":"xxxxx5", - "title": "Really", - "subtitle": "", - "presenter": "Carlos Valente", - "timeStart": 39600000, - "timeEnd": 41400000, - "type": "event" - }, - { - "id":"xxxxx6", - "title": "...", - "subtitle": "", - "presenter": "Carlos Valente", - "timeStart": null, - "timeEnd": null, - "type": "event" - } -] \ No newline at end of file diff --git a/server/jsconfig.json b/server/jsconfig.json new file mode 100644 index 000000000..bbf408cd7 --- /dev/null +++ b/server/jsconfig.json @@ -0,0 +1,3 @@ +{ + "exclude": ["node_modules", "dist"] +} diff --git a/server/app.js b/server/src/app.js similarity index 97% rename from server/app.js rename to server/src/app.js index 6a1acc63e..a7882c50d 100644 --- a/server/app.js +++ b/server/src/app.js @@ -1,5 +1,5 @@ // get config -import { config } from './config.js'; +import { config } from './config/config.js'; // init database import { Low, JSONFile } from 'lowdb'; diff --git a/server/classes/EventTimer.js b/server/src/classes/EventTimer.js similarity index 100% rename from server/classes/EventTimer.js rename to server/src/classes/EventTimer.js diff --git a/server/classes/Timer.js b/server/src/classes/Timer.js similarity index 100% rename from server/classes/Timer.js rename to server/src/classes/Timer.js diff --git a/server/config.js b/server/src/config/config.js similarity index 100% rename from server/config.js rename to server/src/config/config.js diff --git a/server/controllers/OscController.js b/server/src/controllers/OscController.js similarity index 100% rename from server/controllers/OscController.js rename to server/src/controllers/OscController.js diff --git a/server/controllers/eventController.js b/server/src/controllers/eventController.js similarity index 100% rename from server/controllers/eventController.js rename to server/src/controllers/eventController.js diff --git a/server/controllers/eventsController.js b/server/src/controllers/eventsController.js similarity index 100% rename from server/controllers/eventsController.js rename to server/src/controllers/eventsController.js diff --git a/server/controllers/ontimeController.js b/server/src/controllers/ontimeController.js similarity index 99% rename from server/controllers/ontimeController.js rename to server/src/controllers/ontimeController.js index 7dabf952e..2d74bb73f 100644 --- a/server/controllers/ontimeController.js +++ b/server/src/controllers/ontimeController.js @@ -66,7 +66,7 @@ async function parsev1(jsonData) { publicInfo: e.publicInfo, backstageInfo: e.backstageInfo, }; - console.log(event); + // write to db db.data.event = event; db.write(); diff --git a/server/controllers/playbackController.js b/server/src/controllers/playbackController.js similarity index 71% rename from server/controllers/playbackController.js rename to server/src/controllers/playbackController.js index 4dcc45cb3..b8a72f5a5 100644 --- a/server/controllers/playbackController.js +++ b/server/src/controllers/playbackController.js @@ -1,64 +1,64 @@ // Create controller for GET request to '/playback' // Returns ACK message -exports.pbGet = async (req, res) => { +export const pbGet = async (req, res) => { res.send(global.timer.playState); }; // Create controller for GET request to '/playback/start' // Starts timer object -exports.pbStart = async (req, res) => { +export const pbStart = async (req, res) => { global.timer.start(); res.sendStatus(200); }; // Create controller for GET request to '/playback/pause' // Pauses timer object -exports.pbPause = async (req, res) => { +export const pbPause = async (req, res) => { global.timer.pause(); res.sendStatus(200); }; // Create controller for GET request to '/playback/stop' // Stops timer object -exports.pbStop = async (req, res) => { +export const pbStop = async (req, res) => { global.timer.stop(); res.sendStatus(200); }; // Create controller for GET request to '/playback/roll' // Sets timer object to roll mode -exports.pbRoll = async (req, res) => { +export const pbRoll = async (req, res) => { global.timer.roll(); res.sendStatus(501); }; // Create controller for GET request to '/playback/previous' // Sets timer object to roll mode -exports.pbPrevious = async (req, res) => { +export const pbPrevious = async (req, res) => { global.timer.previous(); res.sendStatus(200); }; // Create controller for GET request to '/playback/next' // Sets timer object to roll mode -exports.pbNext = async (req, res) => { +export const pbNext = async (req, res) => { global.timer.next(); res.sendStatus(200); }; // Create controller for GET request to '/playback/unload' // Unloads any events -exports.pbUnload = async (req, res) => { +export const pbUnload = async (req, res) => { global.timer.unload(); - console.log('debug: unload called') + console.log('debug: unload called'); res.sendStatus(200); }; // Create controller for GET request to '/playback/reload' // Reloads current event -exports.pbReload = async (req, res) => { +export const pbReload = async (req, res) => { global.timer.reload(); - console.log('debug: reload called') + console.log('debug: reload called'); res.sendStatus(200); }; diff --git a/server/data/dataModel.js b/server/src/data/dataModel.js similarity index 100% rename from server/data/dataModel.js rename to server/src/data/dataModel.js diff --git a/server/data/eventsDefinition.js b/server/src/data/eventsDefinition.js similarity index 100% rename from server/data/eventsDefinition.js rename to server/src/data/eventsDefinition.js diff --git a/server/routes/eventRouter.js b/server/src/routes/eventRouter.js similarity index 100% rename from server/routes/eventRouter.js rename to server/src/routes/eventRouter.js diff --git a/server/routes/eventsRouter.js b/server/src/routes/eventsRouter.js similarity index 100% rename from server/routes/eventsRouter.js rename to server/src/routes/eventsRouter.js diff --git a/server/routes/ontimeRouter.js b/server/src/routes/ontimeRouter.js similarity index 100% rename from server/routes/ontimeRouter.js rename to server/src/routes/ontimeRouter.js diff --git a/server/routes/playbackRouter.js b/server/src/routes/playbackRouter.js similarity index 100% rename from server/routes/playbackRouter.js rename to server/src/routes/playbackRouter.js diff --git a/server/utils/upload.js b/server/src/utils/upload.js similarity index 94% rename from server/utils/upload.js rename to server/src/utils/upload.js index f53a492c0..e489ac26f 100644 --- a/server/utils/upload.js +++ b/server/src/utils/upload.js @@ -2,7 +2,7 @@ import multer from 'multer'; const storage = multer.diskStorage({ destination: function (req, file, cb) { - cb(null, './uploads'); + cb(null, 'uploads/'); }, filename: function (req, file, cb) { cb(null, Date.now() + '--' + file.originalname); From 3c436007de4b1741810b44d22e98be8189c14856 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Fri, 28 May 2021 13:18:03 +0200 Subject: [PATCH 11/15] cleanup - removing upload for now, should go somewhere else --- client/src/features/editors/Editor.jsx | 32 +++----------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/client/src/features/editors/Editor.jsx b/client/src/features/editors/Editor.jsx index 21b7a0a9c..586f2bd2e 100644 --- a/client/src/features/editors/Editor.jsx +++ b/client/src/features/editors/Editor.jsx @@ -8,13 +8,12 @@ import EventListWrapper from './list/EventListWrapper'; import { useDisclosure } from '@chakra-ui/hooks'; import SettingsModal from '../modals/SettingsModal'; import SettingsIconBtn from 'common/components/buttons/SettingsIconBtn'; -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; import DownloadIconBtn from 'common/components/buttons/DownloadIconBtn'; -import { downloadEvents, uploadEvents } from 'app/api/ontimeApi'; +import { downloadEvents } from 'app/api/ontimeApi'; export default function Editor() { const { isOpen, onOpen, onClose } = useDisclosure(); - const [file, setFile] = useState(null); // Set window title useEffect(() => { @@ -25,19 +24,6 @@ export default function Editor() { downloadEvents(); }; - const handleFile = (e) => { - setFile(e.target.files[0]); - }; - - const handleUpload = (e) => { - e.preventDefault(); - console.log('gonna upload', file); - - if (file && file.type === 'application/json') { - if (file.size < 1048576) uploadEvents(file); - } - }; - return ( <> @@ -81,19 +67,7 @@ export default function Editor() { Info -
-
- - -
-
+
From 59341669061ce598c03d2d3ca11efc3a01a9ceca Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Fri, 28 May 2021 13:51:34 +0200 Subject: [PATCH 12/15] get name from header - attempt getting name from header. will depend on security policies --- client/src/app/api/ontimeApi.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/client/src/app/api/ontimeApi.js b/client/src/app/api/ontimeApi.js index fa41a6bcf..4ebc5f73b 100644 --- a/client/src/app/api/ontimeApi.js +++ b/client/src/app/api/ontimeApi.js @@ -7,10 +7,21 @@ export const downloadEvents = async () => { method: 'GET', responseType: 'blob', // important }).then((response) => { + let headerLine = response.headers['Content-Disposition']; + console.log(response); + let filename = 'events.json'; + + // try and get the filename from the response + if (headerLine != null) { + let startFileNameIndex = headerLine.indexOf('"') + 1; + let endFileNameIndex = headerLine.lastIndexOf('"'); + filename = headerLine.substring(startFileNameIndex, endFileNameIndex); + } + const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; - link.setAttribute('download', 'events.json'); + link.setAttribute('download', filename); document.body.appendChild(link); link.click(); }); From a47dfea56b225ae0268439a7d0bb9ecca5f3ea1f Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Fri, 28 May 2021 14:00:13 +0200 Subject: [PATCH 13/15] refract: tidy up structure - db in folder --- .gitignore | 2 +- server/src/app.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index caa6f98fa..d771a4658 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,4 @@ yarn.lock package.json package-lock.json db.json -server/db backup.json +db backup.json diff --git a/server/src/app.js b/server/src/app.js index a7882c50d..e6d4dd214 100644 --- a/server/src/app.js +++ b/server/src/app.js @@ -3,8 +3,10 @@ import { config } from './config/config.js'; // init database import { Low, JSONFile } from 'lowdb'; +import { join } from 'path'; -const adapter = new JSONFile(config.database.filename); +const file = join('data/', config.database.filename); +const adapter = new JSONFile(file); export const db = new Low(adapter); // dependencies From 0d78038797ca8883c12833be3f667e77dc5ee85f Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Fri, 28 May 2021 14:22:40 +0200 Subject: [PATCH 14/15] Update package.json - yarn start correct file --- server/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/package.json b/server/package.json index fbe1ad4ae..2b399881d 100644 --- a/server/package.json +++ b/server/package.json @@ -16,6 +16,6 @@ "socket.io": "^4.0.0" }, "scripts": { - "start": "node app.js" + "start": "node src/app.js" } } From 8624e2c383c9ac79f3606eacc444cc1986622f86 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Fri, 28 May 2021 14:56:00 +0200 Subject: [PATCH 15/15] add data folder --- server/data/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 server/data/.gitkeep diff --git a/server/data/.gitkeep b/server/data/.gitkeep new file mode 100644 index 000000000..e69de29bb