diff --git a/.gitignore b/.gitignore index 9c993d020..419b7b442 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules frontend/node_modules frontend/dist .nyc_output -coverage/ \ No newline at end of file +coverage/ +.env \ No newline at end of file diff --git a/app.js b/app.js index 574585f45..487e62b00 100644 --- a/app.js +++ b/app.js @@ -1,5 +1,6 @@ 'use strict' + let http = require( 'http' ) const express = require( 'express' ) const root = require( 'app-root-path' ) @@ -8,11 +9,11 @@ const bodyParser = require( 'body-parser' ) const debug = require( 'debug' )( 'speckle:generic' ) const { ApolloServer } = require( 'apollo-server-express' ) +require( 'dotenv' ).config( { path: `${root}/.env` } ) + const { contextApiTokenHelper } = require( './modules/shared' ) const knex = require( './db/knex' ) -require( 'dotenv' ).config( { path: `${root}/.env` } ) - /** * Initialises the express application together with the graphql server middleware. @@ -31,10 +32,6 @@ exports.init = async ( ) => { app.use( bodyParser.json( ) ) app.use( bodyParser.urlencoded( { extended: false } ) ) - // app.get( '/', ( req, res ) => { - // res.send( { fantastic: 'speckle' } ) - // } ) - const { init, graph } = require( './modules' ) // Initialise default modules, including rest api handlers @@ -61,17 +58,24 @@ exports.startHttp = async ( app ) => { let port = process.env.PORT || 3000 app.set( 'port', port ) + let setupComplete = await require( `${root}/setupcheck` )( ) + debug( `Setup is ${setupComplete ? '' : 'not'} complete. Serving ${setupComplete ? 'main app' : 'setup app'}` ) app.use( '/', express.static( `${root}/frontend/dist` ) ) - app.all( '*', ( req, res ) => { try { - res.sendFile( `${root}/frontend/dist/index.html` ); + if ( setupComplete ) { + res.sendFile( `${root}/frontend/dist/app.html` ) + } else { + res.sendFile( `${root}/frontend/dist/setup.html` ) + } } catch ( error ) { - res.json( { success: false, message: "Something went wrong" } ); + res.json( { success: false, message: "Something went wrong" } ) } } ); + + let server = http.createServer( app ) server.on( 'listening', ( ) => { diff --git a/config.js b/config.js deleted file mode 100644 index 963000b18..000000000 --- a/config.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict' - -require( 'dotenv' ).config( { path: `${root}/.env` } ) - -module.exports = { - -} \ No newline at end of file diff --git a/frontend/README.md b/frontend/README.md index 605158183..af49eb89a 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,4 +1,8 @@ -# frontend +# The Speckle Frontend Apps + +This is a vue MPA. It consists of two separate apps: +- the setup app +- the main frontend app ## Project setup ``` @@ -10,6 +14,11 @@ npm install npm run serve ``` +In dev mode, the two separate apps will be available from `localhost:8080/app` for the main frontend, and from `localhost:8080/setup`. + +After building, the server, in production mode, switches between the two based on wether the setup is complete. + + ### Compiles and minifies for production ``` npm run build diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4a260ec1d..0247d5202 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1121,6 +1121,14 @@ "@types/node": "*" } }, + "@types/http-proxy": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.4.tgz", + "integrity": "sha512-IrSHl2u6AWXduUaDLqYpt45tLVCtYv7o4Z0s1KghBCDgIIS9oW5K1H8mZG/A2CfeLdEa7rTd1ACOiHBc1EMT2Q==", + "requires": { + "@types/node": "*" + } + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -1130,8 +1138,7 @@ "@types/node": { "version": "14.0.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.5.tgz", - "integrity": "sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==", - "dev": true + "integrity": "sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==" }, "@types/normalize-package-data": { "version": "2.4.0", @@ -4355,8 +4362,7 @@ "eventemitter3": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", - "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", - "dev": true + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" }, "events": { "version": "3.1.0", @@ -4783,7 +4789,6 @@ "version": "1.11.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz", "integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==", - "dev": true, "requires": { "debug": "^3.0.0" }, @@ -4792,7 +4797,6 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, "requires": { "ms": "^2.1.1" } @@ -5386,7 +5390,6 @@ "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, "requires": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -5394,15 +5397,55 @@ } }, "http-proxy-middleware": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", - "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", - "dev": true, + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-1.0.4.tgz", + "integrity": "sha512-8wiqujNWlsZNbeTSSWMLUl/u70xbJ5VYRwPR8RcAbvsNxzAZbgwLzRvT96btbm3fAitZUmo5i8LY6WKGyHDgvA==", "requires": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" + "@types/http-proxy": "^1.17.4", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "micromatch": "^4.0.2" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + } } }, "http-signature": { @@ -5736,8 +5779,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { "version": "2.0.0", @@ -5749,7 +5791,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -6129,8 +6170,7 @@ "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, "lodash.defaultsdeep": { "version": "4.6.1", @@ -6545,8 +6585,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multicast-dns": { "version": "6.2.3", @@ -7178,8 +7217,7 @@ "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, "pify": { "version": "4.0.1", @@ -8377,8 +8415,7 @@ "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "resolve": { "version": "1.17.0", @@ -10498,6 +10535,18 @@ } } }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, "is-absolute-url": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index c22dfe1a2..610aaa6fa 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -4,10 +4,13 @@ "private": true, "scripts": { "serve": "vue-cli-service serve", - "build": "vue-cli-service build" + "build": "vue-cli-service build", + "serve:setup": "vue-cli-service serve", + "build:setup": "vue-cli-service build" }, "dependencies": { "core-js": "^3.6.4", + "http-proxy-middleware": "^1.0.4", "vue": "^2.6.11", "vue-router": "^3.1.6", "vuetify": "^2.2.11", diff --git a/frontend/src/App.vue b/frontend/src/App.vue deleted file mode 100644 index 80e5e6743..000000000 --- a/frontend/src/App.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/frontend/src/AppFrontend.vue b/frontend/src/AppFrontend.vue new file mode 100644 index 000000000..94e62bbc7 --- /dev/null +++ b/frontend/src/AppFrontend.vue @@ -0,0 +1,31 @@ + + + + + Speckle 2 + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/AppSetup.vue b/frontend/src/AppSetup.vue new file mode 100644 index 000000000..580b5fa31 --- /dev/null +++ b/frontend/src/AppSetup.vue @@ -0,0 +1,60 @@ + + + + + + + Welcome to your new Speckle Server! + There's a bit of housekeeping to do first before we're ready to roll. + + + + + Register an admin user + + Setup variables + + Name of step 3 + + + + + wow + + + Continue + + + + + + Continue + + + + + + Done! + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/main.js b/frontend/src/main-frontend.js similarity index 87% rename from frontend/src/main.js rename to frontend/src/main-frontend.js index 79b7256e1..4ac8d3f40 100644 --- a/frontend/src/main.js +++ b/frontend/src/main-frontend.js @@ -1,5 +1,5 @@ import Vue from 'vue' -import App from './App.vue' +import App from './AppFrontend.vue' import router from './router' import store from './store' import vuetify from './plugins/vuetify'; diff --git a/frontend/src/main-serversetup.js b/frontend/src/main-serversetup.js new file mode 100644 index 000000000..3bf2d111d --- /dev/null +++ b/frontend/src/main-serversetup.js @@ -0,0 +1,10 @@ +import Vue from 'vue' +import SetupApp from './AppSetup.vue' +import vuetify from './plugins/vuetify' + +Vue.config.productionTip = false + +new Vue( { + vuetify, + render: h => h( SetupApp ) +} ).$mount( '#app' ) \ No newline at end of file diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index e7f26834e..c7142cb93 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -7,17 +7,12 @@ Vue.use( VueRouter ) const routes = [ { path: '/', name: 'Home', - component: ( ) => { - return import( '../views/Setup.vue' ) - } + component: ( ) => import( '../views/Home.vue' ) }, { path: '/about', name: 'About', - // route level code-splitting - // this generates a separate chunk (about.[hash].js) for this route - // which is lazy-loaded when the route is visited. - component: ( ) => import( /* webpackChunkName: "about" */ '../views/About.vue' ) + component: ( ) => import( '../views/About.vue' ) } ] diff --git a/frontend/src/views/Setup.vue b/frontend/src/views/Setup.vue deleted file mode 100644 index bab59d8ad..000000000 --- a/frontend/src/views/Setup.vue +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - Welcome to your new Speckle Server! - There's a bit of housekeeping to do first before we're ready to roll. - - - - - Register an admin user - - Setup variables - - Name of step 3 - - - - - wow - - - Continue - - - - - - Continue - - - - - - Done! - - - - - - - - - - \ No newline at end of file diff --git a/frontend/vue.config.js b/frontend/vue.config.js index ef6e86b24..a10d853f3 100644 --- a/frontend/vue.config.js +++ b/frontend/vue.config.js @@ -1,4 +1,26 @@ module.exports = { + pages: { + setup: { + entry: 'src/main-serversetup.js', + title: 'Speckle Server Preflight Setup', + template: 'public/setup.html', + filename: 'setup.html' + }, + app: { + entry: 'src/main-frontend.js', + title: 'Speckle!', + template: 'public/app.html', + filename: 'app.html' + } + }, + devServer: { + historyApiFallback: { + rewrites: [ + { from: /\/app/, to: '/app.html' }, + { from: /\/setup/, to: '/setup.html' } + ] + } + }, "transpileDependencies": [ "vuetify" ] diff --git a/knexfile.js b/knexfile.js index e8c4a4c5a..e7550b85a 100644 --- a/knexfile.js +++ b/knexfile.js @@ -30,14 +30,14 @@ module.exports = { }, development: { client: 'pg', - connection: 'postgres://localhost/speckle2', + connection: process.env.POSTGRES_URL || 'postgres://localhost/speckle2_dev', migrations: { directory: migrationDirs }, }, production: { client: 'pg', - connection: process.env.DATABASE_URL, + connection: process.env.POSTGRES_URL, migrations: { directory: migrationDirs } diff --git a/modules/core/graph/resolvers/user.js b/modules/core/graph/resolvers/user.js index 1a8f55007..23e47c06b 100644 --- a/modules/core/graph/resolvers/user.js +++ b/modules/core/graph/resolvers/user.js @@ -1,8 +1,9 @@ 'use strict' const root = require( 'app-root-path' ) -const { AuthenticationError, UserInputError } = require( 'apollo-server-express' ) +const { ApolloError, AuthenticationError, UserInputError } = require( 'apollo-server-express' ) const { createUser, getUser, getUserRole, updateUser, deleteUser, validatePasssword, createToken, revokeToken, revokeTokenById, validateToken, getUserTokens } = require( '../../services/users' ) const { validateServerRole, validateScopes, authorizeResolver } = require( `${root}/modules/shared` ) +const setupCheck = require( `${root}/setupcheck` ) module.exports = { Query: { @@ -41,5 +42,15 @@ module.exports = { await updateUser( context.userId, args.user ) return true }, + async userCreate( parent, args, context, info ) { + let setupComplete = await setupCheck( ) + if ( setupComplete && process.env.STRATEGY_LOCAL !== 'true' ) + throw new ApolloError( 'Registration method not available' ) + + let userId = await createUser( args.user ) + let token = await createToken( userId, "Default Token", [ 'streams:read', 'streams:write' ] ) + return token + + } } } \ No newline at end of file diff --git a/modules/core/graph/schemas/server.graphql b/modules/core/graph/schemas/server.graphql index 6d6b0cc84..fede24531 100644 --- a/modules/core/graph/schemas/server.graphql +++ b/modules/core/graph/schemas/server.graphql @@ -7,9 +7,11 @@ Information about this server. """ type ServerInfo { name: String! - description: String! - adminContact: String! - tos: String! + company: String + description: String + adminContact: String + canonicalUrl: String + tos: String roles: [Role]! scopes: [Scope]! } diff --git a/modules/core/migrations/000-core.js b/modules/core/migrations/000-core.js index 6a7dde36b..625411146 100644 --- a/modules/core/migrations/000-core.js +++ b/modules/core/migrations/000-core.js @@ -3,7 +3,16 @@ // Knex table migrations exports.up = async knex => { await knex.raw( 'CREATE EXTENSION IF NOT EXISTS "pgcrypto"' ) - await knex.raw( 'CREATE EXTENSION IF NOT EXISTS "ltree"' ) + + await knex.schema.createTable( 'server_config', table => { + table.integer( 'id' ).notNullable( ).defaultTo( 0 ).index( ) + table.string( 'name' ).defaultTo( 'My Speckle Server' ) + table.string( 'company' ) + table.string( 'description' ) + table.string( 'canonicalUrl' ) + table.string( 'adminContact' ) + table.string( 'termsOfService' ) + } ) await knex.schema.createTable( 'users', table => { table.string( 'id', 10 ).primary( ) @@ -31,7 +40,7 @@ exports.up = async knex => { await knex.schema.createTable( 'server_acl', table => { table.string( 'userId', 10 ).references( 'id' ).inTable( 'users' ).primary( ).onDelete( 'cascade' ) table.string( 'role' ).references( 'name' ).inTable( 'user_roles' ).notNullable( ).onDelete( 'cascade' ) - }) + } ) // Tokens. await knex.schema.createTable( 'api_tokens', table => { @@ -153,6 +162,8 @@ exports.up = async knex => { } exports.down = async knex => { + await knex.schema.dropTableIfExists( 'server_config' ) + await knex.schema.dropTableIfExists( 'server_acl' ) await knex.schema.dropTableIfExists( 'stream_acl' ) await knex.schema.dropTableIfExists( 'user_roles' ) diff --git a/package-lock.json b/package-lock.json index 7fcdcd692..ba26dedf1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1593,6 +1593,34 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concurrently": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-5.2.0.tgz", + "integrity": "sha512-XxcDbQ4/43d6CxR7+iV8IZXhur4KbmEJk1CetVMUqCy34z9l0DkszbY+/9wvmSnToTej0SYomc2WSRH+L0zVJw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "date-fns": "^2.0.1", + "lodash": "^4.17.15", + "read-pkg": "^4.0.1", + "rxjs": "^6.5.2", + "spawn-command": "^0.0.2-1", + "supports-color": "^6.1.0", + "tree-kill": "^1.2.2", + "yargs": "^13.3.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -1747,6 +1775,12 @@ "word-wrap": "^1.0.3" } }, + "date-fns": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.14.0.tgz", + "integrity": "sha512-1zD+68jhFgDIM0rF05rcwYO8cExdNqxjq4xP1QKM60Q45mnO6zaMWB4tOzrIr4M4GSLntsKeE4c9Bdl2jhL/yw==", + "dev": true + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -1921,7 +1955,6 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, - "optional": true, "requires": { "is-arrayish": "^0.2.1" } @@ -2751,6 +2784,12 @@ "parse-passwd": "^1.0.0" } }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -2921,8 +2960,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true, - "optional": true + "dev": true }, "is-binary-path": { "version": "2.1.0", @@ -3282,8 +3320,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true, - "optional": true + "dev": true }, "json5": { "version": "2.1.3", @@ -3823,6 +3860,18 @@ "osenv": "^0.1.4" } }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4303,7 +4352,6 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, - "optional": true, "requires": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -4438,6 +4486,12 @@ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "dev": true }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, "pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -4566,6 +4620,17 @@ "strip-json-comments": "~2.0.1" } }, + "read-pkg": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", + "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", + "dev": true, + "requires": { + "normalize-package-data": "^2.3.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0" + } + }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -5026,6 +5091,12 @@ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" }, + "spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", + "dev": true + }, "spawn-wrap": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", @@ -5060,6 +5131,38 @@ } } }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, "split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", @@ -5353,6 +5456,12 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, "ts-invariant": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz", @@ -5502,6 +5611,16 @@ "homedir-polyfill": "^1.0.1" } }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index a26ee02fc..522772ee8 100644 --- a/package.json +++ b/package.json @@ -4,21 +4,21 @@ "description": "speckle server", "main": "index.js", "scripts": { + "dev:all": "concurrently --kill-others \"npm run dev:server\" \"npm run dev:frontend\"", "dev:frontend": "cd frontend && npm run serve", "build:frontend": "cd frontend && npm run build", - "dev:server": "PORT=3000 NODE_ENV=development DEBUG=www:server,speckle:* nodemon ./bin/www --watch . --watch ./bin/www -e js,graphql,env", - "production:server": "PORT=3000 NODE_ENV=production nodemon ./bin/www --watch . --watch ./bin/www -e js,graphql,env", - "test:server": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test nyc nyc --reporter html --reporter lcovonly mocha -s 0 --timeout 2000 --exit", - "test:server:watch": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test mocha --watch -s 0 --exit", - "test:server:graph": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test mocha ./modules/core/tests/graph.spec.js --watch -s 0 --exit --no-config", - "test:server:generic": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test mocha ./modules/core/tests/generic.spec.js --watch -s 0 --exit --no-config", - "test:server:objects": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test mocha ./modules/core/tests/objects.spec.js --watch -s 0 --exit --no-config", - "test:server:streams": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test mocha ./modules/core/tests/streams.spec.js --watch -s 0 --exit --no-config", - "test:server:references": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test mocha ./modules/core/tests/references.spec.js --watch -s 0 --exit --no-config", - "test:server:users": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test mocha ./modules/core/tests/users.spec.js --watch -s 0 --exit --no-config" + "dev:server": "PORT=3000 NODE_ENV=development POSTGRES_URL=postgres://localhost/speckle2 DEBUG=www:server,speckle:* nodemon ./bin/www --watch . --watch ./bin/www -e js,graphql,env", + "test:server": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test POSTGRES_URL=postgres://localhost/speckle2_test nyc nyc --reporter html --reporter lcovonly mocha -s 0 --timeout 2000 --exit", + "test:server:watch": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test POSTGRES_URL=postgres://localhost/speckle2_test mocha --watch -s 0 --exit", + "test:server:graph": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test POSTGRES_URL=postgres://localhost/speckle2_test mocha ./modules/core/tests/graph.spec.js --watch -s 0 --exit --no-config", + "test:server:generic": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test POSTGRES_URL=postgres://localhost/speckle2_test mocha ./modules/core/tests/generic.spec.js --watch -s 0 --exit --no-config", + "test:server:objects": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test POSTGRES_URL=postgres://localhost/speckle2_test mocha ./modules/core/tests/objects.spec.js --watch -s 0 --exit --no-config", + "test:server:streams": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test POSTGRES_URL=postgres://localhost/speckle2_test mocha ./modules/core/tests/streams.spec.js --watch -s 0 --exit --no-config", + "test:server:references": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test POSTGRES_URL=postgres://localhost/speckle2_test mocha ./modules/core/tests/references.spec.js --watch -s 0 --exit --no-config", + "test:server:users": "PORT=3001 DEBUG=speckle:test,speckle:errors NODE_ENV=test POSTGRES_URL=postgres://localhost/speckle2_test mocha ./modules/core/tests/users.spec.js --watch -s 0 --exit --no-config" }, - "author": "", - "license": "MIT", + "author": "The Specklers", + "license": "", "dependencies": { "apollo-server-express": "^2.12.0", "apollo-server-testing": "^2.12.0", @@ -45,6 +45,7 @@ "devDependencies": { "chai": "^4.2.0", "chai-http": "^4.3.0", + "concurrently": "^5.2.0", "cz-conventional-changelog": "^3.1.0", "mocha": "^7.1.1", "nyc": "^15.0.1" diff --git a/setupcheck.js b/setupcheck.js new file mode 100644 index 000000000..9538b151f --- /dev/null +++ b/setupcheck.js @@ -0,0 +1,13 @@ +const knex = require( './db/knex' ) +const ServerRoles = ( ) => knex( 'server_acl' ) +const ServerConf = ( ) => knex( 'server_config' ) + +module.exports = async ( ) => { + let [ { count } ] = await ServerRoles( ).where( { role: 'server:admin' } ).count( ) + if ( parseInt( count ) === 0 ) return false + + let conf = ServerConf( ).select( '*' ).first( ) + if ( !conf ) return false + + return true +} \ No newline at end of file
There's a bit of housekeeping to do first before we're ready to roll.