diff --git a/.env.DEV b/.env.DEV index 401cc7e..f0eb2cb 100644 --- a/.env.DEV +++ b/.env.DEV @@ -9,3 +9,4 @@ USE_CDN= API_KEY='example-application-id' API_SECRET='example-secret' COOKIE_SECRET='b8f6959746b617d9c9e90ce4a4b6e0' +WCIF_DATA_FOLDER=wcif_data diff --git a/.gitignore b/.gitignore index 8f5c99a..250d4ab 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ google-credentials.json .env.* !.env.DEV .wcif_cache +wcif_data # Logs logs diff --git a/README.md b/README.md index c651743..42b397b 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ Node must be installed on your machine. ``` $ npm install -$ ENV=DEV npx nodemon . +$ npm run dev-server ``` -`ENV=DEV` uses a dev WCA environment running on the same machine. If you would like to use the production WCA site, you need to: +Running the development server will use uses a dev WCA environment running on the same machine. If you would like to use the production WCA site, you need to: 1. Make an OAuth application [here](https://www.worldcubeassociation.org/oauth/applications). For "Scopes", use `public manage_competitions`; for "Callback Urls" use `http://localhost:3033/auth/oauth_response`. 2. Make a copy of the `.env.DEV` file, such as `.env.PROD`. This file should not be committed; `.gitignore` should automatically ignore it. diff --git a/functions/functions.js b/functions/functions.js index 1b0d44d..27a5abd 100644 --- a/functions/functions.js +++ b/functions/functions.js @@ -17,5 +17,6 @@ module.exports = { require('./tuple').functions, require('./udf').functions, require('./util').functions, + require('./wcif').functions, ) } diff --git a/functions/wcif.js b/functions/wcif.js new file mode 100644 index 0000000..7b957fc --- /dev/null +++ b/functions/wcif.js @@ -0,0 +1,96 @@ +const fs = require('fs') +const fse = require('fs-extra') + +const ClearWCIF = { + name: 'ClearWCIF', + docs: 'Remove all childActivities keeping only the main schedule, remove all assignments, cleanup roles, cleanup NatsHelper extension data.', + args: [ + { + name: 'clearExternalExtensions', + type: 'Boolean', + docs: 'Also cleanup external tools extensions.', + defaultValue: false, + }, + ], + outputType: 'Void', + usesContext: true, + mutations: ['schedule', 'persons'], + implementation: (ctx, clearExternalExtensions) => { + const cleanupExtensions = (object) => { + if (clearExternalExtensions) { + object.extensions = [] + } else { + object.extensions = object.extensions.filter(({ id }) => !id.startsWith("org.cubingusa.natshelper")) + } + } + cleanupExtensions(competition) + ctx.competition.persons.forEach((person) => { + // Cleanup roles which are user-defined. + const immutableRoles = ['delegate', 'organizer', 'trainee-delegate'] + person.roles = person.roles.filter((r) => immutableRoles.includes(r)) + person.assignments = [] + cleanupExtensions(person) + }) + ctx.competition.schedule.venues.forEach((venue) => { + venue.rooms.forEach((room) => { + cleanupExtensions(room) + room.activities.forEach((activity) => { + cleanupExtensions(activity) + activity.childActivities = [] + }) + }) + }) + } +} + +const ImportWCIF = { + name: 'ImportWCIF', + docs: 'Import the WCIF from a json file', + args: [ + { + name: 'filename', + type: 'String', + docs: 'WCIF filename (relative to WCIF_DATA_FOLDER/competitionId)', + }, + ], + outputType: 'String', + usesContext: true, + implementation: (ctx, filename) => { + var fullPath = `${process.env.WCIF_DATA_FOLDER || '.'}/${ctx.competition.id}/${filename}` + var wcif = JSON.parse(fs.readFileSync(fullPath)) + if (wcif.id !== ctx.competition.id) { + throw new Error(`The WCIF is not for the correct competition (expected "${ctx.competition.id}", but got "${wcif.id})"`) + } + ctx.competition = wcif + return `Imported WCIF from '${fullPath}'.` + } +} + +const ExportWCIF = { + name: 'ExportWCIF', + docs: 'Export the WCIF to a json file', + args: [ + { + name: 'filename', + type: 'String', + docs: 'WCIF filename (emitted in WCIF_DATA_FOLDER/competitionId)', + defaultValue: 'wcif.json', + }, + ], + outputType: 'String', + usesContext: true, + implementation: (ctx, filename) => { + var folder = `${process.env.WCIF_DATA_FOLDER || '.'}/${ctx.competition.id}`; + var fullPath = `${folder}/${filename}` + fse.ensureDirSync(folder) + fs.writeFileSync( + fullPath, + JSON.stringify(ctx.competition, null, 2) + ) + return `WCIF saved to '${fullPath}'.` + } +} + +module.exports = { + functions: [ClearWCIF, ExportWCIF, ImportWCIF], +} diff --git a/package.json b/package.json index 466bc10..7476a54 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "version": "1.0.0", "main": "main.js", "scripts": { + "dev-server": "ENV=DEV npx nodemon -i wcif_data .", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { diff --git a/wcif_data/.keep b/wcif_data/.keep new file mode 100644 index 0000000..e69de29