mirror of
https://github.com/hexastack/hexabot
synced 2025-01-22 18:45:57 +00:00
fix: move users avatars under the new folder
This commit is contained in:
parent
e16660a0a0
commit
d1e9214128
@ -6,8 +6,8 @@
|
|||||||
* 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).
|
* 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 { existsSync, promises as fsPromises } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
import { join } from 'path';
|
import { join, resolve } from 'path';
|
||||||
|
|
||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
@ -16,6 +16,8 @@ import attachmentSchema, {
|
|||||||
} from '@/attachment/schemas/attachment.schema';
|
} from '@/attachment/schemas/attachment.schema';
|
||||||
import subscriberSchema, { Subscriber } from '@/chat/schemas/subscriber.schema';
|
import subscriberSchema, { Subscriber } from '@/chat/schemas/subscriber.schema';
|
||||||
import { config } from '@/config';
|
import { config } from '@/config';
|
||||||
|
import userSchema, { User } from '@/user/schemas/user.schema';
|
||||||
|
import { moveFile, moveFiles } from '@/utils/helpers/fs';
|
||||||
|
|
||||||
import { MigrationServices } from '../types';
|
import { MigrationServices } from '../types';
|
||||||
|
|
||||||
@ -79,22 +81,85 @@ const unpopulateSubscriberAvatar = async ({ logger }: MigrationServices) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateOldAvatarsPath = async ({ logger }: MigrationServices) => {
|
const updateOldAvatarsPath = async ({ logger }: MigrationServices) => {
|
||||||
|
// Make sure the old folder is moved
|
||||||
const oldPath = join(process.cwd(), process.env.AVATAR_DIR || '/avatars');
|
const oldPath = join(process.cwd(), process.env.AVATAR_DIR || '/avatars');
|
||||||
if (existsSync(oldPath)) {
|
if (existsSync(oldPath)) {
|
||||||
await fsPromises.copyFile(oldPath, config.parameters.avatarDir);
|
logger.verbose(
|
||||||
await fsPromises.unlink(oldPath);
|
`Moving subscriber avatar files from ${oldPath} to ${config.parameters.avatarDir} ...`,
|
||||||
|
);
|
||||||
|
await moveFiles(oldPath, config.parameters.avatarDir);
|
||||||
logger.log('Avatars folder successfully moved to its new location ...');
|
logger.log('Avatars folder successfully moved to its new location ...');
|
||||||
} else {
|
} else {
|
||||||
logger.log('No old avatars folder found ...');
|
logger.log(`No old avatars folder found: ${oldPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move users avatars to the "uploads/avatars" folder
|
||||||
|
const AttachmentModel = mongoose.model<Attachment>(
|
||||||
|
Attachment.name,
|
||||||
|
attachmentSchema,
|
||||||
|
);
|
||||||
|
const UserModel = mongoose.model<User>(User.name, userSchema);
|
||||||
|
|
||||||
|
const cursor = UserModel.find().cursor();
|
||||||
|
|
||||||
|
for await (const user of cursor) {
|
||||||
|
try {
|
||||||
|
if (user.avatar) {
|
||||||
|
const avatar = await AttachmentModel.findOne({ _id: user.avatar });
|
||||||
|
if (avatar) {
|
||||||
|
const src = resolve(
|
||||||
|
join(config.parameters.uploadDir, avatar.location),
|
||||||
|
);
|
||||||
|
const dst = resolve(
|
||||||
|
join(config.parameters.avatarDir, avatar.location),
|
||||||
|
);
|
||||||
|
logger.verbose(`Moving user avatar file from ${src} to ${dst} ...`);
|
||||||
|
await moveFile(src, dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(err);
|
||||||
|
logger.error('Unable to move user avatar to the new folder');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const restoreOldAvatarsPath = async ({ logger }: MigrationServices) => {
|
const restoreOldAvatarsPath = async ({ logger }: MigrationServices) => {
|
||||||
|
// Move users avatars to the "/app/avatars" folder
|
||||||
|
const AttachmentModel = mongoose.model<Attachment>(
|
||||||
|
Attachment.name,
|
||||||
|
attachmentSchema,
|
||||||
|
);
|
||||||
|
const UserModel = mongoose.model<User>(User.name, userSchema);
|
||||||
|
|
||||||
|
const cursor = UserModel.find().cursor();
|
||||||
|
|
||||||
|
for await (const user of cursor) {
|
||||||
|
try {
|
||||||
|
if (user.avatar) {
|
||||||
|
const avatar = await AttachmentModel.findOne({ _id: user.avatar });
|
||||||
|
if (avatar) {
|
||||||
|
const src = resolve(
|
||||||
|
join(config.parameters.avatarDir, avatar.location),
|
||||||
|
);
|
||||||
|
const dst = resolve(
|
||||||
|
join(config.parameters.uploadDir, avatar.location),
|
||||||
|
);
|
||||||
|
logger.verbose(`Moving user avatar file from ${src} to ${dst} ...`);
|
||||||
|
await moveFile(src, dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(err);
|
||||||
|
logger.error('Unable to move user avatar to the new folder');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
const oldPath = join(process.cwd(), process.env.AVATAR_DIR || '/avatars');
|
const oldPath = join(process.cwd(), process.env.AVATAR_DIR || '/avatars');
|
||||||
if (existsSync(config.parameters.avatarDir)) {
|
if (existsSync(config.parameters.avatarDir)) {
|
||||||
await fsPromises.copyFile(config.parameters.avatarDir, oldPath);
|
await moveFiles(config.parameters.avatarDir, oldPath);
|
||||||
await fsPromises.unlink(config.parameters.avatarDir);
|
logger.log('Avatars folder successfully moved to the old location ...');
|
||||||
logger.log('Avatars folder successfully moved to its old location ...');
|
|
||||||
} else {
|
} else {
|
||||||
logger.log('No avatars folder found ...');
|
logger.log('No avatars folder found ...');
|
||||||
}
|
}
|
||||||
|
@ -102,14 +102,22 @@ export class ReadOnlyUserController extends BaseController<
|
|||||||
throw new NotFoundException(`user with ID ${id} not found`);
|
throw new NotFoundException(`user with ID ${id} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.avatar) {
|
try {
|
||||||
|
if (!user.avatar) {
|
||||||
|
throw new Error('User has no avatar');
|
||||||
|
}
|
||||||
|
|
||||||
return await this.attachmentService.download(
|
return await this.attachmentService.download(
|
||||||
user.avatar,
|
user.avatar,
|
||||||
config.parameters.avatarDir,
|
config.parameters.avatarDir,
|
||||||
);
|
);
|
||||||
|
} catch (err) {
|
||||||
|
this.logger.verbose(
|
||||||
|
'User has no avatar, generating initials avatar ...',
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
return await generateInitialsAvatar(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
return generateInitialsAvatar(user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
69
api/src/utils/helpers/fs.ts
Normal file
69
api/src/utils/helpers/fs.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* 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 fs from 'fs';
|
||||||
|
import { basename, join, resolve } from 'path';
|
||||||
|
|
||||||
|
export async function moveFile(
|
||||||
|
sourcePath: string,
|
||||||
|
destinationPath: string,
|
||||||
|
overwrite: boolean = true,
|
||||||
|
): Promise<string> {
|
||||||
|
// Check if the file exists at the destination
|
||||||
|
try {
|
||||||
|
if (overwrite) {
|
||||||
|
await fs.promises.unlink(destinationPath); // Remove existing file if overwrite is true
|
||||||
|
} else {
|
||||||
|
await fs.promises.access(destinationPath);
|
||||||
|
throw new Error(`File already exists at destination: ${destinationPath}`);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ignore if file does not exist
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the file
|
||||||
|
await fs.promises.copyFile(sourcePath, destinationPath);
|
||||||
|
await fs.promises.unlink(sourcePath);
|
||||||
|
return destinationPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves all files from a source folder to a destination folder.
|
||||||
|
* @param sourceFolder - The folder containing the files to move.
|
||||||
|
* @param destinationFolder - The folder where the files should be moved.
|
||||||
|
* @param overwrite - Whether to overwrite files if they already exist at the destination (default: false).
|
||||||
|
* @returns A promise that resolves when all files have been moved.
|
||||||
|
*/
|
||||||
|
export async function moveFiles(
|
||||||
|
sourceFolder: string,
|
||||||
|
destinationFolder: string,
|
||||||
|
overwrite: boolean = true,
|
||||||
|
): Promise<void> {
|
||||||
|
// Read the contents of the source folder
|
||||||
|
const files = await fs.promises.readdir(sourceFolder);
|
||||||
|
|
||||||
|
// Filter only files (skip directories)
|
||||||
|
const filePaths = await Promise.all(
|
||||||
|
files.map(async (file) => {
|
||||||
|
const filePath = join(sourceFolder, file);
|
||||||
|
const stat = await fs.promises.stat(filePath);
|
||||||
|
return stat.isFile() ? filePath : null;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Move each file to the destination folder
|
||||||
|
const movePromises = filePaths
|
||||||
|
.filter((filePath): filePath is string => filePath !== null)
|
||||||
|
.map((filePath) => {
|
||||||
|
const fileName = basename(filePath);
|
||||||
|
const destination = resolve(join(destinationFolder, fileName));
|
||||||
|
return moveFile(filePath, destination, overwrite);
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(movePromises);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user