Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions api/src/migration/migrations/1756483008605-v-2-3-2.migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright © 2025 Hexastack. All rights reserved.
*
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/

import mongoose from 'mongoose';

import blockSchema, { Block } from '@/chat/schemas/block.schema';
import roleSchema, { Role } from '@/user/schemas/role.schema';
import userSchema, { User } from '@/user/schemas/user.schema';
Comment on lines +12 to +13
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove unused admin lookup and hard dependency (migration can silently no‑op).

The admin user is fetched but never used. Worse, the migration returns early if no admin exists, leaving data un-migrated. Drop this code to ensure the migration always runs.

-import roleSchema, { Role } from '@/user/schemas/role.schema';
-import userSchema, { User } from '@/user/schemas/user.schema';
+// Admin lookup removed: not needed for this migration

-/**
- * @returns The admin user or null
- */
-const getAdminUser = async () => {
-  const RoleModel = mongoose.model<Role>(Role.name, roleSchema);
-  const UserModel = mongoose.model<User>(User.name, userSchema);
-
-  const adminRole = await RoleModel.findOne({ name: 'admin' });
-  const user = await UserModel.findOne({ roles: [adminRole!._id] }).sort({
-    createdAt: 'asc',
-  });
-
-  return user!;
-};
-
-  const adminUser = await getAdminUser();
-
-  if (!adminUser) {
-    services.logger.warn('Unable to process block, no admin user found');
-    return;
-  }

Also applies to: 17-31, 35-41

🤖 Prompt for AI Agents
In api/src/migration/migrations/1756483008605-v-2-3-2.migration.ts around lines
12-13 (and affecting 17-31, 35-41), remove the unused admin lookup and the
early-return that makes the migration a hard no-op when no admin exists; delete
the code that queries for the admin user and any conditional that returns if
admin is falsy so the migration logic always runs, and remove now-unused imports
(roleSchema/Role and userSchema/User) or adjust imports/typing accordingly;
ensure the remaining migration code executes unconditionally and still handles
the case where no admin-related data exists without throwing.


import { MigrationServices } from '../types';

/**
* @returns The admin user or null
*/
const getAdminUser = async () => {
const RoleModel = mongoose.model<Role>(Role.name, roleSchema);
const UserModel = mongoose.model<User>(User.name, userSchema);

const adminRole = await RoleModel.findOne({ name: 'admin' });
const user = await UserModel.findOne({ roles: [adminRole!._id] }).sort({
createdAt: 'asc',
});

return user!;
};

const migrateBlockOptionsTyping = async (services: MigrationServices) => {
const BlockModel = mongoose.model<Block>(Block.name, blockSchema).collection;

const adminUser = await getAdminUser();

if (!adminUser) {
services.logger.warn('Unable to process block, no admin user found');
return;
}

try {
await BlockModel.updateMany({ 'options.typing': { $exists: true } }, [
{
$set: {
'options.typing': { $toInt: '$options.typing' },
},
},
]);
} catch (error) {
services.logger.error(`Failed to update typing : ${error.message}`);

throw error instanceof Error ? error : new Error(error);
}
};

module.exports = {
async up(services: MigrationServices) {
try {
await migrateBlockOptionsTyping(services);

return true;
} catch (error) {
services.logger.error(`Migration failed : ${error.message}`);
throw error instanceof Error ? error : new Error(error);
}
},
async down(_services: MigrationServices) {
return true;
},
};