🩹 backend: when anonymous user deletes file, update creator to parent folder (#433)
This commit is contained in:
committed by
ericlinagora
parent
c0bd6df482
commit
882120bef0
@@ -15,6 +15,8 @@ import { hasCompanyAdminLevel } from "../../../utils/company";
|
|||||||
import gr from "../../global-resolver";
|
import gr from "../../global-resolver";
|
||||||
import { DriveFile, TYPE } from "../entities/drive-file";
|
import { DriveFile, TYPE } from "../entities/drive-file";
|
||||||
import { FileVersion, TYPE as FileVersionType } from "../entities/file-version";
|
import { FileVersion, TYPE as FileVersionType } from "../entities/file-version";
|
||||||
|
import User, { TYPE as UserType } from "../../user/entities/user";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DriveTdriveTab as DriveTdriveTabEntity,
|
DriveTdriveTab as DriveTdriveTabEntity,
|
||||||
TYPE as DriveTdriveTabRepoType,
|
TYPE as DriveTdriveTabRepoType,
|
||||||
@@ -56,12 +58,14 @@ import {
|
|||||||
import archiver from "archiver";
|
import archiver from "archiver";
|
||||||
import internal from "stream";
|
import internal from "stream";
|
||||||
import config from "config";
|
import config from "config";
|
||||||
|
|
||||||
export class DocumentsService {
|
export class DocumentsService {
|
||||||
version: "1";
|
version: "1";
|
||||||
repository: Repository<DriveFile>;
|
repository: Repository<DriveFile>;
|
||||||
searchRepository: SearchRepository<DriveFile>;
|
searchRepository: SearchRepository<DriveFile>;
|
||||||
fileVersionRepository: Repository<FileVersion>;
|
fileVersionRepository: Repository<FileVersion>;
|
||||||
driveTdriveTabRepository: Repository<DriveTdriveTabEntity>;
|
driveTdriveTabRepository: Repository<DriveTdriveTabEntity>;
|
||||||
|
userRepository: Repository<User>;
|
||||||
ROOT: RootType = "root";
|
ROOT: RootType = "root";
|
||||||
TRASH: TrashType = "trash";
|
TRASH: TrashType = "trash";
|
||||||
quotaEnabled: boolean = config.has("drive.featureUserQuota")
|
quotaEnabled: boolean = config.has("drive.featureUserQuota")
|
||||||
@@ -88,8 +92,10 @@ export class DocumentsService {
|
|||||||
DriveTdriveTabRepoType,
|
DriveTdriveTabRepoType,
|
||||||
DriveTdriveTabEntity,
|
DriveTdriveTabEntity,
|
||||||
);
|
);
|
||||||
|
this.userRepository = await globalResolver.database.getRepository<User>(UserType, User);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error({ error: `${error}` }, "Error while initializing Documents Service");
|
logger.error({ error: `${error}` }, "Error while initializing Documents Service");
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@@ -670,6 +676,51 @@ export class DocumentsService {
|
|||||||
} else {
|
} else {
|
||||||
//This item is not in trash, we move it to trash
|
//This item is not in trash, we move it to trash
|
||||||
item.is_in_trash = true;
|
item.is_in_trash = true;
|
||||||
|
// Check item belongs to someone
|
||||||
|
if (item.creator !== context?.user?.id) {
|
||||||
|
const creator = await this.userRepository.findOne({ id: item.creator });
|
||||||
|
if (creator.type === "anonymous") {
|
||||||
|
const loadedCreators = new Map<string, User>();
|
||||||
|
const path = await getPath(
|
||||||
|
item.id,
|
||||||
|
this.repository,
|
||||||
|
true,
|
||||||
|
context,
|
||||||
|
async item => {
|
||||||
|
if (!item.creator) return true;
|
||||||
|
const user =
|
||||||
|
loadedCreators.get(item.creator) ??
|
||||||
|
(await this.userRepository.findOne({ id: item.creator }));
|
||||||
|
loadedCreators.set(item.creator, user);
|
||||||
|
return user.type !== "anonymous";
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
const [firstOwnedItem] = path;
|
||||||
|
if (firstOwnedItem) {
|
||||||
|
const firstKnownCreator = loadedCreators.get(firstOwnedItem.creator);
|
||||||
|
const accessEntitiesWithoutUser = item.access_info.entities.filter(
|
||||||
|
({ id, type }) => type != "user" || id != firstKnownCreator.id,
|
||||||
|
);
|
||||||
|
item.access_info.entities = [
|
||||||
|
...accessEntitiesWithoutUser,
|
||||||
|
{
|
||||||
|
type: "user",
|
||||||
|
id: firstKnownCreator.id,
|
||||||
|
level: "manage",
|
||||||
|
grantor: context.user.id,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
item.creator = firstKnownCreator.id;
|
||||||
|
} else {
|
||||||
|
// Move to company trash
|
||||||
|
item.parent_id = "trash";
|
||||||
|
item.scope = "shared";
|
||||||
|
}
|
||||||
|
await this.repository.save(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await this.update(item.id, item, context);
|
await this.update(item.id, item, context);
|
||||||
}
|
}
|
||||||
await updateItemSize(previousParentId, this.repository, context);
|
await updateItemSize(previousParentId, this.repository, context);
|
||||||
|
|||||||
@@ -256,30 +256,44 @@ export const updateItemSize = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the path for the driveitem
|
* Get a list of parents for the provided DriveFile id, in top-down order,
|
||||||
|
* but internally iterated towards the top.
|
||||||
*
|
*
|
||||||
* @param {string} id
|
* @param {boolean} ignoreAccess If user from context doesn't have
|
||||||
* @param {Repository<DriveFile>} repository
|
* read access to an item, the item is not included and traversing
|
||||||
* @param {boolean} ignoreAccess
|
* towards parents is stopped there.
|
||||||
* @param {CompanyExecutionContext} context
|
* @param {(item: DriveFile) => Promise<boolean>} predicate If set,
|
||||||
* @returns
|
* returned items in the array include only those for which the
|
||||||
|
* `predicate`'s result resolved to true.
|
||||||
|
* @param {boolean?} stopAtFirstMatch If true, the lowest item
|
||||||
|
* in the hierarchy that matches the `predicate` will be the
|
||||||
|
* only item in the returned array.
|
||||||
|
* @returns A promise to an array of DriveFile entries in order
|
||||||
|
* starting from the root (eg. "My Drive"), and ending in the
|
||||||
|
* DriveFile matching the provided `id` ; both included.
|
||||||
|
*
|
||||||
|
* If `stopAtFirstMatch` is true and `predicate` is provided, the
|
||||||
|
* result is an array with a single item or an empty array.
|
||||||
*/
|
*/
|
||||||
export const getPath = async (
|
export const getPath = async (
|
||||||
id: string,
|
id: string,
|
||||||
repository: Repository<DriveFile>,
|
repository: Repository<DriveFile>,
|
||||||
ignoreAccess?: boolean,
|
ignoreAccess?: boolean,
|
||||||
context?: DriveExecutionContext,
|
context?: DriveExecutionContext,
|
||||||
|
predicate?: (item: DriveFile) => Promise<boolean>,
|
||||||
|
stopAtFirstMatch: boolean = false,
|
||||||
): Promise<DriveFile[]> => {
|
): Promise<DriveFile[]> => {
|
||||||
id = id || "root";
|
id = id || "root";
|
||||||
if (isVirtualFolder(id))
|
if (isVirtualFolder(id)) {
|
||||||
return !context?.user?.public_token_document_id || ignoreAccess
|
const virtualItem = {
|
||||||
? [
|
id,
|
||||||
{
|
name: await getVirtualFoldersNames(id, context),
|
||||||
id,
|
} as DriveFile;
|
||||||
name: await getVirtualFoldersNames(id, context),
|
return (!context?.user?.public_token_document_id || ignoreAccess) &&
|
||||||
} as DriveFile,
|
(!predicate || (await predicate(virtualItem)))
|
||||||
]
|
? [virtualItem]
|
||||||
: [];
|
: [];
|
||||||
|
}
|
||||||
const item = await repository.findOne({
|
const item = await repository.findOne({
|
||||||
id,
|
id,
|
||||||
company_id: context.company.id,
|
company_id: context.company.id,
|
||||||
@@ -288,8 +302,17 @@ export const getPath = async (
|
|||||||
if (!item || (!(await checkAccess(id, item, "read", repository, context)) && !ignoreAccess)) {
|
if (!item || (!(await checkAccess(id, item, "read", repository, context)) && !ignoreAccess)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
const isMatch = !predicate || (await predicate(item));
|
||||||
return [...(await getPath(item.parent_id, repository, ignoreAccess, context)), item];
|
if (stopAtFirstMatch && isMatch) return [item];
|
||||||
|
const parents = await getPath(
|
||||||
|
item.parent_id,
|
||||||
|
repository,
|
||||||
|
ignoreAccess,
|
||||||
|
context,
|
||||||
|
predicate,
|
||||||
|
stopAtFirstMatch,
|
||||||
|
);
|
||||||
|
return isMatch ? [...parents, item] : parents;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user