Added archive migrations to schema version 2
This commit is contained in:
@@ -13,12 +13,12 @@ import { incrementFileStorageUsed } from '/imports/api/users/methods/updateFileS
|
||||
import verifyArchiveSafety from '/imports/api/creature/archive/methods/verifyArchiveSafety.js';
|
||||
|
||||
let migrateArchive;
|
||||
if (Meteor.isServer){
|
||||
migrateArchive = require('/imports/migrations/server/migrateArchive.js').default;
|
||||
if (Meteor.isServer) {
|
||||
migrateArchive = require('/imports/migrations/archive/migrateArchive.js').default;
|
||||
}
|
||||
|
||||
function restoreCreature(archive, userId){
|
||||
if (SCHEMA_VERSION < archive.meta.schemaVersion){
|
||||
function restoreCreature(archive, userId) {
|
||||
if (SCHEMA_VERSION < archive.meta.schemaVersion) {
|
||||
throw new Meteor.Error('Incompatible',
|
||||
'The archive file is from a newer version. Update required to read.')
|
||||
}
|
||||
@@ -35,7 +35,7 @@ function restoreCreature(archive, userId){
|
||||
});
|
||||
if (existingCreature) throw new Meteor.Error('Already exists',
|
||||
'The creature you are trying to restore already exists.')
|
||||
|
||||
|
||||
// Ensure the user owns the restored creature
|
||||
archive.creature.owner = userId;
|
||||
|
||||
@@ -44,13 +44,13 @@ function restoreCreature(archive, userId){
|
||||
Creatures.insert(archive.creature);
|
||||
try {
|
||||
// Add all the properties
|
||||
if (archive.properties && archive.properties.length){
|
||||
if (archive.properties && archive.properties.length) {
|
||||
CreatureProperties.batchInsert(archive.properties);
|
||||
}
|
||||
if (archive.experiences && archive.experiences.length){
|
||||
if (archive.experiences && archive.experiences.length) {
|
||||
Experiences.batchInsert(archive.experiences);
|
||||
}
|
||||
if (archive.logs && archive.logs.length){
|
||||
if (archive.logs && archive.logs.length) {
|
||||
CreatureLogs.batchInsert(archive.logs);
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -73,23 +73,23 @@ const restoreCreaturefromFile = new ValidatedMethod({
|
||||
numRequests: 10,
|
||||
timeInterval: 5000,
|
||||
},
|
||||
async run({fileId}) {
|
||||
async run({ fileId }) {
|
||||
// fetch the file
|
||||
const file = ArchiveCreatureFiles.findOne({_id: fileId}).get();
|
||||
if (!file){
|
||||
const file = ArchiveCreatureFiles.findOne({ _id: fileId }).get();
|
||||
if (!file) {
|
||||
throw new Meteor.Error('File not found',
|
||||
'The requested creature archive does not exist');
|
||||
'The requested creature archive does not exist');
|
||||
}
|
||||
// Assert ownership
|
||||
const userId = file?.userId;
|
||||
if (!userId || userId !== this.userId){
|
||||
if (!userId || userId !== this.userId) {
|
||||
throw new Meteor.Error('Permission denied',
|
||||
'You can only restore creatures you own');
|
||||
'You can only restore creatures you own');
|
||||
}
|
||||
|
||||
assertHasCharactersSlots(this.userId);
|
||||
|
||||
if (Meteor.isServer){
|
||||
if (Meteor.isServer) {
|
||||
// Read the file data
|
||||
const archive = await ArchiveCreatureFiles.readJSONFile(file);
|
||||
restoreCreature(archive, this.userId);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import applyFnToKey from '../utility/applyFnToKey.js';
|
||||
import { unset } from 'lodash';
|
||||
|
||||
export default function removeSchemaFields(schemas, prop){
|
||||
export default function removeSchemaFields(schemas, prop) {
|
||||
schemas.forEach(schema => {
|
||||
schema.removeBeforeComputeFields().forEach(
|
||||
schema?.removeBeforeComputeFields?.().forEach(
|
||||
key => applyFnToKey(prop, key, unset)
|
||||
);
|
||||
});
|
||||
|
||||
16
app/imports/migrations/archive/cleanArchiveAt2.js
Normal file
16
app/imports/migrations/archive/cleanArchiveAt2.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
|
||||
export default function cleanAt2(archive) {
|
||||
archive.properties = archive.properties.map(prop => {
|
||||
let cleanProp = prop;
|
||||
try {
|
||||
const schema = CreatureProperties.simpleSchema(prop);
|
||||
// Clean according to schema
|
||||
cleanProp = schema.clean(prop);
|
||||
schema.validate(cleanProp);
|
||||
} catch (e) {
|
||||
console.warn('Failed to clean archive prop', { propId: prop._id, error: e.message || e.reason || e.toString() });
|
||||
}
|
||||
return cleanProp;
|
||||
});
|
||||
}
|
||||
28
app/imports/migrations/archive/migrateArchive.js
Normal file
28
app/imports/migrations/archive/migrateArchive.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import migrateTo1 from './migrateArchiveTo1.js';
|
||||
import migrate1To2 from './migrateArchive1To2.js';
|
||||
import cleanAt2 from './cleanArchiveAt2.js';
|
||||
|
||||
/* eslint no-fallthrough: "off" -- Using switch fallthrough to run all
|
||||
migration steps after the current version of the file. */
|
||||
export default function migrateArchive(archive) {
|
||||
switch (archive.meta.schemaVersion) {
|
||||
// V1 of DiceCloud
|
||||
case 'version1':
|
||||
migrateLegacyArchive(archive);
|
||||
// V2 of DiceCloud, Schema version 1
|
||||
case 1:
|
||||
migrateTo1(archive);
|
||||
migrate1To2(archive);
|
||||
// V2 of DiceCloud, Schema version 2
|
||||
case 2:
|
||||
cleanAt2(archive);
|
||||
break;
|
||||
default:
|
||||
throw 'Archive version not supported';
|
||||
}
|
||||
}
|
||||
|
||||
function migrateLegacyArchive() {
|
||||
// TODO:
|
||||
throw 'Not implemented';
|
||||
}
|
||||
46
app/imports/migrations/archive/migrateArchive1To2.js
Normal file
46
app/imports/migrations/archive/migrateArchive1To2.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import applyFnToKey from '/imports/api/engine/computation/utility/applyFnToKey.js';
|
||||
import { get } from 'lodash';
|
||||
|
||||
const dollarSignRegex = /(\W)\$(\w+)/gi;
|
||||
|
||||
export default function migrate1To2(archive) {
|
||||
archive.properties = archive.properties.map(prop => {
|
||||
try {
|
||||
// Migrate slot fillers to folders
|
||||
if (prop.type === 'slotFiller') {
|
||||
prop.type = 'folder';
|
||||
}
|
||||
// Get the schema
|
||||
const schema = CreatureProperties.simpleSchema(prop);
|
||||
// Replace dollar signs in calculations with tildes
|
||||
schema.inlineCalculationFields().forEach(key => {
|
||||
applyFnToKey(prop, key, (prop, key) => {
|
||||
const inlineCalcObj = get(prop, key);
|
||||
const string = inlineCalcObj?.text;
|
||||
if (!string) return;
|
||||
const newString = string.replace(dollarSignRegex, '$1~$2');
|
||||
if (string !== newString) {
|
||||
inlineCalcObj.text = newString;
|
||||
inlineCalcObj.hash = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
schema.computedFields().forEach(key => {
|
||||
applyFnToKey(prop, key, (prop, key) => {
|
||||
const inlineCalcObj = get(prop, key);
|
||||
const string = inlineCalcObj?.calculation;
|
||||
if (!string) return;
|
||||
const newString = string.replace(dollarSignRegex, '$1~$2');
|
||||
if (string !== newString) {
|
||||
inlineCalcObj.calculation = newString;
|
||||
inlineCalcObj.hash = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn('Property migration 1 -> 2 failed: ', { propId: prop._id, error: e.message || e.reason || e.toString() });
|
||||
}
|
||||
return prop;
|
||||
});
|
||||
}
|
||||
@@ -1,39 +1,45 @@
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import { get, set } from 'lodash';
|
||||
import applyFnToKey from '/imports/api/engine/computation/utility/applyFnToKey.js';
|
||||
import { calculationUp } from '/imports/migrations/server/dbv1/dbv1.js';
|
||||
|
||||
export default function cleanAt1(archive){
|
||||
|
||||
function calculationUp(val) {
|
||||
if (typeof val !== 'string') return val;
|
||||
if (!val.replace) console.log({ val, replace: val.replace });
|
||||
return val.replace(/#(\w+).(\w+)Result/g, '#$1.$2')
|
||||
.replace(/\.value/g, '.total')
|
||||
.replace(/\.currentValue/g, '.value');
|
||||
}
|
||||
|
||||
export default function migrateTo1(archive) {
|
||||
archive.properties = archive.properties.map(prop => {
|
||||
let cleanProp = prop;
|
||||
try {
|
||||
if (prop.type === 'attack') prop.type = 'action';
|
||||
if (prop.type === 'slotFiller') prop.type = 'folder';
|
||||
// Get the schema
|
||||
const schema = CreatureProperties.simpleSchema(prop);
|
||||
// Clean all the text fields with inline calcs
|
||||
schema.inlineCalculationFields().forEach(key => {
|
||||
applyFnToKey(prop, key, (prop, key) => {
|
||||
let field = get(prop, key);
|
||||
if (typeof field === 'string' || typeof field === 'number'){
|
||||
if (typeof field === 'string' || typeof field === 'number') {
|
||||
field = calculationUp(field);
|
||||
set(prop, key, {text: `${field}`});
|
||||
set(prop, key, { text: `${field}` });
|
||||
}
|
||||
});
|
||||
});
|
||||
schema.computedFields().forEach(key => {
|
||||
applyFnToKey(prop, key, (prop, key) => {
|
||||
let field = get(prop, key) || get(prop, key + 'Calculation');
|
||||
if (typeof field === 'string' || typeof field === 'number'){
|
||||
if (typeof field === 'string' || typeof field === 'number') {
|
||||
field = calculationUp(field);
|
||||
set(prop, key, {calculation: `${field}`});
|
||||
set(prop, key, { calculation: `${field}` });
|
||||
}
|
||||
});
|
||||
});
|
||||
cleanProp = schema.clean(prop);
|
||||
schema.validate(cleanProp);
|
||||
} catch (e){
|
||||
console.warn({propId: prop._id, error: e.message || e.reason || e.toString()});
|
||||
} catch (e) {
|
||||
console.warn('Property migration -> 1 failed: ', { propId: prop._id, error: e.message || e.reason || e.toString() });
|
||||
}
|
||||
return cleanProp;
|
||||
return prop;
|
||||
});
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function cleanAt2() {
|
||||
return;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import cleanAt1 from '/imports/migrations/server/dbv1/cleanAt1.js';
|
||||
|
||||
/* eslint no-fallthrough: "off" -- Using switch fallthrough to run all
|
||||
migration steps after the current version of the file. */
|
||||
export default function migrateArchive(archive){
|
||||
switch (archive.meta.schemaVersion){
|
||||
// V1 of DiceCloud
|
||||
case 'version1':
|
||||
migrateLegacyArchive(archive);
|
||||
// V2 of DiceCloud, Schema version 1
|
||||
case 1:
|
||||
cleanAt1(archive);
|
||||
}
|
||||
}
|
||||
|
||||
function migrateLegacyArchive(archive){
|
||||
// TODO:
|
||||
throw 'Not implemented';
|
||||
}
|
||||
Reference in New Issue
Block a user