dev: track old app names

This commit is contained in:
KernelDeimos 2024-12-18 16:30:14 -05:00
parent 40abd568e3
commit 0ccb3b2eed
6 changed files with 115 additions and 6 deletions

View File

@ -358,6 +358,9 @@ const install = async ({ services, app, useapi, modapi }) => {
const { AppIconService } = require('./services/AppIconService');
services.registerService('app-icon', AppIconService);
const { OldAppNameService } = require('./services/OldAppNameService');
services.registerService('old-app-name', OldAppNameService);
}
const install_legacy = async ({ services }) => {

View File

@ -1214,6 +1214,10 @@ async function app_name_exists(name){
let rows = await db.read(`SELECT EXISTS(SELECT 1 FROM apps WHERE apps.name=?) AS app_name_exists`, [name]);
if(rows[0].app_name_exists)
return true;
const svc_oldAppName = services.get('old-app-name');
const name_info = await svc_oldAppName.check_app_name(name);
if ( name_info ) return true;
}
function send_email_verification_code(email_confirm_code, email){

View File

@ -88,9 +88,9 @@ class AppES extends BaseES {
async upsert (entity, extra) {
if ( await app_name_exists(await entity.get('name')) ) {
const { old_entity } = extra;
const throw_it = ( ! old_entity ) ||
const is_name_change = ( ! old_entity ) ||
( await old_entity.get('name') !== await entity.get('name') );
if ( throw_it && extra.options && extra.options.dedupe_name ) {
if ( is_name_change && extra?.options?.dedupe_name ) {
const base = await entity.get('name');
let number = 1;
while ( await app_name_exists(`${base}-${number}`) ) {
@ -98,10 +98,21 @@ class AppES extends BaseES {
}
await entity.set('name', `${base}-${number}`)
}
else if ( throw_it ) {
throw APIError.create('app_name_already_in_use', null, {
name: await entity.get('name')
});
else if ( is_name_change ) {
// The name might be taken because it's the old name
// of this same app. If it is, the app takes it back.
const svc_oldAppName = this.context.get('services').get('old-app-name');
const name_info = await svc_oldAppName.check_app_name(await entity.get('name'));
if ( ! name_info || name_info.app_uid !== await entity.get('uid') ) {
// Throw error because the name really is taken
throw APIError.create('app_name_already_in_use', null, {
name: await entity.get('name')
});
}
console.log('REMOVING NAME', name_info.id);
// Remove the old name from the old-app-name service
await svc_oldAppName.remove_name(name_info.id);
} else {
entity.del('name');
}
@ -147,6 +158,21 @@ class AppES extends BaseES {
}
}
const has_new_name =
extra.old_entity && (
await entity.get('name') !== await extra.old_entity.get('name')
);
if ( has_new_name ) {
const svc_event = this.context.get('services').get('event');
const event = {
app_uid: await entity.get('uid'),
new_name: await entity.get('name'),
old_name: await extra.old_entity.get('name'),
};
await svc_event.emit('app.rename', event);
}
// Associate app with subdomain (if applicable)
if ( subdomain_id ) {
await this.db.write(

View File

@ -0,0 +1,63 @@
const BaseService = require("./BaseService");
const { DB_READ } = require("./database/consts");
const N_MONTHS = 4;
class OldAppNameService extends BaseService {
_init () {
this.db = this.services.get('database').get(DB_READ, 'old-app-name');
}
async ['__on_boot.consolidation'] () {
const svc_event = this.services.get('event');
svc_event.on('app.rename', async (_, { app_uid, old_name }) => {
this.log.noticeme('GOT EVENT', { app_uid, old_name });
await this.db.write(
'INSERT INTO `old_app_names` (`app_uid`, `name`) VALUES (?, ?)',
[app_uid, old_name]
);
});
}
async check_app_name (name) {
const rows = await this.db.read(
'SELECT * FROM `old_app_names` WHERE `name` = ?',
[name]
);
if ( rows.length === 0 ) return;
// Check if the app has been renamed in the last N months
const [row] = rows;
const timestamp = new Date(row.timestamp);
const age = Date.now() - timestamp.getTime();
const n_ms = N_MONTHS * 30 * 24 * 60 * 60 * 1000
if ( age > n_ms ) {
// Remove record
await this.db.write(
'DELETE FROM `old_app_names` WHERE `id` = ?',
[row.id]
);
// Return undefined
return;
}
return {
id: row.id,
app_uid: row.app_uid,
};
}
async remove_name (id) {
await this.db.write(
'DELETE FROM `old_app_names` WHERE `id` = ?',
[id]
);
}
}
module.exports = {
OldAppNameService,
};

View File

@ -152,6 +152,9 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
[30, [
'0033_ai-usage.sql',
]],
[31, [
'0034_app-redirect.sql',
]],
];
// Database upgrade logic

View File

@ -0,0 +1,10 @@
CREATE TABLE `old_app_names` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`app_uid` char(40) NOT NULL,
`name` varchar(100) NOT NULL UNIQUE,
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`app_uid`) REFERENCES `apps`(`uid`) ON DELETE CASCADE
);
CREATE INDEX `idx_old_app_names_name` ON `old_app_names` (`name`);