Added better error checking to migration schema statics.

This commit is contained in:
rainbow napkin 2025-10-09 18:02:04 -04:00
parent 9fda308306
commit ad0dd6bdbb

View file

@ -24,6 +24,7 @@ const {mongoose} = require('mongoose');
const config = require('../../../config.json'); const config = require('../../../config.json');
const {userModel} = require('../user/userSchema'); const {userModel} = require('../user/userSchema');
const permissionModel = require('../permissionSchema'); const permissionModel = require('../permissionSchema');
const loggerUtils = require('../../utils/loggerUtils');
/** /**
@ -66,41 +67,49 @@ const migrationSchema = new mongoose.Schema({
}, },
}); });
//TODO: before next commit, add error checking to the ingestLegacy statics down below
//Also add a warning for the fail condition in ingestLegacyDump that bails out when missing files
//statics //statics
/** /**
* Static method for ingesting data dump from legacy cytube/fore.st server * Static method for ingesting data dump from legacy cytube/fore.st server
*/ */
migrationSchema.statics.ingestLegacyDump = async function(){ migrationSchema.statics.ingestLegacyDump = async function(){
//If migration is disabled
if(!config.migrate){
//BAIL!
return;
}
//Crash directory
const dir = "./migration/"
const userDump = `${dir}users.sql`
//Double check migration files
try{ try{
//Pull dump stats //If migration is disabled
await fs.stat(userDump); if(!config.migrate){
//If we caught an error (most likely it's missing) //BAIL!
return;
}
//Crash directory
const dir = "./migration/"
const userDump = `${dir}users.sql`
//Double check migration files
try{
//Pull dump stats
await fs.stat(userDump);
//If we caught an error (most likely it's missing)
}catch(err){
loggerUtils.consoleWarn("No migration files detected! Pleas provide legacy migration files or disable migration from config.json!");
//BAIL!
return;
}
//Pull raw dump from file
const rawDump = await fs.readFile(userDump, 'binary');
//Split dump by line
const splitDump = rawDump.split('\n');
//For each line in the user dump
for(const line of splitDump){
//Ingest the legacy user profile
this.ingestLegacyUser(line);
}
}catch(err){ }catch(err){
//BAIL! return loggerUtils.localExceptionHandler(err);
return;
}
//Pull raw dump from file
const rawDump = await fs.readFile(userDump, 'binary');
//Split dump by line
const splitDump = rawDump.split('\n');
//For each line in the user dump
for(const line of splitDump){
//Ingest the legacy user profile
this.ingestLegacyUser(line);
} }
} }
@ -109,82 +118,90 @@ migrationSchema.statics.ingestLegacyDump = async function(){
* @param {String} rawProfile - Line of text contianing raw profile dump * @param {String} rawProfile - Line of text contianing raw profile dump
*/ */
migrationSchema.statics.ingestLegacyUser = async function(rawProfile){ migrationSchema.statics.ingestLegacyUser = async function(rawProfile){
//If migration is disabled try{
if(!config.migrate){ //If migration is disabled
//BAIL! if(!config.migrate){
return; //BAIL!
return;
}
//Filter out the entry from any extra guff on the line
const profileMatches = rawProfile.match(/^\((.*?(?=,),){9}.*?(?=\))\)/g);
//If we have an invalid line
if(profileMatches <= 0){
loggerUtils.consoleWarn('Bad profile detected in legacy dump:');
loggerUtils.consoleWarn(rawProfile);
//BAIL!
return;
}
//Set filtered profile to the match we found
let filteredProfile = profileMatches[0];
//cook the filtered profile in order to trick the JSON interpreter into thinking it's an array
filteredProfile = `[${filteredProfile.substring(1, filteredProfile.length - 1)}]`;
//Replace single qoutes with double to match JSON strings
filteredProfile = filteredProfile.replaceAll(",'",',"');
filteredProfile = filteredProfile.replaceAll("',",'",');
//Make sure single qoutes are escaped
filteredProfile = filteredProfile.replaceAll("\'",'\\\'');
//Dupe the JSON interpreter like the rube that it is
const profileArray = JSON.parse(filteredProfile);
//If profile array is the wrong length
if(profileArray.length != 10){
loggerUtils.consoleWarn('Bad profile detected in legacy dump:');
loggerUtils.consoleWarn(profileArray);
//BAIL!
return;
}
//Look for user in migration table
const foundMigration = await this.findOne({user:profileArray[1]});
const foundUser = await userModel.findOne({user: profileArray[1]});
//If we found the user in the database
if(foundMigration != null || foundUser != null){
//Scream
loggerUtils.consoleWarn(`Found legacy user ${profileArray[1]} in database, skipping migration!`);
//BAIL!
return;
}
//Create migration profile object from scraped info
const migrationProfile = new this({
user: profileArray[1],
pass: profileArray[2],
//Clamp rank to 0 and the max setting allowed by the rank enum
rank: Math.min(Math.max(0, profileArray[3]), permissionModel.rankEnum.length - 1),
email: profileArray[4],
date: profileArray[7],
})
//If our profile array isn't empty
if(profileArray[5] != ''){
//Make sure single qoutes are escaped, and parse bio JSON
const bioObject = JSON.parse(profileArray[5].replaceAll("\'",'\\\''));
//Inject bio information into migration profile, only if they're present;
migrationProfile.bio = bioObject.text == '' ? undefined : bioObject.text;
migrationProfile.image = bioObject.image == '' ? undefined : bioObject.image;
}
//Build DB Doc from migration Profile hashtable and dump it into the DB
await this.create(migrationProfile);
//Let the world know of our triumph!
console.log(`Legacy user profile ${migrationProfile.user} migrated successfully!`);
}catch(err){
return loggerUtils.localExceptionHandler(err);
} }
//Filter out the entry from any extra guff on the line
const profileMatches = rawProfile.match(/^\((.*?(?=,),){9}.*?(?=\))\)/g);
//If we have an invalid line
if(profileMatches <= 0){
//BAIL!
return;
}
//Set filtered profile to the match we found
let filteredProfile = profileMatches[0];
//cook the filtered profile in order to trick the JSON interpreter into thinking it's an array
filteredProfile = `[${filteredProfile.substring(1, filteredProfile.length - 1)}]`;
//Replace single qoutes with double to match JSON strings
filteredProfile = filteredProfile.replaceAll(",'",',"');
filteredProfile = filteredProfile.replaceAll("',",'",');
//Make sure single qoutes are escaped
filteredProfile = filteredProfile.replaceAll("\'",'\\\'');
//Dupe the JSON interpreter like the rube that it is
const profileArray = JSON.parse(filteredProfile);
//If profile array is the wrong length
if(profileArray.length != 10){
//BAIL!
return;
}
//Look for user in migration table
const foundMigration = await this.findOne({user:profileArray[1]});
const foundUser = await userModel.findOne({user: profileArray[1]});
//If we found the user in the database
if(foundMigration != null || foundUser != null){
//Scream
console.log(`Found legacy user ${profileArray[1]} in database, skipping migration!`);
//BAIL!
return;
}
//Create migration profile object from scraped info
const migrationProfile = new this({
user: profileArray[1],
pass: profileArray[2],
//Clamp rank to 0 and the max setting allowed by the rank enum
rank: Math.min(Math.max(0, profileArray[3]), permissionModel.rankEnum.length - 1),
email: profileArray[4],
date: profileArray[7],
})
//If our profile array isn't empty
if(profileArray[5] != ''){
//Make sure single qoutes are escaped, and parse bio JSON
const bioObject = JSON.parse(profileArray[5].replaceAll("\'",'\\\''));
//Inject bio information into migration profile, only if they're present;
migrationProfile.bio = bioObject.text == '' ? undefined : bioObject.text;
migrationProfile.image = bioObject.image == '' ? undefined : bioObject.image;
}
//Build DB Doc from migration Profile hashtable and dump it into the DB
await this.create(migrationProfile);
//Let the world know of our triumph!
console.log(`Legacy user profile ${migrationProfile.user} migrated successfully!`);
} }
module.exports = mongoose.model("migration", migrationSchema); module.exports = mongoose.model("migration", migrationSchema);