feat(structure): structured frontend into an MPA and various other fixes

This commit is contained in:
Dimitrie Stefanescu
2020-05-24 20:16:51 +01:00
parent eb1c90e6b9
commit 23b63c749c
21 changed files with 413 additions and 158 deletions
+2 -1
View File
@@ -2,4 +2,5 @@ node_modules
frontend/node_modules
frontend/dist
.nyc_output
coverage/
coverage/
.env
+13 -9
View File
@@ -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', ( ) => {
-7
View File
@@ -1,7 +0,0 @@
'use strict'
require( 'dotenv' ).config( { path: `${root}/.env` } )
module.exports = {
}
+10 -1
View File
@@ -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
+75 -26
View File
@@ -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",
+4 -1
View File
@@ -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",
-21
View File
@@ -1,21 +0,0 @@
<template>
<v-app dark>
<router-view></router-view>
</v-app>
</template>
<script>
import HelloWorld from './components/HelloWorld';
export default {
name: 'App',
components: {
HelloWorld,
},
data: ( ) => ( {
setup: true
} ),
}
</script>
+31
View File
@@ -0,0 +1,31 @@
<template>
<v-app dark>
<v-app-bar app clipped-left color="accent" dark>
<v-app-bar-nav-icon @click="drawer = !drawer"></v-app-bar-nav-icon>
<span class="title ml-3 mr-5">Speckle&nbsp;<span class="font-weight-light">2</span></span>
<v-spacer></v-spacer>
</v-app-bar>
<v-navigation-drawer v-model="drawer" app clipped color="grey lighten-4">
</v-navigation-drawer>
<v-content>
<router-view></router-view>
</v-content>
</v-app>
</template>
<script>
import HelloWorld from './components/HelloWorld';
export default {
name: 'App',
components: {
HelloWorld,
},
data: ( ) => ( {
setup: true,
drawer: true
} ),
}
</script>
+60
View File
@@ -0,0 +1,60 @@
<template>
<v-app dark>
<v-content>
<v-container align="center" mt-10>
<v-row wrap>
<v-col cols='12'>
<h1 class='display-2 font-weight-light'>Welcome to your new Speckle Server!</h1>
<p class='subheading'>There's a bit of housekeeping to do first before we're ready to roll.</p>
</v-col>
<v-col cols='12'>
<v-stepper v-model="e1">
<v-stepper-header>
<v-stepper-step :complete="e1 > 1" step="1">Register an admin user</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step :complete="e1 > 2" step="2">Setup variables</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step step="3">Name of step 3</v-stepper-step>
</v-stepper-header>
<v-stepper-items>
<v-stepper-content step="1">
<v-card class="mb-12 elevation-0" color="grey lighten-4" height="200px">
wow
</v-card>
<v-btn color="primary" @click="e1 = 2">
Continue
</v-btn>
</v-stepper-content>
<v-stepper-content step="2">
<v-card class="mb-12 elevation-0" color="grey lighten-4" height="200px"></v-card>
<v-btn color="primary" @click="e1 = 3">
Continue
</v-btn>
</v-stepper-content>
<v-stepper-content step="3">
<v-card class="mb-12 elevation-0" color="grey lighten-4" height="200px"></v-card>
<v-btn color="primary" @click="e1 = 1">
Done!
</v-btn>
</v-stepper-content>
</v-stepper-items>
</v-stepper>
</v-col>
</v-row>
</v-container>
</v-content>
</v-app>
</template>
<script>
export default {
name: 'App',
components: {},
data: ( ) => ( {
setup: true, //lol
e1: 1
} ),
}
</script>
@@ -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';
+10
View File
@@ -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' )
+2 -7
View File
@@ -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' )
}
]
-58
View File
@@ -1,58 +0,0 @@
<template>
<v-content>
<v-container align="center" mt-10>
<v-row wrap>
<v-col cols='12'>
<h1 class='display-2 font-weight-light'>Welcome to your new Speckle Server!</h1>
<p class='subheading'>There's a bit of housekeeping to do first before we're ready to roll.</p>
</v-col>
<v-col cols='12'>
<v-stepper v-model="e1">
<v-stepper-header>
<v-stepper-step :complete="e1 > 1" step="1">Register an admin user</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step :complete="e1 > 2" step="2">Setup variables</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step step="3">Name of step 3</v-stepper-step>
</v-stepper-header>
<v-stepper-items>
<v-stepper-content step="1">
<v-card class="mb-12 elevation-0" color="grey lighten-4" height="200px">
wow
</v-card>
<v-btn color="primary" @click="e1 = 2">
Continue
</v-btn>
</v-stepper-content>
<v-stepper-content step="2">
<v-card class="mb-12 elevation-0" color="grey lighten-4" height="200px"></v-card>
<v-btn color="primary" @click="e1 = 3">
Continue
</v-btn>
</v-stepper-content>
<v-stepper-content step="3">
<v-card class="mb-12 elevation-0" color="grey lighten-4" height="200px"></v-card>
<v-btn color="primary" @click="e1 = 1">
Done!
</v-btn>
</v-stepper-content>
</v-stepper-items>
</v-stepper>
</v-col>
</v-row>
</v-container>
</v-content>
</template>
<script>
export default {
name: 'App',
components: {
},
data: ( ) => ( {
e1: 1
} ),
}
</script>
+22
View File
@@ -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"
]
+2 -2
View File
@@ -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
}
+12 -1
View File
@@ -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
}
}
}
+5 -3
View File
@@ -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]!
}
+13 -2
View File
@@ -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' )
+125 -6
View File
@@ -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",
+13 -12
View File
@@ -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"
+13
View File
@@ -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
}