diff --git a/backend/src/app.ts b/backend/src/app.ts index efee999..a0b98cc 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -9,7 +9,6 @@ import path from "path"; // Import routes import userRoutes from './modules/user/routes/user.routes'; -import commentRoutes from './modules/comment/routes/comment.routes'; import contentRoutes from './modules/content/routes/content.routes'; import subscriptionRoutes from './modules/subscription/routes/subscription.routes'; import notificationRoutes from './modules/notification/routes/notification.routes'; @@ -53,7 +52,6 @@ app.get("/health", (req, res) => { // API routes app.use("/user", userRoutes); -app.use("/comment", commentRoutes); app.use("/content", contentRoutes); app.use("/subscription", subscriptionRoutes); app.use("/notification", notificationRoutes); diff --git a/backend/src/modules/comment/controllers/comment.controller.ts b/backend/src/modules/comment/controllers/comment.controller.ts deleted file mode 100644 index b1d3cd7..0000000 --- a/backend/src/modules/comment/controllers/comment.controller.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { - createComment, - deleteComment, - deletePost, - getAllComments, - getComment, - updateComment -} from '../services/comment.service'; -import {ContentService} from '../../content/services/content.service' -import {Request, Response} from 'express'; -import {getUser} from "../../user/services/user.service"; - -export async function createCommentController(req: Request, res: Response): Promise { - const { post_id } = req.params - const { owner_id, text } = req.body; - try { - const response = await getUser(owner_id); - const creation = await createComment(post_id, owner_id, text, response?.username); - res.status(201).json({ message: 'Comment created successfully', creation}); - } catch (error) { - console.log(error) - console.log(post_id, owner_id, text) - res.status(500).json({ error: error }); - } - } - - export async function getCommentByIdController(req: Request, res: Response) { - const { post_id, comment_id } = req.params; - try { - const comment = await getComment(post_id, comment_id); - console.log(comment) - if (comment) res.status(200).json(comment); - else res.status(404).json(null); - } catch (error) { - res.status(500).json({ error: 'Failed to fetch comment' }); - console.log(error) - } -} - -export async function updateCommentController(req: Request, res: Response) { - const { post_id, comment_id, user_id} = req.params; - const comment = await getComment(post_id, comment_id) - if (comment?.owner_id == user_id){ - const updatedComment = req.body; - try { - await updateComment(post_id, comment_id, updatedComment); - res.status(200).json({ message: 'Comment updated successfully' }); - } catch (error) { - res.status(500).json({ error: 'Failed to update comment' }); - console.log(error) - } - } else { - res.status(401).json({ error: 'You do not have permission to try this.'}); - } -} - -export async function deleteCommentController(req: Request, res: Response) { - const { post_id, comment_id, user_id} = req.params; - const comment = await getComment(post_id, comment_id) - if (comment?.owner_id == user_id){ - try { - await deleteComment(post_id, comment_id); - res.status(200).json({ message: 'Comment deleted successfully' }); - } catch (error) { - res.status(500).json({ error: error }); - console.log(error) - } - } else { - res.status(401).json({ error: 'You do not have permission to try this.'}); - } -} - -export async function deletePostController(req: Request, res: Response) { - const { post_id, user_id } = req.params; - const post = await ContentService.getContent(post_id) - const creator_id = post?.creatorUID - if (creator_id == user_id){ - try { - await deletePost(post_id); - res.status(200).json({ message: 'Post (entire comment tree) deleted successfully' }); - } catch (error) { - res.status(500).json({ error: error + " " + post_id}); - console.log(error) - } - } else { - res.status(401).json({ error: 'You do not have permission to try this.'}); - } -} - -export async function getCommentsByPostController(req: Request, res: Response): Promise { - const { post_id } = req.params; - try { - const comments = await getAllComments(post_id); - - if (Object.keys(comments).length > 0) { - res.status(200).json(comments); - } else { - res.status(200).json(null); - } - } catch (error) { - console.error('Error fetching comments:', error); - res.status(500).json({ error: 'Failed to fetch comments' }); - console.log("GET ALL COMMENTS ERROR: ", error) - } -} diff --git a/backend/src/modules/comment/routes/comment.routes.ts b/backend/src/modules/comment/routes/comment.routes.ts deleted file mode 100644 index 9314dfd..0000000 --- a/backend/src/modules/comment/routes/comment.routes.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Router } from 'express'; -import { - updateCommentController, - createCommentController, - deleteCommentController, - getCommentsByPostController, - getCommentByIdController, deletePostController -} from '../controllers/comment.controller'; -const router = Router(); - -router.post('/comments/:post_id', createCommentController); -router.get('/comments/:post_id/', getCommentsByPostController); -router.get('/comments/:post_id/:comment_id', getCommentByIdController); -router.put('/comments/:post_id/:comment_id/:user_id', updateCommentController); -router.delete('/post/:post_id/:user_id', deletePostController); -router.delete('/comments/:post_id/:comment_id/:user_id', deleteCommentController); - -export default router; diff --git a/backend/src/modules/content/controllers/comment.controller.ts b/backend/src/modules/content/controllers/comment.controller.ts new file mode 100644 index 0000000..e5509ab --- /dev/null +++ b/backend/src/modules/content/controllers/comment.controller.ts @@ -0,0 +1,118 @@ +import { + createComment, + deleteComment, + deletePost, + getAllComments, + getComment, + updateComment, +} from "../services/comment.service"; +import { ContentService } from "../services/content.service"; +import { Request, Response } from "express"; +import { getUser } from "../../user/services/user.service"; + +export async function createCommentController( + req: Request, + res: Response +): Promise { + const { post_id } = req.params; + const { owner_id, text } = req.body; + try { + const response = await getUser(owner_id); + const creation = await createComment( + post_id, + owner_id, + text, + response?.username + ); + res.status(201).json({ message: "Comment created successfully", creation }); + } catch (error) { + console.log(error); + console.log(post_id, owner_id, text); + res.status(500).json({ error: error }); + } +} + +export async function getCommentByIdController(req: Request, res: Response) { + const { post_id, comment_id } = req.params; + try { + const comment = await getComment(post_id, comment_id); + console.log(comment); + if (comment) res.status(200).json(comment); + else res.status(404).json(null); + } catch (error) { + res.status(500).json({ error: "Failed to fetch comment" }); + console.log(error); + } +} + +export async function updateCommentController(req: Request, res: Response) { + const { post_id, comment_id, user_id } = req.params; + const comment = await getComment(post_id, comment_id); + if (comment?.owner_id == user_id) { + const updatedComment = req.body; + try { + await updateComment(post_id, comment_id, updatedComment); + res.status(200).json({ message: "Comment updated successfully" }); + } catch (error) { + res.status(500).json({ error: "Failed to update comment" }); + console.log(error); + } + } else { + res.status(401).json({ error: "You do not have permission to try this." }); + } +} + +export async function deleteCommentController(req: Request, res: Response) { + const { post_id, comment_id, user_id } = req.params; + const comment = await getComment(post_id, comment_id); + if (comment?.owner_id == user_id) { + try { + await deleteComment(post_id, comment_id); + res.status(200).json({ message: "Comment deleted successfully" }); + } catch (error) { + res.status(500).json({ error: error }); + console.log(error); + } + } else { + res.status(401).json({ error: "You do not have permission to try this." }); + } +} + +export async function deletePostController(req: Request, res: Response) { + const { post_id, user_id } = req.params; + const post = await ContentService.getContent(post_id); + const creator_id = post?.creatorUID; + if (creator_id == user_id) { + try { + await deletePost(post_id); + res + .status(200) + .json({ message: "Post (entire comment tree) deleted successfully" }); + } catch (error) { + res.status(500).json({ error: error + " " + post_id }); + console.log(error); + } + } else { + res.status(401).json({ error: "You do not have permission to try this." }); + } +} + +export async function getCommentsByPostController( + req: Request, + res: Response +): Promise { + const { post_id } = req.params; + try { + const comments = await getAllComments(post_id); + + if (Object.keys(comments).length > 0) { + res.status(200).json(comments); + } else { + res.status(200).json(null); + } + } catch (error) { + console.error("Error fetching comments:", error); + res.status(500).json({ error: "Failed to fetch comments" }); + console.log("GET ALL COMMENTS ERROR: ", error); + } +} diff --git a/backend/src/modules/comment/models/comment.model.ts b/backend/src/modules/content/models/comment.model.ts similarity index 100% rename from backend/src/modules/comment/models/comment.model.ts rename to backend/src/modules/content/models/comment.model.ts diff --git a/backend/src/modules/content/routes/comment.routes.ts b/backend/src/modules/content/routes/comment.routes.ts new file mode 100644 index 0000000..6264754 --- /dev/null +++ b/backend/src/modules/content/routes/comment.routes.ts @@ -0,0 +1,46 @@ +import { Router } from "express"; +import { + updateCommentController, + createCommentController, + deleteCommentController, + getCommentsByPostController, + getCommentByIdController, +} from "../controllers/comment.controller"; +import { authenticateToken } from "../../../shared/middleware/auth"; + +const commentRouter = Router(); + +// Post routes +commentRouter.post( + "/:contentId/comment", + authenticateToken, + createCommentController +); + +// Get routes +commentRouter.get( + "/:contentId/comments", + authenticateToken, + getCommentsByPostController +); +commentRouter.get( + "/:contentId/comment/:commentId", + authenticateToken, + getCommentByIdController +); + +// Put routes +commentRouter.put( + "/:contentId/comment/:commentId", + authenticateToken, + updateCommentController +); + +// Delete routes +commentRouter.delete( + "/:contentId/comment/:commentId", + authenticateToken, + deleteCommentController +); + +export default commentRouter; diff --git a/backend/src/modules/content/routes/content.routes.ts b/backend/src/modules/content/routes/content.routes.ts index ef65d6c..1105999 100644 --- a/backend/src/modules/content/routes/content.routes.ts +++ b/backend/src/modules/content/routes/content.routes.ts @@ -1,5 +1,6 @@ import { Router } from "express"; import { ContentController } from "../controllers/content.controller"; +import commentRouter from "./comment.routes"; const contentRoutes = Router(); @@ -7,7 +8,10 @@ contentRoutes.post("/", ContentController.createContent); // Create new content contentRoutes.post("/uploadThumbnail", ContentController.uploadThumbnail); // Upload thumbnail contentRoutes.get("/feed/trending", ContentController.getTrendingContent); // Get trending content -contentRoutes.get("/feed/creators/:userId", ContentController.getRelatedContentCreators); // Get related content creators +contentRoutes.get( + "/feed/creators/:userId", + ContentController.getRelatedContentCreators +); // Get related content creators contentRoutes.get("/feed/:userId", ContentController.getPersonalizedContent); // Get personalized content contentRoutes.get("/related/:contentId", ContentController.getRelatedContent); // Get related content @@ -49,4 +53,6 @@ contentRoutes.post( ContentController.unshareContent ); // Unshare content +contentRoutes.use("/", commentRouter); + export default contentRoutes; diff --git a/backend/src/modules/comment/services/comment.service.ts b/backend/src/modules/content/services/comment.service.ts similarity index 98% rename from backend/src/modules/comment/services/comment.service.ts rename to backend/src/modules/content/services/comment.service.ts index b7bf2fa..5b7cd4e 100644 --- a/backend/src/modules/comment/services/comment.service.ts +++ b/backend/src/modules/content/services/comment.service.ts @@ -3,7 +3,7 @@ import { ref, get, set, remove, update, child, push } from "firebase/database"; import { Comment } from "../models/comment.model"; import { pushNotification } from "../../notification/services/notification.service"; import { Notification } from "../../notification/models/notification.model"; -import { ContentService } from "../../content/services/content.service"; +import { ContentService } from "./content.service"; export async function createComment( post_id: string, diff --git a/backend/src/modules/subscription/services/stripe.service.ts b/backend/src/modules/subscription/services/stripe.service.ts index 15e6337..a9c3105 100644 --- a/backend/src/modules/subscription/services/stripe.service.ts +++ b/backend/src/modules/subscription/services/stripe.service.ts @@ -1,9 +1,10 @@ -import Stripe from 'stripe'; -import dotenv from 'dotenv'; +import Stripe from "stripe"; +import dotenv from "dotenv"; dotenv.config(); -const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || '', { - apiVersion: '2025-05-28.basil', + +const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", { + apiVersion: "2025-05-28.basil", }); /** @@ -24,7 +25,7 @@ export class StripeService { }); return customer; } catch (error) { - console.error('Error creating Stripe customer:', error); + console.error("Error creating Stripe customer:", error); throw error; } } @@ -46,20 +47,20 @@ export class StripeService { try { const session = await stripe.checkout.sessions.create({ customer: customerId, - payment_method_types: ['card'], + payment_method_types: ["card"], line_items: [ { price: priceId, quantity: 1, }, ], - mode: 'subscription', + mode: "subscription", success_url: successUrl, cancel_url: cancelUrl, }); return session; } catch (error) { - console.error('Error creating checkout session:', error); + console.error("Error creating checkout session:", error); throw error; } } @@ -74,7 +75,7 @@ export class StripeService { const subscription = await stripe.subscriptions.retrieve(subscriptionId); return subscription; } catch (error) { - console.error('Error retrieving subscription:', error); + console.error("Error retrieving subscription:", error); throw error; } } @@ -95,7 +96,7 @@ export class StripeService { }); return subscription; } catch (error) { - console.error('Error canceling subscription:', error); + console.error("Error canceling subscription:", error); throw error; } } @@ -108,7 +109,7 @@ export class StripeService { */ constructWebhookEvent(payload: string, signature: string): Stripe.Event { try { - const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET || ''; + const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET || ""; const event = stripe.webhooks.constructEvent( payload, signature, @@ -116,7 +117,7 @@ export class StripeService { ); return event; } catch (error) { - console.error('Error constructing webhook event:', error); + console.error("Error constructing webhook event:", error); throw error; } } @@ -126,12 +127,16 @@ export class StripeService { * @param paymentIntentId Stripe payment intent ID * @returns Payment intent object */ - async getPaymentIntent(paymentIntentId: string): Promise { + async getPaymentIntent( + paymentIntentId: string + ): Promise { try { - const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId); + const paymentIntent = await stripe.paymentIntents.retrieve( + paymentIntentId + ); return paymentIntent; } catch (error) { - console.error('Error retrieving payment intent:', error); + console.error("Error retrieving payment intent:", error); throw error; } } @@ -152,7 +157,7 @@ export class StripeService { }); return subscription; } catch (error) { - console.error('Error updating subscription payment method:', error); + console.error("Error updating subscription payment method:", error); throw error; } } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 5cdfb21..7dfb9b9 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,6 +1,8 @@ import { Route, BrowserRouter as Router, Routes } from "react-router-dom"; import Footer from "./components/Footer"; -import AuthProvider from "./hooks/AuthProvider"; +import AuthProvider from "./hooks/AuthProvider/AuthProvider"; +import { ToastProvider } from "./hooks/ToastProvider/ToastProvider"; + import NavbarWrapper from "./components/NavbarWrapper"; import Background from "./components/Background"; import Feed from "./pages/Feed"; @@ -59,55 +61,59 @@ import NotFound from "./pages/error/404"; export default function App() { return ( - - - - - {/* ROUTER */} - - {/* HOME/FEED */} - } /> - - {/* AUTHENTICATION */} - } /> - } /> - } - /> - } /> - } /> - - {/* PROFILE */} - } /> - } /> - - {/* CONTACT */} - } /> - } /> - - {/* LEGAL */} - } /> - } /> - } /> - } /> - } /> - - {/* CONTENT */} - } /> - } /> - } /> - - {/* PRO */} - } /> - } /> - } /> - - {/* 404 */} - } /> - -