App can now go into maintenance mode locking out routing
This commit is contained in:
@@ -1,3 +1,19 @@
|
||||
const MAINTENANCE_MODE = Meteor.settings?.public?.maintenanceMode || false;
|
||||
import { Migrations } from 'meteor/percolate:migrations';
|
||||
import SCHEMA_VERSION from '/imports/constants/SCHEMA_VERSION.js';
|
||||
|
||||
if (Meteor.isServer){
|
||||
Meteor.startup(()=>{
|
||||
const dbVersion = Migrations.getVersion();
|
||||
if (
|
||||
!Meteor.settings.public.maintenanceMode &&
|
||||
SCHEMA_VERSION !== dbVersion
|
||||
){
|
||||
Meteor.settings.public.maintenanceMode = {
|
||||
reason: 'App data needs to be migrated to the latest version'
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const MAINTENANCE_MODE = Meteor.settings.public.maintenanceMode;
|
||||
export default MAINTENANCE_MODE;
|
||||
|
||||
@@ -4,7 +4,13 @@
|
||||
<v-col cols="12">
|
||||
<v-card>
|
||||
<v-card-text>
|
||||
<h4>Database version: {{ versions && versions.dbVersion }}</h4>
|
||||
<h4>Current database version: {{ versions && versions.dbVersion }}</h4>
|
||||
<h4 v-if="schemaVersion == versions.dbVersion ">
|
||||
Database is up to date with latest version
|
||||
</h4>
|
||||
<h4 v-else>
|
||||
Expected database version: {{ schemaVersion }}
|
||||
</h4>
|
||||
<h4>Git version: {{ versions && versions.gitVersion }}</h4>
|
||||
<v-alert
|
||||
v-if="versionError"
|
||||
@@ -14,20 +20,18 @@
|
||||
</v-alert>
|
||||
<v-btn
|
||||
icon
|
||||
:loading="loadingVersion"
|
||||
@click="refreshVersions"
|
||||
>
|
||||
<v-icon>mdi-refresh</v-icon>
|
||||
</v-btn>
|
||||
<v-text-field
|
||||
v-model="migrationInput"
|
||||
label="Database version to migrate to"
|
||||
/>
|
||||
<br>
|
||||
<v-btn
|
||||
:disabled="!migrationInput"
|
||||
:disabled="!(schemaVersion > (versions && versions.dbVersion))"
|
||||
:loading="loadingMigration"
|
||||
@click="migrate"
|
||||
>
|
||||
Migrate
|
||||
Migrate to database version {{ schemaVersion }}
|
||||
</v-btn>
|
||||
<v-alert
|
||||
v-if="migrateError"
|
||||
@@ -45,6 +49,7 @@
|
||||
<script lang="js">
|
||||
import getVersion from '/imports/migrations/methods/getVersion.js';
|
||||
import migrateTo from '/imports/migrations/methods/migrateTo.js';
|
||||
import SCHEMA_VERSION from '/imports/constants/SCHEMA_VERSION.js';
|
||||
|
||||
export default {
|
||||
data(){return {
|
||||
@@ -54,25 +59,24 @@ export default {
|
||||
versionError: undefined,
|
||||
migrateError: undefined,
|
||||
loadingMigration: false,
|
||||
schemaVersion: SCHEMA_VERSION,
|
||||
}},
|
||||
mounted(){
|
||||
this.refreshVersions();
|
||||
},
|
||||
methods: {
|
||||
refreshVersions(){
|
||||
this.loadingVersion = true;
|
||||
getVersion.call((error, result) => {
|
||||
this.loadingVersion = false;
|
||||
this.versionError = error;
|
||||
this.versions = result;
|
||||
});
|
||||
},
|
||||
migrate(){
|
||||
let version = this.migrationInput;
|
||||
if (Number.isFinite(+version)){
|
||||
version = +version;
|
||||
}
|
||||
this.loadingMigration = true;
|
||||
migrateTo.call({
|
||||
version,
|
||||
version: SCHEMA_VERSION,
|
||||
}, error => {
|
||||
this.loadingMigration = false;
|
||||
this.migrateError = error;
|
||||
|
||||
43
app/imports/ui/pages/Maintenance.vue
Normal file
43
app/imports/ui/pages/Maintenance.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<v-layout
|
||||
style="height: 100%;"
|
||||
column
|
||||
align-center
|
||||
justify-center
|
||||
>
|
||||
<h1
|
||||
v-if="maintenanceMode"
|
||||
class="ma-4 text-h3"
|
||||
>
|
||||
DiceCloud is currently under maintenance
|
||||
</h1>
|
||||
<template v-else>
|
||||
<h1
|
||||
class="ma-4 text-h3"
|
||||
>
|
||||
DiceCloud is live.
|
||||
</h1>
|
||||
<v-btn
|
||||
color="accent"
|
||||
to="/"
|
||||
>
|
||||
Home
|
||||
</v-btn>
|
||||
</template>
|
||||
<h1
|
||||
v-if="maintenanceMode && maintenanceMode.reason"
|
||||
class="ma-4 text-h4"
|
||||
>
|
||||
{{ maintenanceMode.reason }}
|
||||
</h1>
|
||||
</v-layout>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import MAINTENANCE_MODE from '/imports/constants/MAINTENANCE_MODE.js';
|
||||
export default {
|
||||
data(){return {
|
||||
maintenanceMode: MAINTENANCE_MODE,
|
||||
}},
|
||||
}
|
||||
</script>
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RouterFactory, nativeScrollBehavior } from 'meteor/akryum:vue-router2';
|
||||
import { acceptInviteToken } from '/imports/api/users/Invites.js';
|
||||
|
||||
import MAINTENANCE_MODE from '/imports/constants/MAINTENANCE_MODE.js';
|
||||
// Components
|
||||
const Home = () => import('/imports/ui/pages/Home.vue');
|
||||
const About = () => import('/imports/ui/pages/About.vue');
|
||||
@@ -26,6 +26,8 @@ const Tabletop = () => import('/imports/ui/pages/Tabletop.vue');
|
||||
const TabletopToolbar = () => import('/imports/ui/tabletop/TabletopToolbar.vue');
|
||||
const TabletopRightDrawer = () => import('/imports/ui/tabletop/TabletopRightDrawer.vue');
|
||||
const Admin = () => import('/imports/ui/pages/Admin.vue');
|
||||
const Maintenance = () => import('/imports/ui/pages/Maintenance.vue');
|
||||
|
||||
// Not found
|
||||
const NotFound = () => import('/imports/ui/pages/NotFound.vue');
|
||||
|
||||
@@ -92,8 +94,8 @@ function claimInvite(to, from, next){
|
||||
});
|
||||
}
|
||||
|
||||
RouterFactory.configure(factory => {
|
||||
factory.addRoutes([{
|
||||
RouterFactory.configure(router => {
|
||||
router.addRoutes([{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
components: {
|
||||
@@ -249,29 +251,40 @@ RouterFactory.configure(factory => {
|
||||
name: 'admin',
|
||||
component: Admin,
|
||||
beforeEnter: ensureAdmin,
|
||||
},{
|
||||
path: '/maintenance',
|
||||
name: 'maintenance',
|
||||
component: Maintenance,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
// Not found route has lowest priority
|
||||
RouterFactory.configure(factory => {
|
||||
factory.addRoute({
|
||||
RouterFactory.configure(router => {
|
||||
router.addRoute({
|
||||
path: '*',
|
||||
component: NotFound,
|
||||
});
|
||||
}, -1);
|
||||
|
||||
function redirectIfMaintenance(to, from, next){
|
||||
if (!MAINTENANCE_MODE) return next();
|
||||
console.log(to);
|
||||
if (to?.path === '/admin' || to?.path === '/maintenance') return next();
|
||||
Tracker.autorun((computation) => {
|
||||
if (userSubscription.ready()){
|
||||
computation.stop();
|
||||
const user = Meteor.user();
|
||||
if (user && user.roles && user.roles.includes('admin')){
|
||||
next({name: 'admin'})
|
||||
} else {
|
||||
next({name: 'maintenance'});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Create the router instance
|
||||
const router = routerFactory.create();
|
||||
router.beforeEach((to, from, next) => {
|
||||
let user = Meteor.user();
|
||||
if (
|
||||
to.path === '/sign-in' ||
|
||||
(user && user.roles && user.roles.includes('admin'))
|
||||
){
|
||||
next();
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
router.beforeEach(redirectIfMaintenance);
|
||||
export default router;
|
||||
|
||||
@@ -56,7 +56,9 @@ self.addEventListener('fetch', (event) => {
|
||||
})));
|
||||
}
|
||||
|
||||
caches.open(version).then(cache => cache.put(event.request, clonedResponse));
|
||||
if (event.request.method !== 'POST') {
|
||||
caches.open(version).then(cache => cache.put(event.request, clonedResponse));
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}).catch(() => {
|
||||
|
||||
@@ -9,3 +9,4 @@ import '/imports/api/parenting/organizeMethods.js';
|
||||
import '/imports/api/users/patreon/updatePatreonOnLogin.js';
|
||||
import '/imports/migrations/server/index.js';
|
||||
import '/imports/migrations/methods/index.js'
|
||||
import '/imports/constants/MAINTENANCE_MODE.js';
|
||||
|
||||
Reference in New Issue
Block a user