🚧 back: user deletion wip
This commit is contained in:
committed by
Anton Shepilov
parent
99d78ad5ac
commit
658e8de6d4
+9
-39
@@ -4,45 +4,13 @@ import type { ExecutionContext } from "../../../../platform/framework/api/crud-s
|
||||
|
||||
import { adminLogger, buildUserDeletionRepositories } from "../utils";
|
||||
|
||||
// /**
|
||||
// * Create all repositories required for deleting a user
|
||||
// * @deprecated Do not use this outside of this file, it is exported exclusively for e2e tests
|
||||
// */
|
||||
// export async function buildUserDeletionRepositories(
|
||||
// db: DatabaseServiceAPI,
|
||||
// search: SearchServiceAPI,
|
||||
// ) {
|
||||
// return {
|
||||
// driveFile: await db.getRepository<DriveFile>(DriveFileType, DriveFile),
|
||||
// file: await db.getRepository<File>(FileType, File),
|
||||
// fileVersion: await db.getRepository<FileVersion>(FileVersionType, FileVersion),
|
||||
|
||||
// user: await db.getRepository<User>(UserType, User),
|
||||
// companyUser: await db.getRepository<CompanyUser>(CompanyUserType, CompanyUser),
|
||||
// externalUser: await db.getRepository<ExternalUser>(ExternalUserType, ExternalUser),
|
||||
|
||||
// // company: await db.getRepository<Company>(CompanyType, Company),
|
||||
// // missed_drive_files
|
||||
// // session
|
||||
// // user_online
|
||||
|
||||
// search: {
|
||||
// driveFile: await search.getRepository<DriveFile>(DriveFileType, DriveFile),
|
||||
// user: await search.getRepository<User>(UserType, User),
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
|
||||
export class AdminDeleteUserController {
|
||||
private constructor(
|
||||
private readonly repos: Awaited<ReturnType<typeof buildUserDeletionRepositories>>,
|
||||
) {}
|
||||
public static async create() {
|
||||
return new AdminDeleteUserController(
|
||||
await buildUserDeletionRepositories(gr.database, gr.platformServices.search),
|
||||
);
|
||||
private _repos: Awaited<ReturnType<typeof buildUserDeletionRepositories>>;
|
||||
private async getRepos() {
|
||||
if (!this._repos)
|
||||
this._repos = await buildUserDeletionRepositories(gr.database, gr.platformServices.search);
|
||||
return this._repos;
|
||||
}
|
||||
// fisherYattesShuffleInPlace
|
||||
|
||||
/** Begin or forward the deletion process of a user */
|
||||
async deleteUser(userId: string): Promise<"failed" | "deleting" | "done"> {
|
||||
@@ -51,7 +19,7 @@ export class AdminDeleteUserController {
|
||||
user: { server_request: true },
|
||||
company: { id: "// TODO: REPLACE WITH COMPANY ID" },
|
||||
} as unknown as ExecutionContext);
|
||||
const existingUser = await this.repos.user.findOne({ id: userId });
|
||||
const existingUser = await (await this.getRepos()).user.findOne({ id: userId });
|
||||
if (existingUser?.deleted) {
|
||||
if (existingUser.delete_process_started_epoch > 0) return "deleting";
|
||||
}
|
||||
@@ -65,7 +33,9 @@ export class AdminDeleteUserController {
|
||||
|
||||
/** Get an array of user IDs that are incompletely deleted */
|
||||
async listUsersPendingDeletion() {
|
||||
return (await this.repos.user.find({}, { $gt: [["delete_process_started_epoch", 0]] }))
|
||||
return (
|
||||
await (await this.getRepos()).user.find({}, { $gt: [["delete_process_started_epoch", 0]] })
|
||||
)
|
||||
.getEntities()
|
||||
.map(({ id }) => id);
|
||||
}
|
||||
|
||||
@@ -8,14 +8,13 @@ import {
|
||||
descendDriveItemsDepthFirstRandomOrder,
|
||||
loadRawVersionsOfItemForDeletion,
|
||||
runInBatchesAreAllTrue,
|
||||
TUserDeletionRepos,
|
||||
} from "./utils";
|
||||
|
||||
export default class AdminServiceImpl implements AdminServiceAPI {
|
||||
version: "1";
|
||||
|
||||
private _repos;
|
||||
private get repos(): TUserDeletionRepos {
|
||||
private get repos(): ReturnType<typeof buildUserDeletionRepositories> {
|
||||
return (this._repos ||= buildUserDeletionRepositories());
|
||||
}
|
||||
|
||||
@@ -35,8 +34,9 @@ export default class AdminServiceImpl implements AdminServiceAPI {
|
||||
Promise.all(
|
||||
paths.map(path => {
|
||||
try {
|
||||
return gr.platformServices.storage.remove(path);
|
||||
return gr.platformServices.storage.remove("x" + path);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
logger.error({ err, path }, "Error deleting storage item");
|
||||
return false;
|
||||
}
|
||||
@@ -71,12 +71,16 @@ export default class AdminServiceImpl implements AdminServiceAPI {
|
||||
*/
|
||||
const deleteUserLogger = adminLogger.child({ adminOp: "DeleteUser", user });
|
||||
const result = await descendDriveItemsDepthFirstRandomOrder(
|
||||
this.repos,
|
||||
await this.repos,
|
||||
"user_" + user.id,
|
||||
async (item, children, _parents) => {
|
||||
let canDeleteItem = true;
|
||||
if (!item.is_directory) {
|
||||
const versionsAssets = await loadRawVersionsOfItemForDeletion(this.repos, item, true);
|
||||
const versionsAssets = await loadRawVersionsOfItemForDeletion(
|
||||
await this.repos,
|
||||
item,
|
||||
true,
|
||||
);
|
||||
for (const { version, file, paths } of versionsAssets) {
|
||||
if (paths.length > 0 && !(await this.deleteS3Paths(deleteUserLogger, paths))) {
|
||||
deleteUserLogger.error({ paths }, "Failed to delete paths");
|
||||
@@ -84,7 +88,7 @@ export default class AdminServiceImpl implements AdminServiceAPI {
|
||||
} else {
|
||||
try {
|
||||
if (file) {
|
||||
const result = await this.repos.file.remove(file);
|
||||
const result = await (await this.repos).file.remove(file);
|
||||
if (!result)
|
||||
// No error but nothing deleted, just move on
|
||||
deleteUserLogger.warn({ file, result }, "Failed to delete file");
|
||||
@@ -96,7 +100,7 @@ export default class AdminServiceImpl implements AdminServiceAPI {
|
||||
if (canDeleteItem && version)
|
||||
try {
|
||||
if (version) {
|
||||
const result = await this.repos.fileVersion.remove(version);
|
||||
const result = await (await this.repos).fileVersion.remove(version);
|
||||
if (!result)
|
||||
// No error but nothing deleted, just move on
|
||||
deleteUserLogger.warn({ version, result }, "Failed to delete version");
|
||||
@@ -109,18 +113,18 @@ export default class AdminServiceImpl implements AdminServiceAPI {
|
||||
}
|
||||
}
|
||||
if (canDeleteItem) {
|
||||
if (children.every(x => !!x)) {
|
||||
if (children === undefined || children.every(x => !!x)) {
|
||||
if (item.is_directory && children.length == 0)
|
||||
deleteUserLogger.warn({ item }, "Deleting empty directory");
|
||||
try {
|
||||
await this.repos.search.driveFile.service.remove([item as never]);
|
||||
await (await this.repos).search.driveFile.service.remove([item as never]);
|
||||
} catch (err) {
|
||||
canDeleteItem = false;
|
||||
deleteUserLogger.error({ err, item }, "Error deleting drive item search entry");
|
||||
}
|
||||
if (canDeleteItem)
|
||||
try {
|
||||
const result = await this.repos.driveFile.remove(item);
|
||||
const result = await (await this.repos).driveFile.remove(item);
|
||||
if (!result)
|
||||
// No error but nothing deleted, just move on
|
||||
deleteUserLogger.warn({ item, result }, "Failed to delete drive item");
|
||||
@@ -141,9 +145,9 @@ export default class AdminServiceImpl implements AdminServiceAPI {
|
||||
);
|
||||
if (!result.every(x => !!x)) return false;
|
||||
//TODO: error checking and such
|
||||
await this.repos.search.user.service.remove([user as never]);
|
||||
await (await this.repos).search.user.service.remove([user as never]);
|
||||
user.delete_process_started_epoch = 0;
|
||||
await this.repos.user.save(user);
|
||||
await (await this.repos).user.save(user);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +158,7 @@ export class UserServiceImpl {
|
||||
const user = await this.get(pk);
|
||||
|
||||
if (context.user.server_request || context.user.id === user.id) {
|
||||
const userCopy = { ...user } as User;
|
||||
//We keep a part of the user id as new name
|
||||
const partialId = user.id.toString().split("-")[0];
|
||||
|
||||
@@ -177,6 +178,8 @@ export class UserServiceImpl {
|
||||
localEventBus.publish<ResourceEventsPayload>("user:deleted", {
|
||||
user: user,
|
||||
});
|
||||
|
||||
await gr.platformServices.admin.deleteUser(userCopy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user