From 3269e7cedf25948952f78525eab4350843dd247b Mon Sep 17 00:00:00 2001 From: Praduman03 Date: Wed, 26 Apr 2023 20:57:32 +0530 Subject: [PATCH] completed all the required task --- src/modules/comments/controller.ts | 96 +++++++++++++++++++---------- src/modules/comments/schema.ts | 4 ++ src/modules/comments/service.ts | 54 +++++++++++++++-- src/modules/threads/controller.ts | 97 ++++++++++++++++++++---------- src/modules/threads/schema.ts | 8 ++- src/modules/threads/service.ts | 70 +++++++++++++++++++-- src/serviceAccountKey.json | 12 ++++ src/services/firebase.ts | 7 ++- 8 files changed, 271 insertions(+), 77 deletions(-) create mode 100644 src/serviceAccountKey.json diff --git a/src/modules/comments/controller.ts b/src/modules/comments/controller.ts index 0b344ba..e3b5e2c 100644 --- a/src/modules/comments/controller.ts +++ b/src/modules/comments/controller.ts @@ -11,15 +11,22 @@ import { createComment, deleteComment, getComment, listComments, updateComment } export const createCommentHandler = async (req: Request, res: Response) => { const { threadId } = req.params - throw new Error('Not implemented') - - // TODO: Validate the request body using CommentCreateSchema - - // TODO: If the request body is invalid, return a 400 response with the error - - // TODO: Create the comment using the createComment service - - // TODO: Return the created comment in the response + // throw new Error('Not implemented') + try { + // TODO: Validate the request body using CommentCreateSchema + const validateData = CommentCreateSchema.parse(req.body) + // TODO: If the request body is invalid, return a 400 response with the error + if (!req.body) { + return res.status(400).json({ success: false, message: "Invalid request" }) + } + // TODO: Create the comment using the createComment service + const commentcreated = await createComment(threadId, validateData) + // TODO: Return the created comment in the response + return res.status(200).json({ success: true, data: commentcreated }) + } catch (error) { + console.error(error) + res.status(400).json({ success: false, message: "Invalid request data" }) + } } /** @@ -31,11 +38,16 @@ export const createCommentHandler = async (req: Request, res: Response) => { export const listCommentsHandler = async (req: Request, res: Response) => { const { threadId } = req.params - throw new Error('Not implemented') - - // TODO: Fetch the list of comments using the listComments service - - // TODO: Return the list of comments in the response + // throw new Error('Not implemented') + try { + // TODO: Fetch the list of comments using the listComments service + const listComment = await listComments(threadId) + // TODO: Return the list of comments in the response + return res.status(200).json({ success: true, message: listComment }) + } catch (error) { + console.log(error) + res.status(400).json({ success: false, message: "error occured" }) + } } /** @@ -47,11 +59,16 @@ export const listCommentsHandler = async (req: Request, res: Response) => { export const getCommentHandler = async (req: Request, res: Response) => { const { threadId, commentId } = req.params - throw new Error('Not implemented') - - // TODO: Fetch the comment by ID using the getComment service - - // TODO: Return the comment in the response + // throw new Error('Not implemented') + try { + // TODO: Fetch the comment by ID using the getComment service + const getData = await getComment(threadId, commentId) + // TODO: Return the comment in the response + return res.status(200).json({ success: true, message: getData }); + } catch (error) { + console.error(error); + res.status(400).json({ message: "error occured" }) + } } /** @@ -63,15 +80,22 @@ export const getCommentHandler = async (req: Request, res: Response) => { export const updateCommentHandler = async (req: Request, res: Response) => { const { threadId, commentId } = req.params - throw new Error('Not implemented') - - // TODO: Validate the request body using CommentUpdateSchema - - // TODO: If the request body is invalid, return a 400 response with the error - - // TODO: Update the comment by ID using the updateComment service - - // TODO: Return the updated comment in the response + // throw new Error('Not implemented') + try { + // TODO: Validate the request body using CommentUpdateSchema + const validateData = CommentUpdateSchema.parse(req.body) + // TODO: If the request body is invalid, return a 400 response with the error + if (!validateData) { + return res.status(400).json({ success: false, message: "invalid request" }) + } + // TODO: Update the comment by ID using the updateComment service + const updateData = await updateComment(threadId, commentId, validateData) + // TODO: Return the updated comment in the response + return res.status(200).json({ success: true, updateData }) + } catch (error) { + console.error(error) + res.status(400).json({ message: "error occured" }) + } } /** @@ -83,9 +107,19 @@ export const updateCommentHandler = async (req: Request, res: Response) => { export const deleteCommentHandler = async (req: Request, res: Response) => { const { threadId, commentId } = req.params - throw new Error('Not implemented') + // throw new Error('Not implemented') + + try { + + // TODO: Delete the comment by ID using the deleteComment service + + await deleteComment(threadId, commentId) - // TODO: Delete the comment by ID using the deleteComment service + // TODO: Return a void success response - // TODO: Return a void success response + return res.status(200).json({ success: true }) + } catch (error) { + console.log(error) + res.status(400).json({ success: false, message: "error occured" }) + } } diff --git a/src/modules/comments/schema.ts b/src/modules/comments/schema.ts index c2fd54f..5c506f0 100644 --- a/src/modules/comments/schema.ts +++ b/src/modules/comments/schema.ts @@ -3,6 +3,10 @@ import { z } from 'zod' // TODO: Add the fields you need to the Comment schema export const CommentSchema = z.object({ id: z.string(), + threadId: z.string(), + comment: z.string(), + createdAt: z.date(), + createdBy: z.string() }) export type Comment = z.infer diff --git a/src/modules/comments/service.ts b/src/modules/comments/service.ts index 17182e9..6ef3976 100644 --- a/src/modules/comments/service.ts +++ b/src/modules/comments/service.ts @@ -2,6 +2,7 @@ import { FieldValue } from 'firebase-admin/firestore' import { db } from '../../services/firebase' import { Thread } from '../threads/schema' import { CommentUpdate, type Comment, type CommentCreate } from './schema' +import * as admin from 'firebase-admin'; // Utility function to get the comments collection for a given thread const commentCollection = (threadId: Thread['id']) => db.collection(`threads/${threadId}/comments`) @@ -26,7 +27,16 @@ const fromFirestore = (snapshot: FirebaseFirestore.DocumentSnapshot => { // TODO: Fetch the list of comments for the given thread - throw new Error('Not implemented') + // throw new Error('Not implemented') + const commentRef = await commentCollection(threadId).get() + + const comments: Comment[] = [] + + commentRef.forEach((doc) => { + comments.push(fromFirestore(doc)); + }) + + return comments } /** @@ -37,7 +47,10 @@ export const listComments = async (threadId: Thread['id']): Promise = */ export const getComment = async (threadId: Thread['id'], id: Comment['id']): Promise => { // TODO: Fetch the comment by ID - throw new Error('Not implemented') + // throw new Error('Not implemented') + const singleComment = await commentCollection(threadId).doc(id).get() + + return fromFirestore(singleComment) } /** @@ -48,7 +61,21 @@ export const getComment = async (threadId: Thread['id'], id: Comment['id']): Pro */ export const createComment = async (threadId: Thread['id'], data: CommentCreate): Promise => { // TODO: Create the comment in Firestore and return the newly created comment - throw new Error('Not implemented') + // throw new Error('Not implemented') + const threadid = threadId + const docRef = commentCollection(threadId).doc(); + + const comment: Comment = { + id: docRef.id, + threadId, + ...data, + createdAt: new Date(), + } + + await docRef.set(comment) + + return comment; + } /** @@ -60,7 +87,17 @@ export const createComment = async (threadId: Thread['id'], data: CommentCreate) */ export const updateComment = async (threadId: Thread['id'], id: Comment['id'], data: CommentUpdate): Promise => { // TODO: Update the comment in Firestore and return the updated comment - throw new Error('Not implemented') + // throw new Error('Not implemented') + + const commentRef = commentCollection(threadId).doc(id) + + await commentRef.update(data) + + const updatedComment = await commentRef.get() + + const updComment = fromFirestore(updatedComment) + + return updComment } /** @@ -71,5 +108,12 @@ export const updateComment = async (threadId: Thread['id'], id: Comment['id'], d */ export const deleteComment = async (threadId: Thread['id'], id: Comment['id']): Promise => { // TODO: Delete the comment from Firestore and return the result - throw new Error('Not implemented') + // throw new Error('Not implemented') + try { + const commentRef = commentCollection(threadId).doc(id) + const deleted = await commentRef.delete(); + return deleted; + } catch (error) { + throw Error("Unabe to delete the comment") + } } diff --git a/src/modules/threads/controller.ts b/src/modules/threads/controller.ts index be2ae8a..9e00e02 100644 --- a/src/modules/threads/controller.ts +++ b/src/modules/threads/controller.ts @@ -1,6 +1,7 @@ import { Request, Response } from 'express' import { threadCreateSchema, threadUpdateSchema } from './schema' import { createThread, deleteThread, getThread, listThreads, updateThread } from './service' +import { messaging } from 'firebase-admin' /** * Create a thread @@ -9,15 +10,22 @@ import { createThread, deleteThread, getThread, listThreads, updateThread } from * @returns Success object of created thread */ export const createThreadHandler = async (req: Request, res: Response) => { - throw new Error('Not implemented') - - // TODO: Validate the request body using threadCreateSchema - - // TODO: If the request body is invalid, return a 400 response with the error - - // TODO: Create the thread using the createThread service - - // TODO: Return the created thread in the response + // throw new Error('Not implemented') + try { + // TODO: Validate the request body using threadCreateSchema + const validateData = threadCreateSchema.parse(req.body) + // TODO: If the request body is invalid, return a 400 response with the error + if (!req.body) { + return res.status(400).json({ success: false, message: 'Invalid request data' }) + } + // TODO: Create the thread using the createThread service + const createdSchema = await createThread(validateData) + // TODO: Return the created thread in the response + return res.status(200).json({ success: true, data: createdSchema }) + } catch (error) { + console.error(error) + res.status(400).json({ success: false, message: "invalid request data" }) + } } /** @@ -27,11 +35,16 @@ export const createThreadHandler = async (req: Request, res: Response) => { * @returns Success object of list of threads */ export const listThreadsHandler = async (req: Request, res: Response) => { - throw new Error('Not implemented') - - // TODO: Fetch the list of threads using the listThreads service - - // TODO: Return the list of threads in the response + // throw new Error('Not implemented') + try { + // TODO: Fetch the list of threads using the listThreads service + const listThread = await listThreads(); + // TODO: Return the list of threads in the response + return res.status(200).json({ success: true, message: listThread }) + } catch (error) { + console.error(error) + res.status(400).json({ success: false, message: "error occured" }) + } } /** @@ -43,11 +56,16 @@ export const listThreadsHandler = async (req: Request, res: Response) => { export const getThreadHandler = async (req: Request, res: Response) => { const { threadId } = req.params - throw new Error('Not implemented') - - // TODO: Fetch the thread using the getThread service - - // TODO: Return the thread in the response + // throw new Error('Not implemented') + try { + // TODO: Fetch the thread using the getThread service + const getData = await getThread(threadId) + // TODO: Return the thread in the response + return res.status(200).json({ success: true, getData }); + } catch (error) { + console.error(error); + res.status(400).json({ success: true, message: "error occured" }) + } } /** @@ -59,15 +77,22 @@ export const getThreadHandler = async (req: Request, res: Response) => { export const updateThreadHandler = async (req: Request, res: Response) => { const { threadId } = req.params - throw new Error('Not implemented') - - // TODO: Validate the request body using threadUpdateSchema - - // TODO: If the request body is invalid, return a 400 response with the error - - // TODO: Update the thread using the updateThread service - - // TODO: Return the updated thread in the response + // throw new Error('Not implemented') + try { + // TODO: Validate the request body using threadUpdateSchema + const validateData = await threadUpdateSchema.parse(req.body) + // TODO: If the request body is invalid, return a 400 response with the error + if (!validateData) { + return res.status(400).json({ success: false, message: "invalid request" }) + } + // TODO: Update the thread using the updateThread service + const updateData = await updateThread(threadId, validateData) + // TODO: Return the updated thread in the response + return res.status(200).json({ success: true, updateData }) + } catch (error) { + console.error(error) + res.status(400).json({ success: false, message: "error occured" }) + } } /** @@ -79,9 +104,15 @@ export const updateThreadHandler = async (req: Request, res: Response) => { export const deleteThreadHandler = async (req: Request, res: Response) => { const { threadId } = req.params - throw new Error('Not implemented') - - // TODO: Delete the thread using the deleteThread service - - // TODO: Return a success response + // throw new Error('Not implemented') + + try { + // TODO: Delete the thread using the deleteThread service + await deleteThread(threadId) + // TODO: Return a success response + return res.status(200).json({ success: true, message: "thread deleted successfully" }) + } catch (error) { + console.log(error) + res.status(400).json({ success: false, message: "error occured" }) + } } diff --git a/src/modules/threads/schema.ts b/src/modules/threads/schema.ts index 2436fd3..311a020 100644 --- a/src/modules/threads/schema.ts +++ b/src/modules/threads/schema.ts @@ -3,12 +3,16 @@ import { z } from 'zod' // TODO: Add the fields you need to the Thread schema export const threadSchema = z.object({ id: z.string(), + name: z.string(), + description: z.string(), + createdAt: z.date(), + createdBy: z.string() }) export type Thread = z.infer // ? These schemas are provided for you, but you may need to add more fields to them -export const threadCreateSchema = threadSchema.omit({ id: true, createdAt: true }) +export const threadCreateSchema = threadSchema.omit({ id: true, createdAt: true, }) export type ThreadCreate = z.infer -export const threadUpdateSchema = threadSchema.omit({ id: true, createdAt: true, createdBy: true }) +export const threadUpdateSchema = threadSchema.omit({ id: true, createdAt: true, createdBy: true, }) export type ThreadUpdate = z.infer diff --git a/src/modules/threads/service.ts b/src/modules/threads/service.ts index 4efb1ea..1141eb8 100644 --- a/src/modules/threads/service.ts +++ b/src/modules/threads/service.ts @@ -1,6 +1,7 @@ import { FieldValue } from 'firebase-admin/firestore' import { db } from '../../services/firebase' import { ThreadUpdate, type Thread, type ThreadCreate } from './schema' +import * as admin from 'firebase-admin'; // Reference to the threads collection const threadCollection = db.collection('threads') @@ -24,7 +25,19 @@ const fromFirestore = (snapshot: FirebaseFirestore.DocumentSnapshot => { // TODO: Fetch the list of threads - throw new Error('Not implemented') + // throw new Error('Not implemented') + const collectionRef = await admin.firestore().collection('threads') + const snapshot = await collectionRef.get() + const threads: Thread[] = []; + + snapshot.forEach((doc) => { + const thread = fromFirestore(doc) + threads.push(thread); + }) + + + //return the data + return threads } /** @@ -34,7 +47,23 @@ export const listThreads = async (): Promise => { */ export const getThread = async (id: Thread['id']): Promise => { // TODO: Fetch the thread by ID - throw new Error('Not implemented') + // throw new Error('Not implemented') + const docRef = await admin.firestore().collection('threads').doc(id) + const doc = await docRef.get(); + + if (!doc.exists) { + throw Error('Thread not found!') + } + + const data = doc.data(); + + if (!data) { + throw Error('thread data not found!') + } + + const thread = await fromFirestore(doc); + + return thread; } /** @@ -44,7 +73,22 @@ export const getThread = async (id: Thread['id']): Promise => { */ export const createThread = async (data: ThreadCreate): Promise => { // TODO: Create the thread in Firestore and return the newly created thread - throw new Error('Not implemented') + // throw new Error('Not implemented') + const threadData = data + + const docRef = await admin.firestore().collection('threads').doc(); + + const thread: Thread = { + id: docRef.id, + name: threadData.name, + description: threadData.description, + createdAt: new Date(), + createdBy: threadData.createdBy + } + + await docRef.set(thread) + + return thread; } /** @@ -55,7 +99,18 @@ export const createThread = async (data: ThreadCreate): Promise => { */ export const updateThread = async (id: Thread['id'], data: ThreadUpdate): Promise => { // TODO: Update the thread in Firestore and return the updated thread - throw new Error('Not implemented') + // throw new Error('Not implemented') + + const updateData = await admin.firestore().collection('threads').doc(id) + + await updateData.update(data) + + const updateddata = await updateData.get() + + const updData = fromFirestore(updateddata) + + return updData + } /** @@ -65,5 +120,10 @@ export const updateThread = async (id: Thread['id'], data: ThreadUpdate): Promis */ export const deleteThread = async (id: Thread['id']): Promise => { // TODO: Delete the thread in Firestore and return the write result - throw new Error('Not implemented') + // throw new Error('Not implemented') + const threadId = id; + + const deleteData = await admin.firestore().collection('threads').doc(threadId).delete() + + return deleteData } diff --git a/src/serviceAccountKey.json b/src/serviceAccountKey.json new file mode 100644 index 0000000..be2f346 --- /dev/null +++ b/src/serviceAccountKey.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "redditcloneapi", + "private_key_id": "33f1299d186e635ce243bc4eb21cc4c54010ab97", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQziA7sHzue1jX\nCXuD9fjNgKd+0w1O1lYxd200HbXGmEKRcQloSsjJGYpu4xVij8vEmjuy7T2QLhrk\n9cjHwpzW/hF7jJziRct5to4mkLZlRyuvyQc5CHgxuKI/+Y1Q0dVluQAyOjZcT+KJ\nD6frPZxBVtasnBX5d9jE04fetXOCh9t0uVuL6xOSlPFcfxCJI6zA75G4QZ5bZiDa\nNH/HoYtSVQcUeBWa2+zcKCpAnyo/NmlYCOxFzxc+FVpISCj0LsRfuOcklLVWHovv\na4jxDsL3wub3KvVZ4y5P0425dErr6FkMmyIaoPqwxNpfW+O00OpE5bsr8S0P87RL\nCrZP6sANAgMBAAECggEASiy/NJUIfGti7tjWgNUzMkV+usXcl2H6so3bREU9mrPi\nCeqezearFw00qRmQMjgkyc2EYZZ3ZS2LrkRFs/jFYHZW3Y3g+VyT4MPiEX8c3DOB\nKGwAXdlNYVRWhuVutwQji4RBtpYJU5epQMlH/IAhbvCbSCwWfk19usXuIUZSJ07Z\nVlfaZfpn4b7Vi37fIhztdSm9alujOXuq7CR2ah8njnzio6ozcwyjaDKMLGA7QIiv\n9uwfSBypRt7rEX0A6t2Akq/yQNzMUQsxkAAYZlWfXv9CCjL/15j0Dy0Js6amtyL4\nbc1xh+yjVX/DjU6fPL+CtD1KVxPqQu+a8Cyp/m7WPQKBgQDw8xKwHLpDYeY40jGn\nj3HcWv+fWz24ImG1R5PqB/o2BcXtQqcYqzoUhvyQNMNb/ttvU0PjCcv52QYx6nmd\nP5ilGdQUjbCnbKPj5c9pv2YZZJKAon96aidOOWPfDchOStV2wYzhNbzBIWOcpXyv\nkbScYYSvQ66fs+XK6g7JTjTEWwKBgQDd2Qu/otHJXCRl2JQ3zQ+Pee0PNHupjlN9\nF3SxhLKFDxuj9+tpDtDvsLD4ITVlGS1N7FA7vKUjUNijxWZzx4ReoWL4bdeETwW9\nQgM3gGmgAzXXpsQnrbGQlaCBnK4mJxvLqm0aI8xcSMMKL8UjDl/s3IdRSd6VPtQE\nwvPf9AiZtwKBgQDAw8asrJ77r4Pu64KcKi+OeiLNi8Jp4N/IltYoQm+T7rR1Z4Cl\nRL93krLWb8/ndpJ5kuTZ64mLfmvtXUgkXK+zTmGUe/LbTxgjCEUStfRp1kM6tEZG\nWkzN0S4sUitxL39tvdUGi+ZRoHO/68k/8NLM1VvAl+ZJkDQETZK8zFt8xwKBgCbJ\nRbaRfuAXjf2IahF/dpL9HCcmY+B3E72xFiPbMWL2Cz0VoUDS6FCfsbEQDUfJqRQQ\nls564txTzCyF3K2tWkU5LhaFDcMCFdzK58kSWGUzanxzmaPeSEchAdjnTcM53zAy\ncbS6QYZ46jCjvXGtl7PPspDRu2qYe3UBqKWlAsPtAoGBAIhq8AMvLw2V41CVbBp2\n9MYHuwhRlCM9xta3TptYtY5U/2TEFQNTc1NbQPL2Od8nEE8AoQCIAYfaQs+ENNMh\n5qWDi9YFMVX0ocOtk7eim82ldzA6AL6UtZB+63GvTyfaZQUEDKWqzNWK8of7xdW8\nk3NvQoCxjRunDnmDL9nd0RzK\n-----END PRIVATE KEY-----\n", + "client_email": "firebase-adminsdk-la3mg@redditcloneapi.iam.gserviceaccount.com", + "client_id": "107864387518038789135", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-la3mg%40redditcloneapi.iam.gserviceaccount.com" +} diff --git a/src/services/firebase.ts b/src/services/firebase.ts index 459ed17..bd8e159 100644 --- a/src/services/firebase.ts +++ b/src/services/firebase.ts @@ -1,8 +1,13 @@ import { initializeApp } from 'firebase-admin/app' import { getFirestore } from 'firebase-admin/firestore' +import * as admin from 'firebase-admin'; + +const serviceAccount = require('../serviceAccountKey.json'); // Initialize Firebase Admin -export const app = initializeApp() +export const app = initializeApp({ + credential: admin.credential.cert(serviceAccount), +}) // Initialize Firestore export const db = getFirestore(app)