From 0fafdbb74248086e6bfe1cbddca1c6315da28a00 Mon Sep 17 00:00:00 2001 From: Sid-80 Date: Sat, 13 Jul 2024 18:54:14 +0530 Subject: [PATCH 1/2] feat: file updates --- src/app/api/files/private/route.ts | 25 --------- src/app/api/files/public/route.ts | 24 --------- src/app/api/files/update/route.ts | 46 ++++++++++++++++ src/app/dashboard/_components/FileList.tsx | 61 +++++++++++++++------- src/components/shared/FileStatusModal.tsx | 33 ++++++------ src/components/shared/RenameFileForm.tsx | 28 ++++++---- src/components/shared/RenameFileModal.tsx | 10 ++-- src/lib/API-URLs.ts | 3 +- 8 files changed, 131 insertions(+), 99 deletions(-) delete mode 100644 src/app/api/files/private/route.ts delete mode 100644 src/app/api/files/public/route.ts create mode 100644 src/app/api/files/update/route.ts diff --git a/src/app/api/files/private/route.ts b/src/app/api/files/private/route.ts deleted file mode 100644 index 39f3a42..0000000 --- a/src/app/api/files/private/route.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { api } from "../../../../../convex/_generated/api"; -import { ConvexHttpClient } from "convex/browser"; - -export const PUT = async(req: Request) => { - try { - const { teamId, email, fileId } = await req.json(); - - console.log(teamId,email,fileId) - - if (!teamId || !email || !fileId) return new Response('Parameters missing!!',{status: 401}); - - const client = new ConvexHttpClient(process.env.NEXT_PUBLIC_CONVEX_URL!); - - const teamInfo = await client.query(api.teams.getTeamById,{_id:teamId}); - - if (teamInfo.createdBy !== email) return new Response('Only owner can make changes!!',{status: 400}); - - - await client.mutation(api.files.changeToPrivate,{_id:fileId}); - - return new Response('Changed to Private!!',{status: 200}); - } catch (err) { - console.log(err) - } -} \ No newline at end of file diff --git a/src/app/api/files/public/route.ts b/src/app/api/files/public/route.ts deleted file mode 100644 index 851805b..0000000 --- a/src/app/api/files/public/route.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { api } from "../../../../../convex/_generated/api"; -import { ConvexHttpClient } from "convex/browser"; - -export const PUT = async(req: Request) => { - try { - const { teamId, email, fileId } = await req.json(); - - if (!teamId || !email || !fileId) return new Response('Parameters missing!!',{status: 401}); - - const client = new ConvexHttpClient(process.env.NEXT_PUBLIC_CONVEX_URL!); - - const teamInfo = await client.query(api.teams.getTeamById,{_id:teamId}) - - if (teamInfo.createdBy !== email) { - return new Response('Only owner can make changes!!',{status: 400}); - } - - await client.mutation(api.files.changeToPublic,{_id:fileId}); - - return new Response('Changed to Public!!',{status: 200}); - } catch (err) { - console.log(err) - } -} \ No newline at end of file diff --git a/src/app/api/files/update/route.ts b/src/app/api/files/update/route.ts new file mode 100644 index 0000000..10b82eb --- /dev/null +++ b/src/app/api/files/update/route.ts @@ -0,0 +1,46 @@ +import { mongoDB } from "@/lib/MongoDB"; +import { AuthMiddleware } from "@/Middleware/AuthMiddleware"; +import FileModel from "@/models/file"; +import { ApiUser } from "@/types/types"; +import { NextResponse } from "next/server"; + +export async function PUT( + request: Request +) { + + const result = await AuthMiddleware(request); + + if (result instanceof NextResponse) { + + try { + await mongoDB(); + + const {fileName, filePrivate, fileId, archive} = await request.json() + console.log(fileName, filePrivate, fileId, archive) + + if(!fileName || filePrivate === undefined || archive === undefined || !fileId){ + return NextResponse.json(`Access Denied!!`, {status:404}); + } + + const user: ApiUser = JSON.parse(request.headers.get("user") || "{}"); + + const file = await FileModel.findById({_id:fileId}); + + if(file.createdBy !== user._id && !file.writtenBy.includes(user._id)){ + return NextResponse.json(`Access Denied!!`, {status:401}); + } + + await FileModel.updateOne({_id:fileId},{ + fileName, + filePrivate, + archive + }) + + return NextResponse.json('',{status:200}); + } catch (err) { + return NextResponse.json(`Err : ${err}`, {status:500}); + } + } else { + return result; + } +} \ No newline at end of file diff --git a/src/app/dashboard/_components/FileList.tsx b/src/app/dashboard/_components/FileList.tsx index ebebf31..f26cf7c 100644 --- a/src/app/dashboard/_components/FileList.tsx +++ b/src/app/dashboard/_components/FileList.tsx @@ -31,6 +31,9 @@ import RenameFileModal from "@/components/shared/RenameFileModal"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Badge } from "@/components/ui/badge"; import FileStatusModal from "@/components/shared/FileStatusModal"; +import { RootState } from "@/config/store"; +import createAxiosInstance from "@/config/AxiosProtectedRoute"; +import { updateFileUrl } from "@/lib/API-URLs"; export interface FILE { archive: boolean; @@ -130,8 +133,8 @@ const FileRow = ({ file: FILE; picture: string; pathname: string; - onArchive: (e: any, id: string) => void; - onUnarchive: (e: any, id: string) => void; + onArchive: (e: any, file: FILE) => void; + onUnarchive: (e: any, file: FILE) => void; onDelete: (e: any, id: string) => void; router: ReturnType; index: number; @@ -171,8 +174,8 @@ const FileRow = ({ - + {pathname === "/dashboard" && ( onArchive(e, file._id)} + onAction={(e) => onArchive(e, file)} /> )} {pathname === "/dashboard/archive" && ( @@ -206,7 +209,7 @@ const FileRow = ({ buttonIcon={ArchiveRestore} dialogTitle="Are you absolutely sure?" dialogDescription="This will unarchive your file." - onAction={(e) => onUnarchive(e, file._id)} + onAction={(e) => onUnarchive(e, file)} buttonVariant="destructive" /> )} @@ -242,6 +245,7 @@ function FileList({ const [isSubmitted, setIsSubmitted] = useState(false); const safeFileList = Array.isArray(fileList) ? fileList : []; const pathname = usePathname(); + const axiosInstance = createAxiosInstance(user.accessToken) const sortedFiles = [...safeFileList]; if (sortConfig !== null) { @@ -263,18 +267,35 @@ function FileList({ setIsSubmitted(true); }; - const archiveFile = useMutation(api.files.addToArchive); - const archiveFunc = async (e: any, id: string) => { + + const archiveFunc = async (e: any, file:FILE) => { e.stopPropagation(); - await archiveFile({ _id: id as Id<"files"> }); - setIsSubmitted(true); + try { + await axiosInstance.put(updateFileUrl,{ + fileName:file.fileName, + filePrivate:file.filePrivate, + fileId:file._id, + archive:true + }) + setIsSubmitted(true); + } catch (err) { + console.log(err); + } }; - const unArchiveFile = useMutation(api.files.removeFromArchive); - const unarchiveFunc = async (e: any, id: string) => { + const unarchiveFunc = async (e: any, file:FILE) => { e.stopPropagation(); - await unArchiveFile({ _id: id as Id<"files"> }); - setIsSubmitted(true); + try { + await axiosInstance.put(updateFileUrl,{ + fileName:file.fileName, + filePrivate:file.filePrivate, + fileId:file._id, + archive:false + }) + setIsSubmitted(true); + } catch (err) { + console.log(err); + } }; const requestSort = (key: keyof FILE) => { @@ -388,7 +409,7 @@ function FileList({
{file.fileName}
- + {pathname === "/dashboard" && ( archiveFunc(e, file._id)} + onAction={(e) => archiveFunc(e, file)} /> )} {pathname === "/dashboard/archive" && ( @@ -406,7 +427,7 @@ function FileList({ buttonIcon={ArchiveRestore} dialogTitle="Are you absolutely sure?" dialogDescription="This will unarchive your file." - onAction={(e) => unarchiveFunc(e, file._id)} + onAction={(e) => unarchiveFunc(e, file)} buttonVariant="destructive" /> )} @@ -433,8 +454,8 @@ function FileList({
state.team.teamId); + const axiosInstance = createAxiosInstance(user.accessToken) const FileHandler = async () => { if (!privateFIle) { try { - const res = await axiosInstance.put(changeToPrivateUrl, { - teamId, - email, - fileId, + const res = await axiosInstance.put(updateFileUrl, { + fileName:file.fileName, + filePrivate:true, + fileId:file._id, + archive: (file.archive === undefined) ? false : file.archive }); if (res.status === 200) { setIsSubmitted(true); @@ -59,10 +61,11 @@ export default function FileStatusModal({ } } else { try { - const res = await axiosInstance.put(changeToPublicUrl, { - teamId, - email, - fileId, + const res = await axiosInstance.put(updateFileUrl, { + fileName:file.fileName, + filePrivate:false, + fileId:file._id, + archive: (file.archive === undefined) ? false : file.archive }); if (res.status === 200) { setIsSubmitted(true); diff --git a/src/components/shared/RenameFileForm.tsx b/src/components/shared/RenameFileForm.tsx index bf8b842..b2f22fa 100644 --- a/src/components/shared/RenameFileForm.tsx +++ b/src/components/shared/RenameFileForm.tsx @@ -18,6 +18,9 @@ import { PencilIcon } from "lucide-react"; import { api } from "../../../convex/_generated/api"; import { Id } from "../../../convex/_generated/dataModel"; import { SetStateAction } from "react"; +import { FILE } from "@/app/dashboard/_components/FileList"; +import { updateFileUrl } from "@/lib/API-URLs"; +import createAxiosInstance from "@/config/AxiosProtectedRoute"; const FormSchema = z.object({ newName: z.string().min(1, { @@ -26,12 +29,14 @@ const FormSchema = z.object({ }); type Props = { - id:string; + file:FILE; setIsSubmitted: React.Dispatch>; + user:any; } -export function RenameFileForm({id,setIsSubmitted}:Props) { - const convex = useConvex(); +export function RenameFileForm({file,setIsSubmitted,user}:Props) { + + const axiosInstance = createAxiosInstance(user.accessToken) const form = useForm>({ resolver: zodResolver(FormSchema), @@ -41,12 +46,17 @@ export function RenameFileForm({id,setIsSubmitted}:Props) { }); async function onSubmit(data: z.infer) { - const result = await convex.mutation(api.files.renameFile,{ - _id:id as Id<"files">, - newName:data.newName - }) - - setIsSubmitted(true); + try { + await axiosInstance.put(updateFileUrl,{ + fileName:data.newName, + filePrivate:file.filePrivate, + fileId:file._id, + archive: (file.archive === undefined) ? false : file.archive + }) + setIsSubmitted(true); + } catch (err) { + console.log(err); + } } return ( diff --git a/src/components/shared/RenameFileModal.tsx b/src/components/shared/RenameFileModal.tsx index 078913a..8fe2d6c 100644 --- a/src/components/shared/RenameFileModal.tsx +++ b/src/components/shared/RenameFileModal.tsx @@ -12,14 +12,14 @@ import { import { RenameFileForm } from "./RenameFileForm"; import { Button } from "../ui/button"; import { useState } from "react"; -import { useRouter } from "next/navigation"; +import { FILE } from "@/app/dashboard/_components/FileList"; type Props = { - id: string; + file: FILE; + user:any; }; -export default function RenameFileModal({ id }: Props) { - const router = useRouter(); +export default function RenameFileModal({ file,user }: Props) { const [isSubmitted, setIsSubmitted] = useState(false); return ( @@ -35,7 +35,7 @@ export default function RenameFileModal({ id }: Props) {

Rename File

- + )} diff --git a/src/lib/API-URLs.ts b/src/lib/API-URLs.ts index 03ecf62..e9c21cf 100644 --- a/src/lib/API-URLs.ts +++ b/src/lib/API-URLs.ts @@ -10,4 +10,5 @@ export const createNewTeamUrl = "/api/teams/create"; export const getTeamUrl = "/api/teams/get"; export const createFileUrl = "/api/files/create"; export const getFileUrl = "/api/files/get"; -export const getFileByIdUrl = "/api/files/getFileById"; \ No newline at end of file +export const getFileByIdUrl = "/api/files/getFileById"; +export const updateFileUrl = "/api/files/update"; \ No newline at end of file From db8e6d3d530d3c609115e1496e0719921b5c7089 Mon Sep 17 00:00:00 2001 From: Sid-80 Date: Sun, 14 Jul 2024 16:43:44 +0530 Subject: [PATCH 2/2] feat: delete team and file --- src/app/api/files/delete/[id]/route.ts | 32 +++++++++++++++++++ src/app/api/teams/delete/[id]/route.ts | 32 +++++++++++++++++++ src/app/dashboard/_components/FileList.tsx | 13 ++++---- .../_components/SideNavBottomSection.tsx | 12 +++---- src/lib/API-URLs.ts | 4 ++- 5 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 src/app/api/files/delete/[id]/route.ts create mode 100644 src/app/api/teams/delete/[id]/route.ts diff --git a/src/app/api/files/delete/[id]/route.ts b/src/app/api/files/delete/[id]/route.ts new file mode 100644 index 0000000..91dc57f --- /dev/null +++ b/src/app/api/files/delete/[id]/route.ts @@ -0,0 +1,32 @@ +import { mongoDB } from "@/lib/MongoDB"; +import { AuthMiddleware } from "@/Middleware/AuthMiddleware"; +import FileModel from "@/models/file"; +import { NextResponse } from "next/server"; + +export async function DELETE( + request: Request, + { params }: { params: { id: string } } + ) { + + const result = await AuthMiddleware(request); + + if (result instanceof NextResponse) { + + try { + + const { id } = params; + + if (!id) return new Response("Parameters missing!!", { status: 401 }); + + await mongoDB(); + + await FileModel.deleteOne({_id:id}) + + return NextResponse.json('Deleted SuccessFully!!',{ status: 200 }); + } catch (err) { + return NextResponse.json(`Err : ${err}`, {status:500}); + } + } else { + return result; + } + } \ No newline at end of file diff --git a/src/app/api/teams/delete/[id]/route.ts b/src/app/api/teams/delete/[id]/route.ts new file mode 100644 index 0000000..259c519 --- /dev/null +++ b/src/app/api/teams/delete/[id]/route.ts @@ -0,0 +1,32 @@ +import { mongoDB } from "@/lib/MongoDB"; +import { AuthMiddleware } from "@/Middleware/AuthMiddleware"; +import TeamModel from "@/models/team"; +import { NextResponse } from "next/server"; + +export async function DELETE( + request: Request, + { params }: { params: { id: string } } + ) { + + const result = await AuthMiddleware(request); + + if (result instanceof NextResponse) { + + try { + + const { id } = params; + + if (!id) return new Response("Parameters missing!!", { status: 401 }); + + await mongoDB(); + + await TeamModel.deleteOne({_id:id}) + + return NextResponse.json('Deleted SuccessFully!!',{ status: 200 }); + } catch (err) { + return NextResponse.json(`Err : ${err}`, {status:500}); + } + } else { + return result; + } + } \ No newline at end of file diff --git a/src/app/dashboard/_components/FileList.tsx b/src/app/dashboard/_components/FileList.tsx index a25d524..e4cc4ec 100644 --- a/src/app/dashboard/_components/FileList.tsx +++ b/src/app/dashboard/_components/FileList.tsx @@ -33,7 +33,7 @@ import { Badge } from "@/components/ui/badge"; import FileStatusModal from "@/components/shared/FileStatusModal"; import { RootState } from "@/config/store"; import createAxiosInstance from "@/config/AxiosProtectedRoute"; -import { updateFileUrl } from "@/lib/API-URLs"; +import { deleteFileUrl, updateFileUrl } from "@/lib/API-URLs"; export interface FILE { archive: boolean; @@ -247,8 +247,6 @@ function FileList({ const pathname = usePathname(); const axiosInstance = createAxiosInstance(user.accessToken) - const axiosInstance = createAxiosInstance(user.accessToken) - const sortedFiles = [...safeFileList]; if (sortConfig !== null) { sortedFiles.sort((a, b) => { @@ -262,11 +260,14 @@ function FileList({ }); } - const deleteFile = useMutation(api.files.deleteFile); const deleteFunc = async (e: any, id: string) => { e.stopPropagation(); - await deleteFile({ _id: id as Id<"files"> }); - setIsSubmitted(true); + try { + await axiosInstance.delete(`${deleteFileUrl}/${id}`) + setIsSubmitted(true); + } catch (err) { + console.log(err); + } }; diff --git a/src/app/dashboard/_components/SideNavBottomSection.tsx b/src/app/dashboard/_components/SideNavBottomSection.tsx index ed3f5b2..6f8f3cf 100644 --- a/src/app/dashboard/_components/SideNavBottomSection.tsx +++ b/src/app/dashboard/_components/SideNavBottomSection.tsx @@ -44,7 +44,7 @@ import { import { RootState } from "@/config/store"; import { useSelector } from "react-redux"; import createAxiosInstance from "@/config/AxiosProtectedRoute"; -import { createFileUrl } from "@/lib/API-URLs"; +import { createFileUrl, deleteTeamUrl } from "@/lib/API-URLs"; import { Switch } from "@/components/ui/switch"; interface TEAM { @@ -97,12 +97,12 @@ function SideNavBottomSection({getFiles, totalFiles, activeTeam }: any) { const deleteFunc = async (e: any, id: String) => { e.stopPropagation(); - if (activeTeam.teamName === "My Org") { - toast.error("My Org can not be deleted"); - return; + try { + await axiosInstance.delete(`${deleteTeamUrl}/${id}`) + setIsSubmitted(true); + } catch (err) { + console.log(err); } - await deleteTeam({ _id: id as Id<"teams"> }); - setIsSubmitted(true); }; const handleFileInput = (val: string) => { diff --git a/src/lib/API-URLs.ts b/src/lib/API-URLs.ts index e9c21cf..b1d0ae1 100644 --- a/src/lib/API-URLs.ts +++ b/src/lib/API-URLs.ts @@ -11,4 +11,6 @@ export const getTeamUrl = "/api/teams/get"; export const createFileUrl = "/api/files/create"; export const getFileUrl = "/api/files/get"; export const getFileByIdUrl = "/api/files/getFileById"; -export const updateFileUrl = "/api/files/update"; \ No newline at end of file +export const updateFileUrl = "/api/files/update"; +export const deleteFileUrl = "/api/files/delete"; +export const deleteTeamUrl = "/api/teams/delete"; \ No newline at end of file