🐛 Restored correct "allow free signup" setting from backup after buggy 4.3 upgrade (#12905)

refs https://github.com/TryGhost/Team/issues/634

- find earliest backup file created when a 4.3 migration was run, if found use the `members_allow_free_signup` value from there to change `members_signup_access` from `'all'` to `'invite'` if necessary
This commit is contained in:
Kevin Ansfield 2021-05-04 09:49:33 +01:00 committed by GitHub
parent 7b6df51d08
commit 0f41d1aa49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -0,0 +1,98 @@
const logging = require('../../../../../shared/logging');
const {createTransactionalMigration} = require('../../utils');
const config = require('../../../../../shared/config');
const fs = require('fs-extra');
const path = require('path');
const semver = require('semver');
// 4.3.0 contained a buggy migration for members_allow_free_signup -> members_signup_access
// meaning all sites switched to allowing free member signup.
//
// This migration attempts to fix that by finding the original value from the db backup file
// created during migration and updating the new setting value to match
// we only care about backups created since the bad release was published
const MIN_DATE = new Date('2021-04-21T00:00:00.000Z');
module.exports = createTransactionalMigration(
async function up(connection) {
const currentSetting = await connection('settings')
.where({key: 'members_signup_access'})
.select('value')
.first();
if (!currentSetting) {
logging.info('Skipping restore of "allow free signups", `members_signup_access` setting doesn\'t exist');
return;
}
if (currentSetting.value !== 'all') {
logging.info('Skipping restore of "allow free signups", setting changed since bad migration');
return;
}
// 1. find any backup files that have a date of 2021-04-21 or later
// 2. loop through backup files to find first one exported on 4.3.0 or later
// 3. load JSON and get correct value
// 4. update database if necessary
const contentPath = config.get('paths').contentPath;
const dataPath = path.join(contentPath, 'data');
const backupFileRegex = /ghost\.([\d]{4}-[\d]{2}-[\d]{2})-([\d]{2}-[\d]{2}-[\d]{2})\.json$/;
const backupFileDate = function (filename) {
const dateMatch = filename.match(backupFileRegex);
return new Date(`${dateMatch[1]}T${dateMatch[2].replace(/-/g, ':')}.000Z`);
};
logging.info('Restoring "allow free signups" value from backup files if needed');
let files;
try {
files = await fs.readdir(dataPath);
} catch (error) {
logging.info('Skipping restore, unable to read backup files');
return;
}
// filter to known backup files, later than min date, ordered earliest to latest
const backupFiles = files
.filter(filename => backupFileRegex.test(filename))
.filter(filename => backupFileDate(filename) > MIN_DATE)
.sort((a, b) => backupFileDate(a) - backupFileDate(b));
let hasRestored = false;
for (const backupFile of backupFiles) {
try {
const backup = require(path.join(dataPath, backupFile));
if (semver.satisfies(backup.meta.version, '4.3.x')) {
const oldValue = backup.data.settings.find(s => s.key === 'members_allow_free_signup');
if (oldValue && oldValue.value === 'false') {
logging.info('Setting `members_signup_access` to \'invite\' to match previous `members_allow_free_signup` setting');
await connection('settings')
.where({key: 'members_signup_access'})
.update({value: 'invite'});
// found earliest backup we care about, don't check any more files
hasRestored = true;
break;
}
}
} catch (error) {
// noop, move on to next file
}
}
if (!hasRestored) {
logging.info('Skipping restore, not necessary');
}
},
async function down() {
// noop
}
);