✨ Share with me endpoint (#77)
* 🛠️ remove babel from dependencies * 🛠️ removes some of the redundant dependencies + versions update * ✨ separate endpoint for "shared with me"
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import * as cron from "node-cron";
|
||||
import uuid from "node-uuid";
|
||||
import uuid from "uuid";
|
||||
|
||||
import { TdriveService } from "../../framework";
|
||||
import { CronAPI, CronJob, CronExpression, CronTask } from "./api";
|
||||
|
||||
@@ -168,12 +168,12 @@ export const getAccessLevel = async (
|
||||
const prevalidatedPublicTokenDocumentId = context?.user?.public_token_document_id;
|
||||
|
||||
try {
|
||||
item =
|
||||
item ||
|
||||
(await repository.findOne({
|
||||
if (!item) {
|
||||
item = await repository.findOne({
|
||||
id,
|
||||
company_id: context.company.id,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
throw Error("Drive item doesn't exist");
|
||||
|
||||
@@ -2,8 +2,8 @@ import SearchRepository from "../../../core/platform/services/search/repository"
|
||||
import { getLogger, logger, TdriveLogger } from "../../../core/platform/framework";
|
||||
import { CrudException, ListResult } from "../../../core/platform/framework/api/crud-service";
|
||||
import Repository, {
|
||||
inType,
|
||||
comparisonType,
|
||||
inType,
|
||||
} from "../../../core/platform/services/database/services/orm/repository/repository";
|
||||
import { PublicFile } from "../../../services/files/entities/file";
|
||||
import globalResolver from "../../../services/global-resolver";
|
||||
@@ -16,15 +16,15 @@ import {
|
||||
TYPE as DriveTdriveTabRepoType,
|
||||
} from "../entities/drive-tdrive-tab";
|
||||
import {
|
||||
DriveExecutionContext,
|
||||
CompanyExecutionContext,
|
||||
DocumentsMessageQueueRequest,
|
||||
DriveExecutionContext,
|
||||
DriveFileAccessLevel,
|
||||
DriveItemDetails,
|
||||
DriveTdriveTab,
|
||||
RootType,
|
||||
SearchDocumentsOptions,
|
||||
TrashType,
|
||||
CompanyExecutionContext,
|
||||
DriveTdriveTab,
|
||||
DriveFileAccessLevel,
|
||||
} from "../types";
|
||||
import {
|
||||
addDriveItemToArchive,
|
||||
@@ -783,7 +783,9 @@ export class DocumentsService {
|
||||
limitStr: "100",
|
||||
},
|
||||
$in: [
|
||||
["access_entities", [context.user.id, context.company.id]],
|
||||
...(options.onlyDirectlyShared
|
||||
? [["access_entities", [context.user.id, context.company.id]] as inType]
|
||||
: []),
|
||||
...(options.company_id ? [["company_id", [options.company_id]] as inType] : []),
|
||||
...(options.creator ? [["creator", [options.creator]] as inType] : []),
|
||||
...(options.mime_type
|
||||
@@ -819,24 +821,31 @@ export class DocumentsService {
|
||||
context,
|
||||
);
|
||||
|
||||
// Use Promise.all to check access on each item in parallel
|
||||
const filteredResult = await Promise.all(
|
||||
result.getEntities().filter(async item => {
|
||||
// if this flag is on, the access permissions were checked inside the database
|
||||
if (!options.onlyDirectlyShared) {
|
||||
const filteredResult = await this.filter(result.getEntities(), async item => {
|
||||
try {
|
||||
// Check access for each item
|
||||
const hasAccess = await checkAccess(item.id, null, "read", this.repository, context);
|
||||
// Return true if the user has access
|
||||
return hasAccess;
|
||||
return await checkAccess(item.id, null, "read", this.repository, context);
|
||||
} catch (error) {
|
||||
this.logger.warn("failed to check item access", error);
|
||||
return false;
|
||||
}
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
return new ListResult(result.type, filteredResult, result.nextPage);
|
||||
return new ListResult(result.type, filteredResult, result.nextPage);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
private async filter(arr, callback) {
|
||||
const fail = Symbol();
|
||||
return (
|
||||
await Promise.all(arr.map(async item => ((await callback(item)) ? item : fail)))
|
||||
).filter(i => i !== fail);
|
||||
}
|
||||
|
||||
getTab = async (tabId: string, context: CompanyExecutionContext): Promise<DriveTdriveTab> => {
|
||||
const tab = await this.driveTdriveTabRepository.findOne(
|
||||
{ company_id: context.company.id, tab_id: tabId },
|
||||
|
||||
@@ -47,6 +47,7 @@ export type SearchDocumentsOptions = {
|
||||
sort?: SortType;
|
||||
view?: string;
|
||||
fields?: string[];
|
||||
onlyDirectlyShared?: boolean;
|
||||
};
|
||||
|
||||
export type SearchDocumentsBody = {
|
||||
|
||||
@@ -55,6 +55,7 @@ export class DocumentsController {
|
||||
filename: q.resumableFilename || q.filename || file?.filename || undefined,
|
||||
type: q.resumableType || q.type || file?.mimetype || undefined,
|
||||
waitForThumbnail: !!q.thumbnail_sync,
|
||||
ignoreThumbnails: false,
|
||||
};
|
||||
|
||||
createdFile = await globalResolver.services.files.save(null, file, options, context);
|
||||
@@ -140,6 +141,35 @@ export class DocumentsController {
|
||||
};
|
||||
};
|
||||
|
||||
sharedWithMe = async (
|
||||
request: FastifyRequest<{
|
||||
Params: RequestParams;
|
||||
Body: SearchDocumentsBody;
|
||||
Querystring: { public_token?: string };
|
||||
}>,
|
||||
): Promise<ListResult<DriveFileDTO>> => {
|
||||
try {
|
||||
const context = getDriveExecutionContext(request);
|
||||
|
||||
const options: SearchDocumentsOptions = {
|
||||
...request.body,
|
||||
company_id: request.body.company_id || context.company.id,
|
||||
onlyDirectlyShared: true,
|
||||
};
|
||||
|
||||
if (!Object.keys(options).length) {
|
||||
this.throw500Search();
|
||||
}
|
||||
|
||||
const fileList = await globalResolver.services.documents.documents.search(options, context);
|
||||
|
||||
return this.driveFileDTOBuilder.build(fileList, context, options.fields, options.view);
|
||||
} catch (error) {
|
||||
logger.error({ error: `${error}` }, "error while searching for document");
|
||||
this.throw500Search();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return access level of a given user on a given item
|
||||
*/
|
||||
@@ -352,6 +382,7 @@ export class DocumentsController {
|
||||
const options: SearchDocumentsOptions = {
|
||||
...request.body,
|
||||
company_id: request.body.company_id || context.company.id,
|
||||
onlyDirectlyShared: false,
|
||||
};
|
||||
|
||||
if (!Object.keys(options).length) {
|
||||
|
||||
@@ -13,7 +13,27 @@ import { getSharedByUser } from "../../services/access-check";
|
||||
|
||||
export class DriveFileDTOBuilder {
|
||||
private views: Map<string, string[]> = new Map([
|
||||
["default", Object.getOwnPropertyNames(new DriveFile())],
|
||||
[
|
||||
"default",
|
||||
[
|
||||
"company_id",
|
||||
"id",
|
||||
"parent_id",
|
||||
"is_in_trash",
|
||||
"is_directory",
|
||||
"name",
|
||||
"extension",
|
||||
"description",
|
||||
"added",
|
||||
"last_modified",
|
||||
"size",
|
||||
"last_version_cache",
|
||||
"tags",
|
||||
"access_info",
|
||||
"content_keywords",
|
||||
"creator",
|
||||
],
|
||||
],
|
||||
[
|
||||
"shared_with_me",
|
||||
[
|
||||
@@ -39,6 +59,8 @@ export class DriveFileDTOBuilder {
|
||||
fields?: string[],
|
||||
view?: string,
|
||||
): Promise<ListResult<DriveFileDTO>> {
|
||||
const file = new DriveFile();
|
||||
file.id = "1";
|
||||
if (view) {
|
||||
fields = this.views.get(view);
|
||||
}
|
||||
|
||||
@@ -87,6 +87,13 @@ const routes: FastifyPluginCallback = (fastify: FastifyInstance, _options, next)
|
||||
handler: documentsController.search.bind(documentsController),
|
||||
});
|
||||
|
||||
fastify.route({
|
||||
method: "POST",
|
||||
url: `${baseUrl}/shared-with-me`,
|
||||
preValidation: [fastify.authenticate],
|
||||
handler: documentsController.sharedWithMe.bind(documentsController),
|
||||
});
|
||||
|
||||
fastify.route({
|
||||
method: "GET",
|
||||
url: `${baseUrl}/tabs/:tab_id`,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { logger, TwakeContext } from "../../../../../core/platform/framework";
|
||||
import { logger, TdriveContext } from "../../../../../core/platform/framework";
|
||||
import { PreviewClearMessageQueueRequest, PreviewMessageQueueCallback } from "../../../types";
|
||||
import gr from "../../../../global-resolver";
|
||||
import { MessageQueueHandler } from "../../../../../core/platform/services/message-queue/api";
|
||||
@@ -22,7 +22,7 @@ export class ClearProcessor
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
init?(context?: TwakeContext): Promise<this> {
|
||||
init?(context?: TdriveContext): Promise<this> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@ import {
|
||||
} from "../../../../../utils/mime";
|
||||
import { PreviewMessageQueueRequest, ThumbnailResult } from "../../../types";
|
||||
import { generateVideoPreview } from "./video";
|
||||
import { Initializable, TwakeServiceProvider } from "../../../../../core/platform/framework";
|
||||
import { Initializable, TdriveServiceProvider } from "../../../../../core/platform/framework";
|
||||
import { cleanFiles } from "../../../../../utils/files";
|
||||
|
||||
export class PreviewProcessService implements TwakeServiceProvider, Initializable {
|
||||
export class PreviewProcessService implements TdriveServiceProvider, Initializable {
|
||||
name: "PreviewProcessService";
|
||||
version: "1";
|
||||
|
||||
|
||||
@@ -125,10 +125,10 @@ async function getVideoDimensions(videoPath: string): Promise<{ width: number; h
|
||||
ffmpeg.ffprobe(videoPath, (err, metadata) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
const { width, height } = metadata.streams[0];
|
||||
resolve({ width, height });
|
||||
}
|
||||
|
||||
const { width, height } = metadata.streams[0];
|
||||
resolve({ width, height });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user