Merge pull request #4 from loadingthedev/support-shared-drive

Add support for Shared drive
This commit is contained in:
Arief Rachmawan
2023-09-25 22:03:59 +07:00
committed by GitHub
9 changed files with 84 additions and 132 deletions
@@ -37,10 +37,12 @@ export async function GET(
const _fileMeta = gdrive.files.get({
fileId: decryptData(data.id),
fields: "id, name, size, mimeType, webContentLink",
supportsAllDrives: gIndexConfig.apiConfig.isTeamDrive,
});
const _fileContent = gdrive.files.get(
{
fileId: decryptData(data.id),
supportsAllDrives: gIndexConfig.apiConfig.isTeamDrive,
alt: "media",
},
{ responseType: "stream" },
+24 -73
View File
@@ -3,90 +3,58 @@ import { drive_v3 } from "googleapis";
import { NextRequest, NextResponse } from "next/server";
import getSearchParams from "utils/apiHelper/getSearchParams";
import {
decryptData,
encryptData,
} from "utils/encryptionHelper/hash";
import { decryptData, encryptData } from "utils/encryptionHelper/hash";
import ExtendedError from "utils/extendedError";
import { gdriveFilesList } from "utils/gdrive";
import gdrive from "utils/gdriveInstance";
import { IGDriveFiles } from "types/api/files";
import {
APIGetFileResponse,
ErrorResponse,
} from "types/api/response";
import { APIGetFileResponse, ErrorResponse } from "types/api/response";
function isHiddenFile(name: string) {
return gIndexConfig.apiConfig.hiddenFiles.find((item) =>
name.startsWith(item),
)
? true
: false;
return gIndexConfig.apiConfig.hiddenFiles.find((item) => name.startsWith(item)) ? true : false;
}
function generateFileObject(
data: drive_v3.Schema$File,
): IGDriveFiles {
function generateFileObject(data: drive_v3.Schema$File): IGDriveFiles {
return {
mimeType: data.mimeType as string,
fileExtension: (data.fileExtension as string) ?? null,
encryptedId: encryptData(data.id as string),
name: data.name as string,
trashed: (data.trashed as boolean) ?? false,
modifiedTime: new Date(
data.modifiedTime as string,
).toLocaleDateString(),
encryptedWebContentLink: encryptData(
data.webContentLink as string,
),
modifiedTime: new Date(data.modifiedTime as string).toLocaleDateString(),
encryptedWebContentLink: encryptData(data.webContentLink as string),
size: Number(data.size ?? 0),
thumbnailLink: (data.thumbnailLink as string) ?? null,
imageMediaMetadata: data.imageMediaMetadata
? {
width: Number(data.imageMediaMetadata.width ?? 0),
height: Number(
data.imageMediaMetadata.height ?? 0,
),
rotation: Number(
data.imageMediaMetadata.rotation ?? 0,
),
height: Number(data.imageMediaMetadata.height ?? 0),
rotation: Number(data.imageMediaMetadata.rotation ?? 0),
}
: null,
videoMediaMetadata: data.videoMediaMetadata
? {
width: Number(data.videoMediaMetadata.width ?? 0),
height: Number(
data.videoMediaMetadata.height ?? 0,
),
durationMillis: Number(
data.videoMediaMetadata.durationMillis ?? 0,
),
height: Number(data.videoMediaMetadata.height ?? 0),
durationMillis: Number(data.videoMediaMetadata.durationMillis ?? 0),
}
: null,
};
}
function generateFolderObject(
data: drive_v3.Schema$File,
): IGDriveFiles {
function generateFolderObject(data: drive_v3.Schema$File): IGDriveFiles {
return {
mimeType: data.mimeType as string,
encryptedId: encryptData(data.id as string),
name: data.name as string,
trashed: (data.trashed as boolean) ?? false,
modifiedTime: new Date(
data.modifiedTime as string,
).toLocaleDateString(),
modifiedTime: new Date(data.modifiedTime as string).toLocaleDateString(),
};
}
export async function GET(request: NextRequest) {
const reqStart = Date.now();
try {
const { encryptedId, isFile, pageToken } =
getSearchParams(request.url, [
"encryptedId",
"isFile",
"pageToken",
]);
const { encryptedId, isFile, pageToken } = getSearchParams(request.url, ["encryptedId", "isFile", "pageToken"]);
let data: {
file: IGDriveFiles | null;
@@ -103,54 +71,37 @@ export async function GET(request: NextRequest) {
const fileContent = await gdrive.files.get({
fileId: decryptData(encryptedId),
fields: gIndexConfig.apiConfig.defaultField,
supportsAllDrives: gIndexConfig.apiConfig.isTeamDrive,
});
if (isHiddenFile(fileContent.data.name as string))
throw new ExtendedError(
"File not found",
404,
"File you are looking for is not found",
);
throw new ExtendedError("File not found", 404, "File you are looking for is not found");
const payload: IGDriveFiles = generateFileObject(
fileContent.data,
);
const payload: IGDriveFiles = generateFileObject(fileContent.data);
data.file = payload;
} else {
const filterName = gIndexConfig.apiConfig.hiddenFiles
.map((item) => `name != '${item}'`)
.join(" and ");
const filterName = gIndexConfig.apiConfig.hiddenFiles.map((item) => `name != '${item}'`).join(" and ");
const query: string[] = [
...gIndexConfig.apiConfig.defaultQuery,
`'${
encryptedId
? decryptData(encryptedId)
: gIndexConfig.apiConfig.rootFolder
}' in parents`,
`'${encryptedId ? decryptData(encryptedId) : gIndexConfig.apiConfig.rootFolder}' in parents`,
`${filterName}`,
];
const folderContent = await gdrive.files.list({
const folderContent = await gdriveFilesList({
q: query.join(" and "),
fields: `files(${gIndexConfig.apiConfig.defaultField}), nextPageToken`,
orderBy: gIndexConfig.apiConfig.defaultOrder,
pageSize: gIndexConfig.apiConfig.itemsPerPage,
pageToken: pageToken ?? undefined,
supportsAllDrives: gIndexConfig.apiConfig.isTeamDrive,
includeItemsFromAllDrives: gIndexConfig.apiConfig.isTeamDrive,
});
const listFolders: IGDriveFiles[] =
folderContent.data.files
?.filter(
(item) =>
item.mimeType ===
"application/vnd.google-apps.folder",
)
?.filter((item) => item.mimeType === "application/vnd.google-apps.folder")
.map((item) => generateFolderObject(item)) ?? [];
const listFiles: IGDriveFiles[] =
folderContent.data.files
?.filter(
(item) =>
item.mimeType !==
"application/vnd.google-apps.folder",
)
?.filter((item) => item.mimeType !== "application/vnd.google-apps.folder")
.map((item) => generateFileObject(item)) ?? [];
data = {
+13 -39
View File
@@ -2,52 +2,32 @@ import gIndexConfig from "config";
import { NextRequest, NextResponse } from "next/server";
import getSearchParams from "utils/apiHelper/getSearchParams";
import {
decryptData,
encryptData,
} from "utils/encryptionHelper/hash";
import { decryptData, encryptData } from "utils/encryptionHelper/hash";
import ExtendedError from "utils/extendedError";
import { gdriveFilesList } from "utils/gdrive";
import gdrive from "utils/gdriveInstance";
import {
APIGetPasswordResponse,
ErrorResponse,
} from "types/api/response";
import { APIGetPasswordResponse, ErrorResponse } from "types/api/response";
export async function GET(request: NextRequest) {
const reqStart = Date.now();
try {
const { path } = getSearchParams(request.url, ["path"]);
if (!path)
throw new ExtendedError(
"Path is required",
400,
"Can't find path in query, please check your query",
);
const mappedPath: Record<
"name" | "id" | "mimeType",
string
>[] = JSON.parse(decryptData(path));
const passwordParents = mappedPath.map(
(path) => `'${decryptData(path.id)}' in parents`,
);
if (!path) throw new ExtendedError("Path is required", 400, "Can't find path in query, please check your query");
const mappedPath: Record<"name" | "id" | "mimeType", string>[] = JSON.parse(decryptData(path));
const passwordParents = mappedPath.map((path) => `'${decryptData(path.id)}' in parents`);
const query: string[] = [
"trashed = false",
`name = '${
gIndexConfig.apiConfig.specialFile.password
}' and (${passwordParents.join(" or ")})`,
`name = '${gIndexConfig.apiConfig.specialFile.password}' and (${passwordParents.join(" or ")})`,
];
const passwordData = await gdrive.files.list({
const passwordData = await gdriveFilesList({
q: query.join(" and "),
fields: "files(id, name, parents)",
});
const protectedPaths = mappedPath.map((path) => {
const isPasswordExist = passwordData.data.files?.find(
(file) =>
file.parents?.[0] === decryptData(path.id),
);
const isPasswordExist = passwordData.data.files?.find((file) => file.parents?.[0] === decryptData(path.id));
if (isPasswordExist)
return {
name: path.name,
@@ -67,6 +47,7 @@ export async function GET(request: NextRequest) {
{
fileId: path.passwordId as string,
alt: "media",
supportsAllDrives: gIndexConfig.apiConfig.isTeamDrive,
},
{ responseType: "text" },
)
@@ -77,21 +58,14 @@ export async function GET(request: NextRequest) {
);
});
const passwordContent = await Promise.all(
_passwordContent,
);
const passwordContent = await Promise.all(_passwordContent);
let prevPath = [""];
let password: Record<
"relativePath" | "password",
string
>[] = [];
let password: Record<"relativePath" | "password", string>[] = [];
mappedPath.forEach((path) => {
prevPath.push(path.name);
const isPasswordExist = passwordContent.find(
(password) => password.path === path.name,
);
const isPasswordExist = passwordContent.find((password) => password.path === path.name);
if (isPasswordExist) {
password.push({
relativePath: prevPath.join("/"),
+6 -16
View File
@@ -3,29 +3,21 @@ import { NextRequest, NextResponse } from "next/server";
import getSearchParams from "utils/apiHelper/getSearchParams";
import { decryptData } from "utils/encryptionHelper/hash";
import { gdriveFilesList } from "utils/gdrive";
import gdrive from "utils/gdriveInstance";
import {
APIGetReadmeResponse,
ErrorResponse,
} from "types/api/response";
import { APIGetReadmeResponse, ErrorResponse } from "types/api/response";
export async function GET(request: NextRequest) {
const reqStart = Date.now();
try {
const { encryptedId } = getSearchParams(request.url, [
"encryptedId",
]);
const { encryptedId } = getSearchParams(request.url, ["encryptedId"]);
const query: string[] = [
...gIndexConfig.apiConfig.defaultQuery,
`'${
encryptedId
? decryptData(encryptedId)
: gIndexConfig.apiConfig.rootFolder
}' in parents`,
`'${encryptedId ? decryptData(encryptedId) : gIndexConfig.apiConfig.rootFolder}' in parents`,
];
const folderContent = await gdrive.files.list({
const folderContent = await gdriveFilesList({
q: query.join(" and "),
fields: `files(${gIndexConfig.apiConfig.defaultField}), nextPageToken`,
orderBy: gIndexConfig.apiConfig.defaultOrder,
@@ -33,9 +25,7 @@ export async function GET(request: NextRequest) {
pageToken: undefined,
});
const isReadmeExist = folderContent.data.files?.find(
(file) =>
file.name ===
gIndexConfig.apiConfig.specialFile.readme,
(file) => file.name === gIndexConfig.apiConfig.specialFile.readme,
);
let data: string | null = null;
@@ -20,6 +20,7 @@ export async function GET(request: NextRequest, { params }: { params: { encrypte
const fileContent = await gdrive.files.get({
fileId: lastId,
fields: "id, name, mimeType, parents",
supportsAllDrives: gIndexConfig.apiConfig.isTeamDrive,
});
if (fileContent) {
path.push(fileContent.data.name as string);
@@ -29,6 +30,7 @@ export async function GET(request: NextRequest, { params }: { params: { encrypte
const folderContent = await gdrive.files.get({
fileId: lastId,
fields: "id, name, mimeType, parents",
supportsAllDrives: gIndexConfig.apiConfig.isTeamDrive,
});
if (folderContent.data.id === gIndexConfig.apiConfig.rootFolder) {
lastId = "";
+2 -2
View File
@@ -4,7 +4,7 @@ import { NextRequest, NextResponse } from "next/server";
import getSearchParams from "utils/apiHelper/getSearchParams";
import { encryptData } from "utils/encryptionHelper/hash";
import ExtendedError from "utils/extendedError";
import gdrive from "utils/gdriveInstance";
import { gdriveFilesList } from "utils/gdrive";
import { IGDriveFiles } from "types/api/files";
import { APISearchResponse, ErrorResponse } from "types/api/response";
@@ -15,7 +15,7 @@ export async function GET(request: NextRequest) {
const { query } = getSearchParams(request.url, ["query"]);
if (!query) throw new ExtendedError("Missing query", 400, "Search query is required");
const searchFiles = await gdrive.files.list({
const searchFiles = await gdriveFilesList({
q: [...gIndexConfig.apiConfig.defaultQuery, `name contains '${query}'`].join(" and "),
fields: `files(${gIndexConfig.apiConfig.defaultField}), nextPageToken`,
orderBy: "name_natural desc",
+2 -1
View File
@@ -40,7 +40,7 @@ const config: gIndexConfig = {
* Then, copy the folder id and paste it here
*/
rootFolder: "1KgPV6QB1GYT8fmn2uTfbtr9rDXqcRR0j",
isTeamDrive: false, // Set this to true if you're using Team Drive
defaultQuery: ["trashed = false", "(not mimeType contains 'google-apps' or mimeType contains 'folder')"],
defaultField:
"id, name, mimeType, thumbnailLink, fileExtension, modifiedTime, size, imageMediaMetadata, videoMediaMetadata, webContentLink, trashed",
@@ -165,6 +165,7 @@ interface gIndexConfig {
apiConfig: {
rootFolder: string;
isTeamDrive: boolean;
defaultQuery: string[];
defaultField: string;
defaultOrder: string;
+3 -1
View File
@@ -10,6 +10,7 @@ import PasswordLayout from "components/Layout/Password";
import PreviewLayout from "components/Layout/Preview";
import { decryptData, encryptData } from "utils/encryptionHelper/hash";
import { gdriveFilesList } from "utils/gdrive";
import gdrive from "utils/gdriveInstance";
import { addNewPassword, checkPathPassword } from "utils/passwordHelper";
@@ -196,10 +197,11 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
const fetchRootId = gdrive.files.get({
fileId: gIndexConfig.apiConfig.rootFolder,
fields: "id",
supportsAllDrives: gIndexConfig.apiConfig.isTeamDrive,
});
const fetchPathId = path.map(async (path) => {
const query = ["trashed = false", `name = '${path}'`];
const fetchFolderContents = await gdrive.files.list({
const fetchFolderContents = await gdriveFilesList({
q: `${query.join(" and ")}`,
fields: "files(id, name, mimeType, parents)",
});
+30
View File
@@ -0,0 +1,30 @@
import gIndexConfig from "config";
import { GaxiosResponse } from "gaxios";
import type { drive_v3 } from "googleapis";
import gdrive from "utils/gdriveInstance";
interface ListFiles extends drive_v3.Params$Resource$Files$List {}
export async function gdriveFilesList({
q,
fields,
orderBy,
pageSize,
pageToken,
}: ListFiles): Promise<GaxiosResponse<drive_v3.Schema$FileList>> {
const result = await gdrive.files.list({
q,
fields,
orderBy,
pageSize,
pageToken,
...(gIndexConfig.apiConfig.isTeamDrive && {
supportsAllDrives: true,
includeItemsFromAllDrives: true,
driveId: gIndexConfig.apiConfig.rootFolder,
corpora: "drive",
}),
});
return result;
}