mirror of
https://github.com/HeyPuter/puter.git
synced 2025-02-02 23:28:39 +08:00
dev: track old app names
This commit is contained in:
parent
40abd568e3
commit
0ccb3b2eed
@ -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 }) => {
|
||||
|
@ -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){
|
||||
|
@ -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(
|
||||
|
63
src/backend/src/services/OldAppNameService.js
Normal file
63
src/backend/src/services/OldAppNameService.js
Normal 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,
|
||||
};
|
@ -152,6 +152,9 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
|
||||
[30, [
|
||||
'0033_ai-usage.sql',
|
||||
]],
|
||||
[31, [
|
||||
'0034_app-redirect.sql',
|
||||
]],
|
||||
];
|
||||
|
||||
// Database upgrade logic
|
||||
|
@ -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`);
|
Loading…
Reference in New Issue
Block a user