Remove unused folder

This commit is contained in:
mbaharip
2023-05-08 10:13:48 +07:00
parent 153047de55
commit 03f56d4402
11 changed files with 0 additions and 1160 deletions
-67
View File
@@ -1,67 +0,0 @@
import initMiddleware from "utils/apiMiddleware";
import { NextApiRequest, NextApiResponse } from "next";
import { ErrorResponse } from "types/googleapis";
import driveClient from "utils/driveClient";
import { ExtendedError } from "utils/driveHelper";
import apiConfig from "config/api.config";
export default initMiddleware(async function handler(
request: NextApiRequest,
response: NextApiResponse,
) {
const _start = Date.now();
try {
const { id, fileName } = request.query;
const getFileMetadata = await driveClient.files.get({
fileId: id as string,
fields: "name, mimeType, size, webContentLink",
});
if (
getFileMetadata.data.name !== decodeURIComponent(fileName as string) ||
getFileMetadata.data.mimeType?.startsWith("application/vnd.google-apps")
) {
throw new ExtendedError("File not found", 404, "notFound");
}
if (Number(getFileMetadata.data.size) > apiConfig.maxResponseSize) {
return response
.status(301)
.redirect(getFileMetadata.data.webContentLink as string);
}
const getFileStream = await driveClient.files.get(
{
fileId: id as string,
alt: "media",
},
{ responseType: "stream" },
);
response.setHeader(
"Content-Type",
getFileMetadata.data.mimeType || "application/octet-stream",
);
response.setHeader(
"Content-Disposition",
`attachment; filename=${encodeURIComponent(
getFileMetadata.data.name as string,
)}`,
);
return response.status(200).send(getFileStream.data);
} catch (error: any) {
const payload: ErrorResponse = {
success: false,
timestamp: new Date().toISOString(),
responseTime: Date.now() - _start,
code: error.code || 500,
errors: {
message: error.errors?.[0].message || error.message || "Unknown error",
reason: error.errors?.[0].reason || error.cause || "internalError",
},
};
return response.status(payload.code || 500).json(payload);
}
});
-130
View File
@@ -1,130 +0,0 @@
import { ErrorResponse, FileResponse, TFileParent } from "@/types/googleapis";
import drive from "@utils/driveClient";
import { NextApiRequest, NextApiResponse } from "next";
import config from "@config/site.config";
import { validateProtected } from "@utils/driveHelper";
import { ExtendedError } from "@/types/default";
import { reverseString } from "@utils/hashHelper";
import initMiddleware from "@utils/apiMiddleware";
async function handler(request: NextApiRequest, response: NextApiResponse) {
try {
const { id, hash } = request.query;
const { authorization } = request.headers;
const headerHash = authorization?.split(" ")[1] || null;
const fetchFileMetadata = await drive.files.get({
fileId: id as string,
fields: "id, name, mimeType, size, exportLinks, parents",
});
if (!config.files.allowDownloadProtectedWithoutAccess) {
const parentsArray: TFileParent[] = [];
let validHash = headerHash as string;
if (hash) {
validHash = reverseString(hash as string);
}
// Fetch parents
if (
fetchFileMetadata.data.mimeType === "application/vnd.google-apps.folder"
) {
parentsArray.push({
id: fetchFileMetadata.data.id as string,
name: fetchFileMetadata.data.name as string,
});
}
let parents = fetchFileMetadata.data.parents || [];
while (parents.length > 0) {
const fetchParents = await drive.files.get({
fileId: parents[0],
fields: "id, name, parents",
});
if (fetchParents.data.id === config.files.rootFolder) {
parentsArray.push({
id: fetchParents.data.id as string,
name: fetchParents.data.name as string,
});
break;
}
parents = fetchParents.data.parents || [];
if (!parents.length) break;
parentsArray.push({
id: fetchParents.data.id as string,
name: fetchParents.data.name as string,
});
}
// Check for password file
const validatePassword = await validateProtected(parentsArray, validHash);
if (validatePassword.isProtected && !validatePassword.valid) {
return response.status(200).json({
success: true,
timestamp: new Date().toISOString(),
passwordRequired: true,
passwordValidated: false,
parents: [],
file: {},
} as FileResponse);
}
}
const { name, mimeType, size } = fetchFileMetadata.data;
if (mimeType === "application/vnd.google-apps.folder") {
const error = new Error("Folder cannot be downloaded") as ExtendedError;
error.cause = "badRequest";
error.code = 400;
throw error;
}
response.setHeader(
"Content-Disposition",
`attachment; filename=${encodeURIComponent(name as string)}`,
);
response.setHeader("Content-Type", mimeType || "application/octet-stream");
response.setHeader("Content-Length", size || 0);
const streamFile = await drive.files.get(
{
fileId: id as string,
alt: "media",
},
{
responseType: "stream",
},
);
return response.send(streamFile.data);
} catch (error: any) {
if (error satisfies ErrorResponse) {
const payload: ErrorResponse = {
success: false,
timestamp: new Date().toISOString(),
code: error.code || 500,
errors: {
message:
error.errors?.[0].message || error.message || "Unknown error",
reason: error.errors?.[0].reason || error.cause || "internalError",
},
};
return response.status(error.code).json(payload);
}
const payload: ErrorResponse = {
success: false,
timestamp: new Date().toISOString(),
code: error.code || 500,
errors: {
message: error.message || "Unknown error",
reason: error.cause || "internalError",
},
};
return response.status(500).json(payload);
}
}
export default initMiddleware(handler);
-171
View File
@@ -1,171 +0,0 @@
import {
ErrorResponse,
FileResponse,
FilesResponse,
TFileParent,
} from "types/googleapis";
import drive from "utils/driveClient";
import {} from "utils/driveHelper";
import { NextApiRequest, NextApiResponse } from "next";
import config from "config/site.config";
export default async function handler(
request: NextApiRequest,
response: NextApiResponse<FilesResponse | FileResponse | ErrorResponse>,
) {
try {
const _start = Date.now();
const { id } = request.query;
const { authorization } = request.headers;
const hash = authorization?.split(" ")[1] || null;
const parentsArray: TFileParent[] = [];
const fetchFile = await drive.files.get({
fileId: id as string,
fields:
"id, name, mimeType, parents, thumbnailLink, fileExtension, createdTime, modifiedTime, size, imageMediaMetadata, videoMediaMetadata, exportLinks",
});
// Fetch parents
if (fetchFile.data.mimeType === "application/vnd.google-apps.folder") {
parentsArray.push({
id: fetchFile.data.id as string,
name: fetchFile.data.name as string,
});
}
let parents = fetchFile.data.parents || [];
while (parents.length > 0) {
const fetchParents = await drive.files.get({
fileId: parents[0],
fields: "id, name, parents",
});
if (fetchParents.data.id === config.files.rootFolder) {
parentsArray.push({
id: fetchParents.data.id as string,
name: fetchParents.data.name as string,
});
break;
}
parents = fetchParents.data.parents || [];
if (!parents.length) break;
parentsArray.push({
id: fetchParents.data.id as string,
name: fetchParents.data.name as string,
});
}
// Check for password file
const validatePassword = await validateProtected(
parentsArray || (id as string),
hash as string,
);
if (validatePassword.isProtected && !validatePassword.valid) {
return response.status(200).json({
success: true,
timestamp: new Date().toISOString(),
passwordRequired: true,
passwordValidated: false,
protectedId: validatePassword.protectedId,
parents: [],
file: {},
} as FileResponse);
}
// Check if file is folder
if (fetchFile.data.mimeType === "application/vnd.google-apps.folder") {
const { pageToken } = request.query;
const fetchFiles = await drive.files.list({
q: buildQuery({
id: id as string,
extraQuery: ["not mimeType contains 'application/vnd.google-apps'"],
}),
fields:
"files(id, name, mimeType, thumbnailLink, fileExtension, createdTime, modifiedTime, size, videoMediaMetadata), nextPageToken",
orderBy: "folder, name asc",
pageSize: config.files.itemsPerPage,
pageToken: (pageToken as string) || undefined,
});
const fetchFolders = await drive.files.list({
q: buildQuery({
id: id as string,
extraQuery: ["mimeType = 'application/vnd.google-apps.folder'"],
}),
fields:
"files(id, name, mimeType, thumbnailLink, fileExtension, createdTime, modifiedTime, size, videoMediaMetadata), nextPageToken",
orderBy: "folder, name asc",
pageSize: config.files.itemsPerPage,
pageToken: (pageToken as string) || undefined,
});
const checkReadme = await drive.files.list({
q: buildQuery({ id: id as string, extraQuery: ["name = 'readme.md'"] }),
});
const folders =
fetchFolders.data.files?.filter(
(file) => file.mimeType === "application/vnd.google-apps.folder",
) || [];
const files =
fetchFiles.data.files?.filter(
(file) => file.mimeType !== "application/vnd.google-apps.folder",
) || [];
const payload: FilesResponse = {
success: true,
timestamp: new Date().toISOString(),
parents: parentsArray,
passwordRequired: validatePassword.isProtected,
passwordValidated: validatePassword.valid,
protectedId: validatePassword.protectedId,
folders,
files,
nextPageToken: fetchFiles.data.nextPageToken || undefined,
readmeExists: !!checkReadme.data.files?.length,
};
return response.status(200).json(payload);
}
const payload: FileResponse = {
success: true,
timestamp: new Date().toISOString(),
parents: parentsArray,
passwordRequired: validatePassword.isProtected,
passwordValidated: validatePassword.valid,
protectedId: validatePassword.protectedId,
file: fetchFile.data,
};
return response.status(200).json(payload);
} catch (error: any) {
if (error satisfies ErrorResponse) {
const payload: ErrorResponse = {
success: false,
timestamp: new Date().toISOString(),
code: error.code || 500,
errors: {
message:
error.errors?.[0].message || error.message || "Unknown error",
reason: error.errors?.[0].reason || error.cause || "internalError",
},
};
return response.status(error.code).json(payload);
}
const payload: ErrorResponse = {
success: false,
timestamp: new Date().toISOString(),
code: error.code || 500,
errors: {
message: error.message || "Unknown error",
reason: error.cause || "internalError",
},
};
return response.status(500).json(payload);
}
}
-131
View File
@@ -1,131 +0,0 @@
import { ErrorResponse, FileResponse, TFileParent } from "@/types/googleapis";
import drive from "@utils/driveClient";
import { NextApiRequest, NextApiResponse } from "next";
import config from "@config/site.config";
import { validateProtected } from "@utils/driveHelper";
import { ExtendedError } from "@/types/default";
import { reverseString } from "@utils/hashHelper";
export default async function handler(
request: NextApiRequest,
response: NextApiResponse,
) {
try {
const { id, hash } = request.query;
const { authorization } = request.headers;
const headerHash = authorization?.split(" ")[1] || null;
const fetchFileMetadata = await drive.files.get({
fileId: id as string,
fields: "id, name, mimeType, size, exportLinks, parents",
});
if (!config.files.allowDownloadProtectedWithoutAccess) {
const parentsArray: TFileParent[] = [];
let validHash = headerHash as string;
if (hash) {
validHash = reverseString(hash as string);
}
// Fetch parents
if (
fetchFileMetadata.data.mimeType === "application/vnd.google-apps.folder"
) {
parentsArray.push({
id: fetchFileMetadata.data.id as string,
name: fetchFileMetadata.data.name as string,
});
}
let parents = fetchFileMetadata.data.parents || [];
while (parents.length > 0) {
const fetchParents = await drive.files.get({
fileId: parents[0],
fields: "id, name, parents",
});
if (fetchParents.data.id === config.files.rootFolder) {
parentsArray.push({
id: fetchParents.data.id as string,
name: fetchParents.data.name as string,
});
break;
}
parents = fetchParents.data.parents || [];
if (!parents.length) break;
parentsArray.push({
id: fetchParents.data.id as string,
name: fetchParents.data.name as string,
});
}
// Check for password file
const validatePassword = await validateProtected(parentsArray, validHash);
if (validatePassword.isProtected && !validatePassword.valid) {
return response.status(200).json({
success: true,
timestamp: new Date().toISOString(),
passwordRequired: true,
passwordValidated: false,
parents: [],
file: {},
} as FileResponse);
}
}
const { name, mimeType, size } = fetchFileMetadata.data;
if (mimeType === "application/vnd.google-apps.folder") {
const error = new Error("Folder cannot be downloaded") as ExtendedError;
error.cause = "badRequest";
error.code = 400;
throw error;
}
response.setHeader(
"Content-Disposition",
`inline; filename=${encodeURIComponent(name as string)}`,
);
response.setHeader("Content-Type", mimeType || "application/octet-stream");
response.setHeader("Content-Length", size || 0);
const streamFile = await drive.files.get(
{
fileId: id as string,
alt: "media",
},
{
responseType: "stream",
},
);
return response.send(streamFile.data);
} catch (error: any) {
if (error satisfies ErrorResponse) {
const payload: ErrorResponse = {
success: false,
timestamp: new Date().toISOString(),
code: error.code || 500,
errors: {
message:
error.errors?.[0].message || error.message || "Unknown error",
reason: error.errors?.[0].reason || error.cause || "internalError",
},
};
return response.status(error.code).json(payload);
}
const payload: ErrorResponse = {
success: false,
timestamp: new Date().toISOString(),
code: error.code || 500,
errors: {
message: error.message || "Unknown error",
reason: error.cause || "internalError",
},
};
return response.status(500).json(payload);
}
}
-110
View File
@@ -1,110 +0,0 @@
import { ErrorResponse, FilesResponse } from "@/types/googleapis";
import drive from "@/utils/driveClient";
import { buildQuery, validateProtected } from "@/utils/driveHelper";
import { NextApiRequest, NextApiResponse } from "next";
import config from "@config/site.config";
export default async function handler(
request: NextApiRequest,
response: NextApiResponse<FilesResponse | ErrorResponse>,
) {
try {
const { pageToken } = request.query;
const { authorization } = request.headers;
const hash = authorization?.split(" ")[1] || null;
// Check for password file
const validatePassword = await validateProtected(
config.files.rootFolder,
hash as string,
);
if (validatePassword.isProtected && !validatePassword.valid) {
return response.status(200).json({
success: true,
timestamp: new Date().toISOString(),
passwordRequired: true,
passwordValidated: false,
protectedId: config.files.rootFolder,
parents: [],
files: [],
folders: [],
nextPageToken: undefined,
readmeExists: false,
});
}
const fetchFiles = await drive.files.list({
q: buildQuery({
extraQuery: ["not mimeType contains 'application/vnd.google-apps'"],
}),
fields:
"files(id, name, mimeType, thumbnailLink, fileExtension, createdTime, modifiedTime, size, videoMediaMetadata), nextPageToken",
orderBy: "folder, name asc",
pageSize: config.files.itemsPerPage,
pageToken: (pageToken as string) || undefined,
});
const fetchFolders = await drive.files.list({
q: buildQuery({
extraQuery: ["mimeType = 'application/vnd.google-apps.folder'"],
}),
fields:
"files(id, name, mimeType, thumbnailLink, fileExtension, createdTime, modifiedTime, size, videoMediaMetadata), nextPageToken",
orderBy: "folder, name asc",
pageSize: config.files.itemsPerPage,
pageToken: (pageToken as string) || undefined,
});
const checkReadme = await drive.files.list({
q: buildQuery({ extraQuery: ["name = 'readme.md'"] }),
});
const folders =
fetchFolders.data.files?.filter(
(file) => file.mimeType === "application/vnd.google-apps.folder",
) || [];
const files =
fetchFiles.data.files?.filter(
(file) => file.mimeType !== "application/vnd.google-apps.folder",
) || [];
const payload: FilesResponse = {
success: true,
timestamp: new Date().toISOString(),
passwordRequired: validatePassword.isProtected,
passwordValidated: validatePassword.valid,
protectedId: validatePassword.protectedId,
folders,
files,
nextPageToken: fetchFiles.data.nextPageToken || undefined,
readmeExists: !!checkReadme.data.files?.length,
};
return response.status(200).json(payload);
} catch (error: any) {
if (error satisfies ErrorResponse) {
const payload: ErrorResponse = {
success: false,
timestamp: new Date().toISOString(),
code: error.code || 500,
errors: {
message:
error.errors?.[0].message || error.message || "Unknown error",
reason: error.errors?.[0].reason || error.cause || "internalError",
},
};
return response.status(error.code).json(payload);
}
const payload: ErrorResponse = {
success: false,
timestamp: new Date().toISOString(),
code: error.code || 500,
errors: {
message: error.message || "Unknown error",
reason: error.cause || "internalError",
},
};
return response.status(500).json(payload);
}
}
-68
View File
@@ -1,68 +0,0 @@
import { ErrorResponse, SearchResponse } from "@/types/googleapis";
import drive from "@/utils/driveClient";
import { buildQuery } from "@/utils/driveHelper";
import { NextApiRequest, NextApiResponse } from "next";
import config from "@config/site.config";
export default async function handler(
request: NextApiRequest,
response: NextApiResponse<SearchResponse | ErrorResponse>,
) {
try {
const { query } = request.query;
if (!query) {
const payload: SearchResponse = {
success: true,
timestamp: new Date().toISOString(),
files: [],
};
return response.status(200).json(payload);
}
const fetchFiles = await drive.files.list({
q: buildQuery({
extraQuery: [`name contains '${query}'`],
globalSearch: true,
}),
fields:
"files(id, name, mimeType, thumbnailLink, fileExtension, createdTime, modifiedTime, size)",
pageSize: config.files.searchResult,
});
const payload: SearchResponse = {
success: true,
timestamp: new Date().toISOString(),
files: fetchFiles.data.files || [],
};
return response.status(200).json(payload);
} catch (error: any) {
if (error satisfies ErrorResponse) {
const payload: ErrorResponse = {
success: false,
timestamp: new Date().toISOString(),
code: error.code || 500,
errors: {
message:
error.errors?.[0].message || error.message || "Unknown error",
reason: error.errors?.[0].reason || error.cause || "internalError",
},
};
return response.status(error.code).json(payload);
}
const payload: ErrorResponse = {
success: false,
timestamp: new Date().toISOString(),
code: error.code || 500,
errors: {
message: error.message || "Unknown error",
reason: error.cause || "internalError",
},
};
return response.status(500).json(payload);
}
}
-54
View File
@@ -1,54 +0,0 @@
import { promisify } from "util";
import { pipeline } from "stream";
import { GetServerSideProps } from "next";
import drive from "utils/driveClient";
export default function Media() {
return <div />;
}
const pipelineAsync = promisify(pipeline);
export const getServerSideProps: GetServerSideProps = async ({
res,
query,
}) => {
const { id, fileName } = query;
const getImageMetadata = drive.files.get({
fileId: id as string,
fields: "name, mimeType",
});
const getImageStream = drive.files.get(
{
fileId: id as string,
alt: "media",
},
{ responseType: "stream" },
);
const [{ data: imageMetadata }, imageStream] = await Promise.all([
getImageMetadata,
getImageStream,
]);
// Only allow images, video, audio, and pdf
if (
!(imageMetadata.mimeType as string).startsWith("image/") &&
!(imageMetadata.mimeType as string).startsWith("video/") &&
!(imageMetadata.mimeType as string).startsWith("audio/")
) {
return {
notFound: true,
};
}
// Check fileName === image metadata
if (fileName !== imageMetadata.name) {
return {
notFound: true,
};
}
res.setHeader("Content-Type", imageMetadata.mimeType as string);
await pipelineAsync(imageStream.data, res);
return {
props: {},
};
};
-146
View File
@@ -1,146 +0,0 @@
import { MdWarning } from "react-icons/md";
import { useEffect, useState } from "react";
import {
createEncryptionKey,
generateRandomEncryptionKey,
} from "utils/encryptionHelper";
import useCopyText from "hooks/useCopyText";
import { toast } from "react-toastify";
import Link from "next/link";
import useLocalStorage from "hooks/useLocalStorage";
export default function Encryption() {
const [settingJson, setSettingJson] = useLocalStorage("tempEncryption", "");
const [key, setKey] = useState<string>("");
const [allowNext, setAllowNext] = useState<boolean>(false);
const copyText = useCopyText();
useEffect(() => {
if (settingJson) {
setKey(settingJson);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (key) {
setAllowNext(true);
} else {
setAllowNext(false);
}
}, [key]);
return (
<div className='mx-auto flex max-w-screen-xl flex-col gap-4'>
<div className={"card"}>
<div className='flex w-full items-center justify-between rounded-lg px-4'>
<span className='font-bold'>Encryption key</span>
</div>
<div className={"divider-horizontal"} />
<div className={"banner warning"}>
<MdWarning className={"h-6 w-6 text-red-500"} />
<span>
Make sure you don&apos;t share your encryption key with anyone.
</span>
</div>
<p className={"mx-auto max-w-screen-md px-4 py-4 text-center"}>
On this page you can generate a random encryption key, or you can
define your own.
<br />
This key will be used to encrypt your files.
<br />
<br />
You can also copy the key to your clipboard and save it somewhere
safe.
</p>
<div
className={"mx-auto flex w-full max-w-screen-md flex-col gap-4 px-4"}
>
<div className={"flex flex-col gap-2"}>
<span className='font-bold'>Encryption key</span>
<input
type={"text"}
className={"pr-4"}
value={key}
onChange={(e) => setKey(e.target.value)}
placeholder={"Enter your encryption key here..."}
/>
</div>
<div className={"mx-auto grid w-full max-w-md grid-cols-2 gap-2"}>
<button
className={"primary flex w-full items-center justify-center"}
onClick={(e) => {
e.preventDefault();
generateRandomEncryptionKey()
.then((key) => {
setKey(key);
})
.catch((err) => {
toast.error("Failed to generate encryption key");
console.error(err);
});
}}
>
Generate
</button>
<button
className={"danger flex w-full items-center justify-center"}
onClick={(e) => {
e.preventDefault();
setKey("");
}}
>
Reset
</button>
<button
className={
"secondary col-span-full flex w-full items-center justify-center"
}
onClick={(e) => {
e.preventDefault();
copyText(key);
}}
>
Copy
</button>
</div>
</div>
<div className={"divider-horizontal"} />
<div
className={
"mx-auto flex w-full items-center justify-end gap-2 tablet:gap-4"
}
>
<Link href={"/setup"}>
<button className={"secondary"}>Previous Page</button>
</Link>
<Link
href={allowNext ? "/setup/google-cloud" : ""}
onClick={async () => {
if (!allowNext) return;
if (!key) return;
createEncryptionKey(key).then((encryptionKey) => {
setSettingJson(encryptionKey);
});
}}
>
<button
className={"primary"}
disabled={!allowNext}
>
Next Page
</button>
</Link>
</div>
</div>
</div>
);
}
-104
View File
@@ -1,104 +0,0 @@
import Link from "next/link";
import LoadingFeedback from "components/APIFeedback/Loading";
import MarkdownRender from "components/utility/MarkdownRender";
import useLocalStorage from "hooks/useLocalStorage";
import { useEffect, useState } from "react";
type ConfigProps = {
client_id: string;
client_secret: string;
refresh_token: string;
};
const defaultConfig: ConfigProps = {
client_id: "",
client_secret: "",
refresh_token: "",
};
export default function SetupFinal() {
const [isLoading, setIsLoading] = useState<boolean>(true);
const [tempKey] = useLocalStorage("tempEncryption", "");
const [tempConfig] = useLocalStorage<ConfigProps>(
"tempGoogleCloud",
defaultConfig,
);
const [dataConfig, setDataConfig] = useState<ConfigProps>(defaultConfig);
const [dataKey, setDataKey] = useState<string>("");
const [mdContent, setMdContent] = useState<string>("");
useEffect(() => {
setIsLoading(true);
if (tempConfig) {
setDataConfig(tempConfig);
}
if (tempKey) {
setDataKey(tempKey);
}
setIsLoading(false);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
setIsLoading(true);
const mdContent = `To finishing the setup, you need to do the following steps:
## API Config
The API Config file are located at \`src/config/api.ts\`. You need to fill in the following information:
\`\`\`js
module.exports = {
client_id: "${dataConfig.client_id}",
client_secret: "${dataConfig.client_secret}",
refresh_token: "${dataConfig.refresh_token}",
}
\`\`\`
## Environment Config
The environment variables are differ for each hosting service. If you are using Vercel, you can add the environment variables on the project settings page.
\`\`\`
ENCRYPTION_KEY="${dataKey}"
\`\`\`
**NOTE:** Make sure to redeploy the site after adding the environment variables.
## Customizing the Site
The site can be customized by editing the \`src/config/site.ts\` file. You can change the site title, description, and other information.
All the explanation also included in the file.`;
setMdContent(mdContent);
setIsLoading(false);
// Remove the temp data
localStorage.removeItem("tempEncryption");
localStorage.removeItem("tempGoogleCloud");
}, [dataConfig, dataKey]);
return (
<div className={"mx-auto flex max-w-screen-xl flex-col gap-4"}>
<div className={"card"}>
<div className='flex w-full items-center justify-between rounded-lg px-4'>
<span className='font-bold'>Finishing setup</span>
</div>
<div className={"divider-horizontal"} />
{isLoading ? (
<LoadingFeedback message={"Loading data..."} />
) : (
<MarkdownRender content={mdContent} />
)}
<div className={"divider-horizontal"} />
<div
className={
"mx-auto flex w-full flex-row items-center justify-end gap-2 tablet:gap-4"
}
>
<Link href={"/"}>
<button className={"primary"}>Finish</button>
</Link>
</div>
</div>
</div>
);
}
-142
View File
@@ -1,142 +0,0 @@
import { useEffect, useState } from "react";
import { encrypt } from "utils/encryptionHelper";
import Link from "next/link";
import useLocalStorage from "hooks/useLocalStorage";
import MarkdownRender from "components/utility/MarkdownRender";
import useSWR from "swr";
import fetcher from "utils/swrFetch";
import LoadingFeedback from "components/APIFeedback/Loading";
export default function SetupGoogleCloud() {
const [encryptionKey] = useLocalStorage("tempEncryption", "");
const [_settingJson, setSettingJson] = useLocalStorage("tempGoogleCloud", {
client_id: "",
client_secret: "",
refresh_token: "",
});
const [client_id, setClientID] = useState<string>("");
const [client_secret, setClientSecret] = useState<string>("");
const [refresh_token, setRefreshToken] = useState<string>("");
const [allowNext, setAllowNext] = useState<boolean>(false);
const { data, isLoading } = useSWR("/setup/GoogleCloudStep.md", fetcher);
useEffect(() => {
if (client_id && client_secret && refresh_token) {
setAllowNext(true);
} else {
setAllowNext(false);
}
}, [client_id, client_secret, refresh_token]);
return (
<div className='mx-auto flex max-w-screen-xl flex-col gap-4'>
<div className={"card"}>
<div className='flex w-full items-center justify-between rounded-lg px-4'>
<span className='font-bold'>Setting up Google Cloud</span>
</div>
<div className={"divider-horizontal"} />
<div className={"banner"}>
<span>
If you already have Client ID, Client Secret, and Refresh Token.
Click <a href={"#skip"}>here</a> to skip this step.
</span>
</div>
<div
className={"mx-auto flex w-full max-w-screen-md flex-col gap-4 px-4"}
>
<div className={"flex flex-col gap-2"}>
{isLoading ? (
<LoadingFeedback message={"Loading file..."} />
) : (
<MarkdownRender content={data as string} />
)}
</div>
</div>
</div>
<div
className={"card"}
id={"skip"}
>
<div className='flex w-full items-center justify-between rounded-lg px-4'>
<span className='font-bold'>Store Google Cloud credentials</span>
</div>
<div className={"divider-horizontal"} />
<div
className={"mx-auto flex w-full max-w-screen-md flex-col gap-4 px-4"}
>
<div className={"flex flex-col gap-2"}>
<span className='font-bold'>Client ID</span>
<input
type={"text"}
className={"pr-4"}
value={client_id}
onChange={(e) => setClientID(e.target.value)}
placeholder={"Enter your client id here..."}
/>
</div>
<div className={"flex flex-col gap-2"}>
<span className='font-bold'>Client Secret</span>
<input
type={"text"}
className={"pr-4"}
value={client_secret}
onChange={(e) => setClientSecret(e.target.value)}
placeholder={"Enter your client secret here..."}
/>
<span className={"text-xs tablet:text-sm"}>
* Client secret will be encrypted using your encryption key
</span>
</div>
<div className={"flex flex-col gap-2"}>
<span className='font-bold'>Refresh Token</span>
<input
type={"text"}
className={"pr-4"}
value={refresh_token}
onChange={(e) => setRefreshToken(e.target.value)}
placeholder={"Enter your refresh token here..."}
/>
<span className={"text-xs tablet:text-sm"}>
* Refresh token will be encrypted using your encryption key
</span>
</div>
</div>
<div className={"divider-horizontal"} />
<div
className={
"mx-auto flex w-full items-center justify-end gap-2 tablet:gap-4"
}
>
<Link href={"/setup/encryption"}>
<button className={"secondary"}>Previous Page</button>
</Link>
<Link
href={allowNext ? "/setup/final" : ""}
onClick={() => {
if (!allowNext) return;
setSettingJson({
client_id,
client_secret: encrypt(client_secret, encryptionKey),
refresh_token: encrypt(refresh_token, encryptionKey),
});
}}
>
<button
className={"primary"}
disabled={!allowNext}
>
Next Page
</button>
</Link>
</div>
</div>
</div>
);
}
-37
View File
@@ -1,37 +0,0 @@
import Link from "next/link";
export default function Setup() {
return (
<div className={"mx-auto flex max-w-screen-xl flex-col gap-4"}>
<div className={"card"}>
<div className='flex w-full items-center justify-between rounded-lg px-4'>
<span className='font-bold'>Starting configuration</span>
</div>
<div className={"divider-horizontal"} />
<p className={"mx-auto max-w-screen-md px-4 py-4 text-center"}>
This page will guide you through the initial configuration for
deploying guDora-index. It start from setting up your encryption key,
Google cloud, and setting up the project.
<br />
<br />
This step will take you couple of minutes. So please read the
instructions and follow them carefully.
</p>
<div className={"divider-horizontal"} />
<div
className={
"mx-auto flex w-full flex-row items-center justify-end gap-2 tablet:gap-4"
}
>
<Link href={"/setup/encryption"}>
<button className={"primary"}>Start</button>
</Link>
</div>
</div>
</div>
);
}