From 7a691e4bbc0550cdfa54d313840041c13ffa0f8e Mon Sep 17 00:00:00 2001 From: Izam Mohammed Date: Sat, 9 Mar 2024 21:11:04 +0530 Subject: [PATCH 01/26] feat: added the toxicity for the ai bot --- ai_server/ai_server/settings.py | 1 + ai_server/ai_server/urls.py | 3 +- ai_server/chat/llm_call.py | 33 +++++++++---- ai_server/chat/urls.py | 3 +- ai_server/chat/views.py | 7 --- ai_server/toxicity/__init__.py | 0 ai_server/toxicity/admin.py | 3 ++ ai_server/toxicity/apps.py | 6 +++ ai_server/toxicity/hf_call.py | 57 +++++++++++++++++++++++ ai_server/toxicity/migrations/__init__.py | 0 ai_server/toxicity/models.py | 3 ++ ai_server/toxicity/tests.py | 3 ++ ai_server/toxicity/urls.py | 6 +++ ai_server/toxicity/views.py | 39 ++++++++++++++++ 14 files changed, 145 insertions(+), 19 deletions(-) create mode 100644 ai_server/toxicity/__init__.py create mode 100644 ai_server/toxicity/admin.py create mode 100644 ai_server/toxicity/apps.py create mode 100644 ai_server/toxicity/hf_call.py create mode 100644 ai_server/toxicity/migrations/__init__.py create mode 100644 ai_server/toxicity/models.py create mode 100644 ai_server/toxicity/tests.py create mode 100644 ai_server/toxicity/urls.py create mode 100644 ai_server/toxicity/views.py diff --git a/ai_server/ai_server/settings.py b/ai_server/ai_server/settings.py index 8e0ebc8..8b04ffe 100644 --- a/ai_server/ai_server/settings.py +++ b/ai_server/ai_server/settings.py @@ -40,6 +40,7 @@ "rest_framework", "corsheaders", "chat", + "toxicity", ] MIDDLEWARE = [ diff --git a/ai_server/ai_server/urls.py b/ai_server/ai_server/urls.py index 5d9ad7d..a35d787 100644 --- a/ai_server/ai_server/urls.py +++ b/ai_server/ai_server/urls.py @@ -19,7 +19,8 @@ urlpatterns = [ # path("admin/", admin.site.urls), - path("", include("chat.urls")) + path("chat", include("chat.urls")), + path("toxic", include("toxicity.urls")), ] handler404 = "utils.exception_handler.error_404" diff --git a/ai_server/chat/llm_call.py b/ai_server/chat/llm_call.py index 5c52644..9bb5ee6 100644 --- a/ai_server/chat/llm_call.py +++ b/ai_server/chat/llm_call.py @@ -5,26 +5,41 @@ from langchain_core.output_parsers import StrOutputParser from .prompt import PROMPT -def call(input: str) -> Dict[str, Union[bool, str]]: - if "OPENAI_API_KEY" not in os.environ: +def call(user_input: str) -> Dict[str, Union[bool, str]]: + """ + Calls the OpenAI Chat API to generate a response. + + Args: + user_input (str): The input text to generate a response for. + + Returns: + Dict[str, Union[bool, str]]: A dictionary containing the success status and the generated response. + """ + if "OPENAI_API_KEY" not in os.environ or not os.environ["OPENAI_API_KEY"]: return { "success": False, - "message": "OpenAI API key not found", - } + "message": "OpenAI API key not found or empty", + } prompt = ChatPromptTemplate.from_template(PROMPT) model = ChatOpenAI(temperature=0) - chain = prompt | model | StrOutputParser() - - response:str = chain.invoke({"prompt": input}) + chain = prompt | model | StrOutputParser() + try: + response: str = chain.invoke({"prompt": user_input}) + except Exception as e: + return { + "success": False, + "message": f"Error in generation: {str(e)}", + } + if not response: return { "success": False, "message": "Error in generation", - } + } return { "success": True, "message": response, - } + } diff --git a/ai_server/chat/urls.py b/ai_server/chat/urls.py index e369ae5..a772ce9 100644 --- a/ai_server/chat/urls.py +++ b/ai_server/chat/urls.py @@ -2,6 +2,5 @@ from . import views urlpatterns = [ - path("", views.home, name="home"), - path('chat', views.index, name="routes"), + path("", views.index, name="chat"), ] \ No newline at end of file diff --git a/ai_server/chat/views.py b/ai_server/chat/views.py index 9585fe0..9cb51bf 100644 --- a/ai_server/chat/views.py +++ b/ai_server/chat/views.py @@ -4,13 +4,6 @@ from rest_framework import status from .llm_call import call as llm_call -@api_view(["GET", "POST"]) -def home(request): - return Response( - {"success":True ,"message":"connected successfully"}, - status=status.HTTP_200_OK - ) - @api_view(["POST"]) def index(request): content: dict = request.data diff --git a/ai_server/toxicity/__init__.py b/ai_server/toxicity/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ai_server/toxicity/admin.py b/ai_server/toxicity/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/ai_server/toxicity/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/ai_server/toxicity/apps.py b/ai_server/toxicity/apps.py new file mode 100644 index 0000000..5b2195d --- /dev/null +++ b/ai_server/toxicity/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ToxicityConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "toxicity" diff --git a/ai_server/toxicity/hf_call.py b/ai_server/toxicity/hf_call.py new file mode 100644 index 0000000..a14034d --- /dev/null +++ b/ai_server/toxicity/hf_call.py @@ -0,0 +1,57 @@ +from typing import Dict, Union, List +import requests +import os + +RESPONSE_TYPE = Dict[str, Union[str, float]] + + +def _transform_response(response: List[List[RESPONSE_TYPE]]) -> RESPONSE_TYPE: + """ + Transforms the response from the API call. + + Args: + response (List[List[RESPONSE_TYPE]]): The response from the API call. + + Returns: + RESPONSE_TYPE: The transformed response. + """ + if response[0][0]["score"] > response[0][1]["score"]: + return response[0][0] + return response[0][1] + + +def call(text: str) -> RESPONSE_TYPE: + """ + Calls the Hugging Face API to classify toxic comments. + + Args: + text (str): The text to classify. + + Returns: + RESPONSE_TYPE: The response from the API. + """ + if "HF_TOKEN" not in os.environ or not os.environ["HF_TOKEN"]: + return { + "success": False, + "message": "Huggingface Token not found or empty", + } + + HF_TOKEN = os.environ["HF_TOKEN"] + headers = {"Authorization": f"Bearer {HF_TOKEN}"} + api_url = ( + "https://api-inference.huggingface.co/models/martin-ha/toxic-comment-model" + ) + + response = requests.post(api_url, headers=headers, json={"inputs": text}) + + if response.status_code != 200: + return { + "success": False, + "message": f"API returned status code {response.status_code}", + } + + response_data = response.json() + transformed_response = _transform_response(response_data) + transformed_response["success"] = True + + return transformed_response diff --git a/ai_server/toxicity/migrations/__init__.py b/ai_server/toxicity/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ai_server/toxicity/models.py b/ai_server/toxicity/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/ai_server/toxicity/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/ai_server/toxicity/tests.py b/ai_server/toxicity/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/ai_server/toxicity/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/ai_server/toxicity/urls.py b/ai_server/toxicity/urls.py new file mode 100644 index 0000000..6d2f8a7 --- /dev/null +++ b/ai_server/toxicity/urls.py @@ -0,0 +1,6 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path("", views.index, name="toxic"), +] \ No newline at end of file diff --git a/ai_server/toxicity/views.py b/ai_server/toxicity/views.py new file mode 100644 index 0000000..1e83572 --- /dev/null +++ b/ai_server/toxicity/views.py @@ -0,0 +1,39 @@ +from typing import Dict, Union +from rest_framework.decorators import api_view +from rest_framework.response import Response +from rest_framework import status +from .hf_call import call as hf_call + +@api_view(["POST"]) +def index(request): + content: dict = request.data + text = content.get("text") + if text is None: + return Response( + {"success": False, "message": "text is required !"}, + status=status.HTTP_400_BAD_REQUEST, + ) + if not isinstance(text, str): + return Response( + {"success": False, "message": "text should be str !"}, + status=status.HTTP_400_BAD_REQUEST, + ) + if not text: + return Response( + {"success": False, "message": "query should not be empty"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + response:Dict[str, Union[bool, str]] = hf_call(text=text) + + if not response["success"]: + return Response( + response, + status=status.HTTP_500_INTERNAL_SERVER_ERROR, + ) + + return Response( + response, + status=status.HTTP_200_OK, + ) + From 71469f19b038d4b12012801a9b9d4a73d6842708 Mon Sep 17 00:00:00 2001 From: Sreesanjay Date: Sat, 9 Mar 2024 22:53:38 +0530 Subject: [PATCH 02/26] feat: added user management --- server/app.js | 2 +- server/controller/adminUser.js | 118 ++++++++++++++++++++++++++++ server/controller/myMind.js | 106 +++++++++++++++++++++++++ server/controller/userController.js | 110 ++++++++++++++++++++++++++ server/models/myMind.js | 14 ++++ server/models/reportsModel.js | 21 +++++ server/routes/adminMindRoute.js | 10 +++ server/routes/adminRoute.js | 4 + server/routes/adminUserRoute.js | 9 +++ server/routes/communityRoute.js | 4 + server/routes/indexRoute.js | 31 ++++++++ server/routes/userMyMindRoute.js | 7 ++ server/routes/userRoute.js | 26 ++---- 13 files changed, 440 insertions(+), 22 deletions(-) create mode 100644 server/controller/adminUser.js create mode 100644 server/controller/myMind.js create mode 100644 server/controller/userController.js create mode 100644 server/models/myMind.js create mode 100644 server/models/reportsModel.js create mode 100644 server/routes/adminMindRoute.js create mode 100644 server/routes/adminUserRoute.js create mode 100644 server/routes/indexRoute.js create mode 100644 server/routes/userMyMindRoute.js diff --git a/server/app.js b/server/app.js index 839fe89..f6442af 100644 --- a/server/app.js +++ b/server/app.js @@ -7,7 +7,7 @@ const morgan = require('morgan') const cookieParser = require('cookie-parser'); const { notFound, errorHandler } = require('./middlewares/errorMiddlewares') -const userRoute = require('./routes/userRoute.js') +const userRoute = require('./routes/indexRoute.js') const adminRoute = require('./routes/adminRoute.js') const ORIGIN = process.env.NODE_ENV === 'development' ? "http://localhost:4000" : 'https://thalia.vercel.app' const corsConfig = { diff --git a/server/controller/adminUser.js b/server/controller/adminUser.js new file mode 100644 index 0000000..728d68d --- /dev/null +++ b/server/controller/adminUser.js @@ -0,0 +1,118 @@ +const User = require('../models/userModel') +// const Profile = require('../models/profileModel') +// const Report = require('../models/reportsModel') + +/** + * @desc request fetching all users + * @route GET /api/admin/users?search + * @access private + */ +const getUserList = async (req, res, next) => { + const search = req.query.search; + try { + const userList = await User.aggregate([ + { + $match: { + role: 'USER' + } + }, + { + $lookup: { + from: "profiles", + localField: '_id', + foreignField: "user_id", + as: "profile" + } + }, + { + $unwind: { + path: '$profile' + } + }, + { + $project: { + email: 1, + role: 1, + is_blocked: 1, + username: "$profile.username", + fullname: "$profile.fullname", + profile_img: "$profile.profile_img", + bio: "$profile.bio" + } + }, + { + $lookup: { + from: "reports", + localField: '_id', + foreignField: "report_id", + as: "reports" + } + }, + { + $match: { + $or: [ + { username: { $regex: new RegExp(search, 'i') } }, + { fullname: { $regex: new RegExp(search, 'i') } } + ], + } + } + ]) + res.status(200).json({ + success: true, + message: "users list fetched", + userList + }) + } catch (error) { + next(error.message) + } +} + +/** + * @desc request for blocking user + * @route GET /api/admin/users/block/:id + * @access private + */ + +const blockUser = async (req, res, next) => { + try { + const block = await User.findOneAndUpdate({ _id: req.params.id }, { $set: { is_blocked: true } }, { new: true }); + if (block.is_blocked) { + res.status(200).json({ + success: true, + message: "user blocked" + }) + } else { + throw new Error("Internal server error") + } + } catch (error) { + next(error.message) + } +} + +/** + * @desc request for unblocking user + * @route GET /api/admin/users/unblock/:id + * @access private + */ + +const unblockUser = async (req, res, next) => { + try { + const block = await User.findOneAndUpdate({ _id: req.params.id }, { $set: { is_blocked: false } }, { new: true }); + if (!block.is_blocked) { + res.status(200).json({ + success: true, + message: "user unblocked" + }) + } else { + throw new Error("Internal server error") + } + } catch (error) { + next(error.message) + } +} + +module.exports = { + getUserList, + blockUser, + unblockUser +} \ No newline at end of file diff --git a/server/controller/myMind.js b/server/controller/myMind.js new file mode 100644 index 0000000..00cff41 --- /dev/null +++ b/server/controller/myMind.js @@ -0,0 +1,106 @@ +const MyMind = require('../models/myMind') + +/** + * @desc request fetching all content + * @route GET /api/admin/my-body?page=1&&search='aa' + * @access private + */ +const getContents = async (req, res, next) => { + try { + const page = req.query.page; + const search = req.query.search + const count = await MyMind.countDocuments() + const contents = await MyMind.find({ name: { $regex: new RegExp(search, 'i') } }).skip((page - 1) * 10).limit(10); + res.status(200).json({ + success: true, + message: 'all contents fetched', + contents, + count + }) + } catch (error) { + next(error.message); + } +} + +/** + * @desc request for creating content + * @route POST /api/admin/my-body + * @access private + */ +const createContent = async (req, res, next) => { + try { + const { name, content } = req.body; + if (!name || !content) { + res.status(400); + throw new Error('Details missing') + } + const newContent = await new MyMind({ + name, content + }).save() + if (newContent) { + res.status(201).json({ + success: true, + message: 'new content created successfully', + newContent + }) + } else { + throw new Error('Internal server error') + } + } catch (error) { + next(error.message); + } +} + +/** + * @desc request for updating content + * @route PUT /api/admin/my-body/:id + * @access private + */ +const updateContent = async (req, res, next) => { + try { + if (!req.params.id) { + res.status(400) + throw new Error('content not found') + } + const content = await MyMind.findOneAndUpdate({ _id: req.params.id }, { $set: { ...req.body } }, { new: true }) + if (content) { + res.status(200).json({ + success: true, + message: 'content updated successfully', + content + }) + } else { + throw new Error('Internal server error') + } + } catch (error) { + next(error.message); + } +} + +/** + * @desc request for deleting content + * @route delete /api/admin/my-body/:id + * @access private + */ +const deleteContent = async (req, res, next) => { + try { + if (!req.params.id) { + res.status(400) + throw new Error('Content not found') + } + await MyMind.findOneAndDelete({ _id: req.params.id }) + res.status(200).json({ + success: true, + message: 'content deleted successfully' + }) + } catch (error) { + next(error.message); + } +} + +module.exports = { + getContents, + createContent, + updateContent, + deleteContent +} \ No newline at end of file diff --git a/server/controller/userController.js b/server/controller/userController.js new file mode 100644 index 0000000..74493d9 --- /dev/null +++ b/server/controller/userController.js @@ -0,0 +1,110 @@ +const User = require('../models/userModel') +const Profile = require('../models/profileModel') +const Report = require('../models/reportsModel') + +/** + * @desc request fetching all users + * @route GET /api/users?search + * @access private + */ +const getUsers = async (req, res, next) => { + const search = req.query.search; + try { + const userList = await User.aggregate([ + { + $match: { + is_blocked: false, + role: 'USER' + } + }, + { + $lookup: { + from: "profiles", + localField: '_id', + foreignField: "user_id", + as: "profile" + } + }, + { + $unwind: { + path: '$profile' + } + }, + { + $project: { + email: 1, + role: 1, + is_blocked: 1, + username: "$profile.username", + fullname: "$profile.fullname", + profile_img: "$profile.profile_img", + bio: "$profile.bio" + } + }, + { + $match: { + $or: [ + { username: { $regex: new RegExp(search, 'i') } }, + { fullname: { $regex: new RegExp(search, 'i') } } + ], + } + } + ]) + res.status(200).json({ + success: true, + message: "users list fetched", + userList + }) + } catch (error) { + next(error.message) + } +} + + +/** + * @desc request fetching user profile + * @route GET /api/users/:id + * @access private + */ +const getUserDetails = async (req, res, next) => { + try { + const userDetails = await Profile.findOne({ user_id: req.params.id }, { _id: 0, username: 1, fullname: 1 }) + res.status(200).json({ + success: true, + message: "user details fetched", + userDetails + }) + } catch (error) { + next(error.message) + } +} + + +/** + * @desc request for report user + * @route GET /api/users/report + * @access private + */ +const reportUser = async (req, res, next) => { + try { + const report = await new Report({ + report_id: req.body.user_id, + reporter_id: req.user._id, + report_type: req.body.report_type, + reason: req.body.reason + }).save() + res.status(200).json({ + success: true, + message: "new report added", + report + }) + } catch (error) { + next(error.message) + } +} + +module.exports = { + getUsers, + getUserDetails, + reportUser +} \ No newline at end of file diff --git a/server/models/myMind.js b/server/models/myMind.js new file mode 100644 index 0000000..cc885bd --- /dev/null +++ b/server/models/myMind.js @@ -0,0 +1,14 @@ +const mongoose = require("mongoose"); + +const myMindSchema = new mongoose.Schema({ + name: { + type: String, + required: true + }, + content: { + type: String, + required: true + }, +}, { timestamps: true }); + +module.exports = mongoose.model("MyMind", myMindSchema); \ No newline at end of file diff --git a/server/models/reportsModel.js b/server/models/reportsModel.js new file mode 100644 index 0000000..51da2f1 --- /dev/null +++ b/server/models/reportsModel.js @@ -0,0 +1,21 @@ +const mongoose = require("mongoose"); + +const reportSchema = new mongoose.Schema({ + report_id: { + type: mongoose.Types.ObjectId, + required: true + }, + reporter_id: { + type: mongoose.Types.ObjectId, + required: true + }, + report_type: { + type: String, + enum: ['USER', 'COMMUNITY'] + }, + reason: { + type: String, + } +}, { timestamps: true }); + +module.exports = mongoose.model("Report", reportSchema); \ No newline at end of file diff --git a/server/routes/adminMindRoute.js b/server/routes/adminMindRoute.js new file mode 100644 index 0000000..ef52987 --- /dev/null +++ b/server/routes/adminMindRoute.js @@ -0,0 +1,10 @@ +const express = require('express'); +const { isAdminLogedIn } = require('../middlewares/authMiddleware'); +const { getContents, createContent, updateContent, deleteContent } = require('../controller/myMind') +const router = express.Router(); + +router.get('/', isAdminLogedIn, getContents) +router.post('/', isAdminLogedIn, createContent) +router.put('/:id', isAdminLogedIn, updateContent) +router.delete('/:id', isAdminLogedIn, deleteContent) +module.exports = router; \ No newline at end of file diff --git a/server/routes/adminRoute.js b/server/routes/adminRoute.js index 4e33dfc..ec4cba9 100644 --- a/server/routes/adminRoute.js +++ b/server/routes/adminRoute.js @@ -3,7 +3,11 @@ const router = express.Router(); const adminRightsRoute = require('./adminRightsRoute') const adminBodyRoute = require('./adminBodyRoute') const adminCommunity = require('./adminCommunity') +const adminMindRoute = require('./adminMindRoute') +const adminUserRoute = require('./adminUserRoute') router.use('/rights', adminRightsRoute) router.use('/my-body', adminBodyRoute) +router.use('/my-mind', adminMindRoute) router.use('/community', adminCommunity) +router.use('/users', adminUserRoute) module.exports = router; \ No newline at end of file diff --git a/server/routes/adminUserRoute.js b/server/routes/adminUserRoute.js new file mode 100644 index 0000000..9fef735 --- /dev/null +++ b/server/routes/adminUserRoute.js @@ -0,0 +1,9 @@ +const express = require('express'); +const router = express.Router(); +const { isAdminLogedIn } = require('../middlewares/authMiddleware'); +const { getUserList, blockUser, unblockUser } = require('../controller/adminUser') + +router.get('/', isAdminLogedIn, getUserList) +router.put('/block/:id', isAdminLogedIn, blockUser) +router.put('/unblock/:id', isAdminLogedIn, unblockUser) +module.exports = router; \ No newline at end of file diff --git a/server/routes/communityRoute.js b/server/routes/communityRoute.js index 7c742c9..374775a 100644 --- a/server/routes/communityRoute.js +++ b/server/routes/communityRoute.js @@ -8,4 +8,8 @@ router.post('/', isLogedIn, createCommunity) router.post('/join', isLogedIn, joinCommunity) router.post('/accept-join', isLogedIn, acceptJoin) router.get('/my-communities', isLogedIn, getmyCommunities) + + +//discussion + module.exports = router; \ No newline at end of file diff --git a/server/routes/indexRoute.js b/server/routes/indexRoute.js new file mode 100644 index 0000000..df7a3ce --- /dev/null +++ b/server/routes/indexRoute.js @@ -0,0 +1,31 @@ +const express = require('express'); +const router = express.Router(); +const { signup, verifyMail, verifyOtp, signin } = require('../controller/authController'); +const profileRoute = require('./profileRoute') +const userRightsRoute = require('./userRightsRoute') +const userMyBodyRoute = require('./userMyBodyRoute') +const userMyMindRoute = require('./userMyMindRoute') +const communityRoute = require('./communityRoute') +const userRoute = require('./userRoute') + +//authentication +router.post('/signup', signup) +router.post('/verify-mail', verifyMail) +router.post('/verify-otp', verifyOtp) +router.post('/signin', signin) + +router.use('/profile', profileRoute) +router.use('/rights', userRightsRoute) +router.use('/my-body', userMyBodyRoute) +router.use('/my-mind', userMyMindRoute) +router.use('/community', communityRoute) +router.use('/users', userRoute) + +router.post('/chat', (req, res) => { + res.status(200).json({ + success: true, + message: "this is the response for " + req.body.query.slice(0, 10) + }) +}) + +module.exports = router; \ No newline at end of file diff --git a/server/routes/userMyMindRoute.js b/server/routes/userMyMindRoute.js new file mode 100644 index 0000000..5c118c3 --- /dev/null +++ b/server/routes/userMyMindRoute.js @@ -0,0 +1,7 @@ +const express = require('express'); +const { isLogedIn } = require('../middlewares/authMiddleware'); +const { getContents } = require('../controller/myMind') +const router = express.Router(); + +router.get('/', isLogedIn, getContents) +module.exports = router; \ No newline at end of file diff --git a/server/routes/userRoute.js b/server/routes/userRoute.js index 87c5aed..5d0737d 100644 --- a/server/routes/userRoute.js +++ b/server/routes/userRoute.js @@ -1,26 +1,10 @@ const express = require('express'); +const { isLogedIn } = require('../middlewares/authMiddleware'); const router = express.Router(); -const { signup, verifyMail, verifyOtp, signin } = require('../controller/authController'); -const profileRoute = require('./profileRoute') -const userRightsRoute = require('./userRightsRoute') -const userMyBodyRoute = require('./userMyBodyRoute') -const communityRoute = require('./communityRoute') -//authentication -router.post('/signup', signup) -router.post('/verify-mail', verifyMail) -router.post('/verify-otp', verifyOtp) -router.post('/signin', signin) +const { getUsers, getUserDetails, reportUser } = require('../controller/userController') -router.use('/profile', profileRoute) -router.use('/rights', userRightsRoute) -router.use('/my-body', userMyBodyRoute) -router.use('/community', communityRoute) - -router.post('/chat', (req, res) => { - res.status(200).json({ - success: true, - message: "this is the response for " + req.body.query.slice(0, 10) - }) -}) +router.get('/', isLogedIn, getUsers) +router.get('/:id', isLogedIn, getUserDetails) +router.post('/report', isLogedIn, reportUser) module.exports = router; \ No newline at end of file From f7a2d05aaa9c6bb74f18c98a76b44001f9b62845 Mon Sep 17 00:00:00 2001 From: Sreesanjay Date: Sat, 9 Mar 2024 22:57:34 +0530 Subject: [PATCH 03/26] feat: added discussion model --- server/models/discussionModel.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 server/models/discussionModel.js diff --git a/server/models/discussionModel.js b/server/models/discussionModel.js new file mode 100644 index 0000000..c09e4ee --- /dev/null +++ b/server/models/discussionModel.js @@ -0,0 +1,32 @@ +const mongoose = require("mongoose"); + +const discussionSchema = new mongoose.Schema({ + community_id: { + type: mongoose.Types.ObjectId, + ref: 'Community', + required: true + }, + user_id: { + type: mongoose.Types.ObjectId, + ref: 'User', + required: true + }, + content: { + type: 'string', + required: true + }, + likes: [ + { + type: mongoose.Types.ObjectId, + ref: 'User', + default: [] + } + ], + caption: { type: 'string' }, + content_type: { type: 'string', enum: ['MEDIA', 'TEXT'] }, + file_type: { type: 'string', enum: ['IMAGE', 'VIDEO'] }, + is_delete: { type: Boolean, default: false } + +}, { timestamps: true }); + +module.exports = mongoose.model("Discussion", discussionSchema); \ No newline at end of file From 247321b0960daa93ca732a979a0bf589a8d1988b Mon Sep 17 00:00:00 2001 From: Sreesanjay Date: Sat, 9 Mar 2024 23:52:47 +0530 Subject: [PATCH 04/26] feat: create discussion api added --- server/controller/discussion.js | 692 ++++++++++++++++++++++++++++++++ server/routes/communityRoute.js | 9 +- 2 files changed, 700 insertions(+), 1 deletion(-) create mode 100644 server/controller/discussion.js diff --git a/server/controller/discussion.js b/server/controller/discussion.js new file mode 100644 index 0000000..aed4031 --- /dev/null +++ b/server/controller/discussion.js @@ -0,0 +1,692 @@ +const Discussion = require("../models/discussionModel") + +/** + * @desc function creating discussion + * @route POST /api/community/discussions + * @access private + */ +const createDiscussion = async (req, res, next) => { + const { content, community_id, user_id } = req.body; + if (!content || !community_id || !user_id) { + res.status(400); + return next(new Error('Invalid details')); + } + const newDiscussion = await new Discussion(req.body).save() + if (newDiscussion) { + const discussion = await Discussion.aggregate([ + { + $match: { + _id: newDiscussion._id + } + }, + { + $lookup: { + from: "profiles", + localField: 'user_id', + foreignField: 'user_id', + as: 'userProfile', + pipeline: [ + { + $lookup: { + from: "users", + localField: 'user_id', + foreignField: '_id', + as: 'user', + } + }, + { + $unwind: { + path: '$user' + } + }, + { + $project: { + username: 1, + profile_img: 1, + fullname: 1, + user_id: 1, + email: '$user.email' + } + } + ] + } + }, + { + $unwind: { + path: '$userProfile' + } + } + ]) + if (discussion) { + res.status(200).json({ + status: 'created', + message: 'new discussion added', + discussion: discussion[0] + }) + } + } + +} + +// /** +// * @desc function discussions of a community +// * @route GET /api/community/discussions/:id +// * @access private +// */ +// export const getDiscussions: RequestHandler = asyncHandler( +// async (req: Request, res: Response, next: NextFunction): Promise => { +// const { id } = req.params; +// if (!id) { +// res.status(400); +// return next(new Error('community not found')) +// } + +// const page = (req.query.page && typeof (req.query.page) === "string") ? req.query.page : null +// const pageSize = 3; +// const query = page ? { +// createdAt: { $lt: new Date(page) } +// } : {} + +// const discussions = await Discussion.aggregate([ +// { +// $match: { +// community_id: new ObjectId(id), +// is_delete: false +// } +// }, +// { +// $sort: { +// createdAt: -1 +// } +// }, +// { +// $match: query +// }, +// { +// $limit: pageSize +// }, +// { +// $lookup: { +// from: "comments", +// localField: '_id', +// foreignField: 'post_id', +// as: "comments", +// } +// }, +// { +// $lookup: { +// from: "userprofiles", +// localField: 'user_id', +// foreignField: 'user_id', +// as: 'userProfile', +// pipeline: [ +// { +// $lookup: { +// from: "users", +// localField: 'user_id', +// foreignField: '_id', +// as: 'user', +// } +// }, +// { +// $unwind: { +// path: '$user' +// } +// }, +// { +// $project: { +// username: 1, +// profile_img: 1, +// fullname: 1, +// user_id: 1, +// verified: 1, +// email: '$user.email' +// } +// } +// ] +// } +// }, +// { +// $unwind: { +// path: '$userProfile' +// } +// }, +// { +// $project: { +// _id: 1, +// content: 1, +// user_id: 1, +// likes: 1, +// community_id: 1, +// content_type: 1, +// file_type: 1, +// caption: 1, +// is_delete: 1, +// createdAt: 1, +// userProfile: 1, +// comments: { $size: "$comments" }, +// } +// } +// ]) + + +// if (discussions) { +// res.status(200).json({ +// status: 'ok', +// message: 'discussion fetched', +// discussions +// }) +// } else { +// next(new Error('Internal server error')) +// } +// } +// ) + +// /** +// * @desc requst for recent discussions of a community +// * @route GET /api/community/discussions/recent +// * @access private +// */ +// export const getRecentDiscussion: RequestHandler = asyncHandler( +// async (req: Request, res: Response, next: NextFunction): Promise => { +// const page = (req.query.page && typeof (req.query.page) === "string") ? req.query.page : null +// const pageSize = 3; +// const query = page ? { +// createdAt: { $lt: new Date(page) } +// } : {} + +// const community = await Members.find({ user_id: req.user?._id, status: 'active' }) +// const communityId = community.map((item) => item.community_id); + +// const discussions = await Discussion.aggregate([ +// { +// $match: { +// community_id: { $in: communityId }, +// is_delete: false +// } +// }, +// { +// $sort: { +// createdAt: -1 +// } +// }, +// { +// $match: query +// }, +// { +// $limit: pageSize +// }, +// { +// $lookup: { +// from: "comments", +// localField: '_id', +// foreignField: 'post_id', +// as: "comments", +// } +// }, +// { +// $lookup: { +// from: "userprofiles", +// localField: 'user_id', +// foreignField: 'user_id', +// as: 'userProfile', +// pipeline: [ +// { +// $lookup: { +// from: "users", +// localField: 'user_id', +// foreignField: '_id', +// as: 'user', +// } +// }, +// { +// $unwind: { +// path: '$user' +// } +// }, +// { +// $project: { +// username: 1, +// profile_img: 1, +// fullname: 1, +// user_id: 1, +// verified: 1, +// email: '$user.email' +// } +// } +// ] +// } +// }, +// { +// $unwind: { +// path: '$userProfile' +// } +// }, +// { +// $project: { +// _id: 1, +// content: 1, +// user_id: 1, +// likes: 1, +// community_id: 1, +// content_type: 1, +// file_type: 1, +// caption: 1, +// is_delete: 1, +// createdAt: 1, +// userProfile: 1, +// comments: { $size: "$comments" }, +// } +// } +// ]) + + +// if (discussions) { +// res.status(200).json({ +// status: 'ok', +// message: 'discussion fetched', +// discussions +// }) +// } else { +// next(new Error('Internal server error')) +// } +// } +// ) + +// /** +// * @desc function for deleting a discussions +// * @route DELETE /api/community/discussions/:id +// * @access private +// */ +// export const deleteDiscussion: RequestHandler = asyncHandler( +// async (req: Request, res: Response, next: NextFunction): Promise => { +// const { id } = req.params; +// if (!id) { +// res.status(400); +// return next(new Error('discussion not found')) +// } +// const deletedDiscussion = await Discussion.findOneAndUpdate({ _id: id }, { $set: { is_delete: true } }, { new: true }) +// if (deletedDiscussion) { +// res.status(200).json({ +// status: 'ok', +// message: 'discussion deleted', +// deletedDiscussion +// }) +// } else { +// next(new Error('Internal server error')) +// } +// } +// ) + +// /** +// * @desc function for like a discussions +// * @route DELETE /api/community/discussions/like/:id +// * @access private +// */ +// export const likeDiscussion: RequestHandler = asyncHandler( +// async (req: Request, res: Response, next: NextFunction): Promise => { +// const { id } = req.params; +// if (!id) { +// res.status(400); +// return next(new Error('discussion not found')) +// } +// const likedDiscussion = await Discussion.findOneAndUpdate({ _id: id }, { $addToSet: { likes: req.user?._id } }, { new: true }) +// if (likedDiscussion) { +// res.status(200).json({ +// status: 'ok', +// message: 'discussion liked', +// likedDiscussion +// }) +// } else { +// next(new Error('Internal server error')) +// } +// } +// ) + +// /** +// * @desc function for dislike a discussions +// * @route DELETE /api/community/discussions/dislike/:id +// * @access private +// */ +// export const dislikeDiscussion: RequestHandler = asyncHandler( +// async (req: Request, res: Response, next: NextFunction): Promise => { +// const { id } = req.params; +// if (!id) { +// res.status(400); +// return next(new Error('discussion not found')) +// } +// const likedDiscussion = await Discussion.findOneAndUpdate({ _id: id }, { $pull: { likes: req.user?._id } }, { new: true }) +// if (likedDiscussion) { +// res.status(200).json({ +// status: 'ok', +// message: 'discussion disliked', +// likedDiscussion +// }) +// } else { +// next(new Error('Internal server error')) +// } +// } +// ) + +// /** +// * @desc rquest for add commment on a discussions +// * @route POST /api/community/discussions/comment +// * @access private +// */ +// export const addComment: RequestHandler = asyncHandler( +// async (req: Request, res: Response, next: NextFunction): Promise => { +// const { discussion_id } = req.body; +// if (!discussion_id) { +// res.status(400) +// return next(new Error("Invalid discussion")); +// } +// const newComment = await new Comment({ +// user_id: req.user?._id, +// post_id: req.body.discussion_id, +// content: req.body.content +// }) +// if (req.body.reply) { +// newComment.reply = req.body.reply +// } +// const comment = await newComment.save() + +// if (comment) { +// const resComment = await Comment.aggregate([ +// { +// $match: { +// _id: comment._id +// } +// }, +// { +// $lookup: { +// from: 'userprofiles', +// localField: 'user_id', +// foreignField: 'user_id', +// as: 'user_details', +// pipeline: [ +// { +// $lookup: { +// from: 'users', +// localField: 'user_id', +// foreignField: '_id', +// as: "email", +// pipeline: [ +// { +// $project: { +// _id: 0, +// email: 1 +// } +// } +// ] + +// } +// }, +// { +// $unwind: { +// path: "$email" +// } +// }, +// { +// $project: { +// username: 1, +// profile_img: 1, +// email: '$email.email' +// } +// }, + +// ] +// } +// }, { +// $unwind: { +// path: '$user_details' +// } +// }, + +// ]) +// res.status(200).json({ +// status: 'ok', +// message: 'new Comment added', +// comment: resComment[0] +// }) +// } else { +// next(new Error('Internal server error')) +// } +// } +// ) + +// /** +// * @desc rquest for fetching comments of a discussion +// * @route GET /api/community/discussions/comment/:id +// * @access private +// */ +// export const getComments: RequestHandler = asyncHandler( +// async (req: Request, res: Response, next: NextFunction): Promise => { +// const { id } = req.params; +// if (!id) { +// res.status(400) +// return next(new Error("Invalid discussion")); +// } + + +// const comments = await Comment.aggregate([ +// { +// $match: { +// post_id: new ObjectId(id) +// } +// }, +// { +// $lookup: { +// from: 'userprofiles', +// localField: 'user_id', +// foreignField: 'user_id', +// as: 'user_details', +// pipeline: [ +// { +// $lookup: { +// from: 'users', +// localField: 'user_id', +// foreignField: '_id', +// as: "email", +// pipeline: [ +// { +// $project: { +// _id: 0, +// email: 1 +// } +// } +// ] + +// } +// }, +// { +// $unwind: { +// path: "$email" +// } +// }, +// { +// $project: { +// username: 1, +// profile_img: 1, +// email: '$email.email' +// } +// }, + +// ] +// } +// }, { +// $unwind: { +// path: '$user_details' +// } +// }, + +// ]) +// if (comments) { +// res.status(200).json({ +// status: 'ok', +// message: 'comments fetched', +// comment: comments +// }) +// } else { +// next(new Error('Internal server error')) +// } +// } +// ) + +// /** +// * @desc rquest for fetching replyies of comment +// * @route GET /api/community/discussions/comment/reply/:id +// * @access private +// */ +// export const getReplyCommemts: RequestHandler = asyncHandler( +// async (req: Request, res: Response, next: NextFunction): Promise => { +// const { id } = req.params; +// if (!id) { +// res.status(400) +// return next(new Error("Invalid comment")); +// } + + +// const comments = await Comment.aggregate([ +// { +// $match: { +// reply: new ObjectId(id) +// } +// }, +// { +// $lookup: { +// from: 'userprofiles', +// localField: 'user_id', +// foreignField: 'user_id', +// as: 'user_details', +// pipeline: [ +// { +// $lookup: { +// from: 'users', +// localField: 'user_id', +// foreignField: '_id', +// as: "email", +// pipeline: [ +// { +// $project: { +// _id: 0, +// email: 1 +// } +// } +// ] + +// } +// }, +// { +// $unwind: { +// path: "$email" +// } +// }, +// { +// $project: { +// username: 1, +// profile_img: 1, +// email: '$email.email' +// } +// }, + +// ] +// } +// }, { +// $unwind: { +// path: '$user_details' +// } +// }, + +// ]) +// if (comments) { +// res.status(200).json({ +// status: 'ok', +// message: 'reply comment fetched', +// comment: comments +// }) +// } else { +// next(new Error('Internal server error')) +// } +// } +// ) + + +// /** +// * @desc rquest for add commment on a discussions +// * @route DELETE /api/community/discussions/comment +// * @access private +// */ +// export const deleteComment: RequestHandler = asyncHandler( +// async (req: Request, res: Response, next: NextFunction): Promise => { +// const { id } = req.params; +// if (!id) { +// res.status(400) +// return next(new Error("Invalid comment")); +// } +// const deletedComment = await Comment.findOneAndDelete({ _id: id }) +// if (deletedComment) { +// res.status(200).json({ +// status: 'ok', +// message: 'comment deleted', +// deletedComment +// }) +// } else { +// next(new Error('Internal server error')) +// } +// } +// ) + + +// /** +// * @desc rquest for add like on comment +// * @route PUT /api/community/discussions/comment/like/:id +// * @access private +// */ +// export const likeComment: RequestHandler = asyncHandler( +// async (req: Request, res: Response, next: NextFunction): Promise => { +// const { id } = req.params; +// if (!id) { +// res.status(400) +// return next(new Error("Invalid comment")); +// } +// const comment = await Comment.findOneAndUpdate({ _id: id }, { $addToSet: { likes: req.user?._id } }, { new: true }) +// if (comment) { +// res.status(200).json({ +// status: 'ok', +// message: 'comment liked', +// comment +// }) +// } else { +// next(new Error('Internal server error')) +// } +// } +// ) + + +// /** +// * @desc rquest for dislike on comment +// * @route PUT /api/community/discussions/comment/dislike/:id +// * @access private +// */ +// const dislikeComment = async (req, res, next) => { +// const { id } = req.params; +// if (!id) { +// res.status(400) +// return next(new Error("Invalid comment")); +// } +// const comment = await Comment.findOneAndUpdate({ _id: id }, { $pull: { likes: req.user?._id } }, { new: true }) +// if (comment) { +// res.status(200).json({ +// status: 'ok', +// message: 'comment disliked', +// comment +// }) +// } else { +// next(new Error('Internal server error')) +// } +// } + + +module.exports = { + createDiscussion +} \ No newline at end of file diff --git a/server/routes/communityRoute.js b/server/routes/communityRoute.js index 374775a..1ceeb2c 100644 --- a/server/routes/communityRoute.js +++ b/server/routes/communityRoute.js @@ -2,6 +2,8 @@ const express = require('express'); const { isLogedIn } = require('../middlewares/authMiddleware'); const router = express.Router(); const { createCommunity, getSuggestions, joinCommunity, acceptJoin, getmyCommunities } = require('../controller/community') +const { createDiscussion } = require('../controller/discussion') +// const { getDiscussions, createDiscussion, getRecentDiscussion, deleteDiscussion, likeDiscussion, dislikeDiscussion } = require('../controller/discussion') router.get('/get-suggestions', isLogedIn, getSuggestions) router.post('/', isLogedIn, createCommunity) @@ -11,5 +13,10 @@ router.get('/my-communities', isLogedIn, getmyCommunities) //discussion - +// router.get('/discussions/recent', isLogedIn, getRecentDiscussion) +// router.get('/discussions/:id', isLogedIn, getDiscussions) +router.post('/discussions', isLogedIn, createDiscussion) +// router.delete('/discussions/:id', isLogedIn, deleteDiscussion) +// router.put('/discussions/like/:id', isLogedIn, likeDiscussion) +// router.put('/discussions/dislike/:id', isLogedIn, dislikeDiscussion) module.exports = router; \ No newline at end of file From 736cf620d8c0806b9c369b7dd92b1585e5eb2f5c Mon Sep 17 00:00:00 2001 From: Sreesanjay Date: Sun, 10 Mar 2024 00:01:56 +0530 Subject: [PATCH 05/26] feat: comment schema added --- server/controller/discussion.js | 212 ++++++++++++++++---------------- server/models/commentModel.js | 0 2 files changed, 103 insertions(+), 109 deletions(-) create mode 100644 server/models/commentModel.js diff --git a/server/controller/discussion.js b/server/controller/discussion.js index aed4031..a7fc8d0 100644 --- a/server/controller/discussion.js +++ b/server/controller/discussion.js @@ -68,119 +68,113 @@ const createDiscussion = async (req, res, next) => { } -// /** -// * @desc function discussions of a community -// * @route GET /api/community/discussions/:id -// * @access private -// */ -// export const getDiscussions: RequestHandler = asyncHandler( -// async (req: Request, res: Response, next: NextFunction): Promise => { -// const { id } = req.params; -// if (!id) { -// res.status(400); -// return next(new Error('community not found')) -// } +/** + * @desc function discussions of a community + * @route GET /api/community/discussions/:id + * @access private + */ -// const page = (req.query.page && typeof (req.query.page) === "string") ? req.query.page : null -// const pageSize = 3; -// const query = page ? { -// createdAt: { $lt: new Date(page) } -// } : {} +const getDiscussions = async (req, res, next) => { + const { id } = req.params; + if (!id) { + res.status(400); + return next(new Error('community not found')) + } -// const discussions = await Discussion.aggregate([ -// { -// $match: { -// community_id: new ObjectId(id), -// is_delete: false -// } -// }, -// { -// $sort: { -// createdAt: -1 -// } -// }, -// { -// $match: query -// }, -// { -// $limit: pageSize -// }, -// { -// $lookup: { -// from: "comments", -// localField: '_id', -// foreignField: 'post_id', -// as: "comments", -// } -// }, -// { -// $lookup: { -// from: "userprofiles", -// localField: 'user_id', -// foreignField: 'user_id', -// as: 'userProfile', -// pipeline: [ -// { -// $lookup: { -// from: "users", -// localField: 'user_id', -// foreignField: '_id', -// as: 'user', -// } -// }, -// { -// $unwind: { -// path: '$user' -// } -// }, -// { -// $project: { -// username: 1, -// profile_img: 1, -// fullname: 1, -// user_id: 1, -// verified: 1, -// email: '$user.email' -// } -// } -// ] -// } -// }, -// { -// $unwind: { -// path: '$userProfile' -// } -// }, -// { -// $project: { -// _id: 1, -// content: 1, -// user_id: 1, -// likes: 1, -// community_id: 1, -// content_type: 1, -// file_type: 1, -// caption: 1, -// is_delete: 1, -// createdAt: 1, -// userProfile: 1, -// comments: { $size: "$comments" }, -// } -// } -// ]) + const discussions = await Discussion.aggregate([ + { + $match: { + community_id: new ObjectId(id), + is_delete: false + } + }, + { + $sort: { + createdAt: -1 + } + }, + { + skip: (page - 1) * 10 + }, + { + $limit: 10 + }, + { + $lookup: { + from: "comments", + localField: '_id', + foreignField: 'post_id', + as: "comments", + } + }, + { + $lookup: { + from: "userprofiles", + localField: 'user_id', + foreignField: 'user_id', + as: 'userProfile', + pipeline: [ + { + $lookup: { + from: "users", + localField: 'user_id', + foreignField: '_id', + as: 'user', + } + }, + { + $unwind: { + path: '$user' + } + }, + { + $project: { + username: 1, + profile_img: 1, + fullname: 1, + user_id: 1, + verified: 1, + email: '$user.email' + } + } + ] + } + }, + { + $unwind: { + path: '$userProfile' + } + }, + { + $project: { + _id: 1, + content: 1, + user_id: 1, + likes: 1, + community_id: 1, + content_type: 1, + file_type: 1, + caption: 1, + is_delete: 1, + createdAt: 1, + userProfile: 1, + comments: { $size: "$comments" }, + } + } + ]) -// if (discussions) { -// res.status(200).json({ -// status: 'ok', -// message: 'discussion fetched', -// discussions -// }) -// } else { -// next(new Error('Internal server error')) -// } -// } -// ) + if (discussions) { + res.status(200).json({ + status: 'ok', + message: 'discussion fetched', + discussions + }) + } else { + next(new Error('Internal server error')) + } +} +) // /** // * @desc requst for recent discussions of a community diff --git a/server/models/commentModel.js b/server/models/commentModel.js new file mode 100644 index 0000000..e69de29 From ad3c48199a4b98806236ece1eb8bc58d23bbb857 Mon Sep 17 00:00:00 2001 From: Amarnath AS Date: Sun, 10 Mar 2024 00:11:50 +0530 Subject: [PATCH 06/26] fix: admin right management services added --- client/src/Services/rightServices.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/src/Services/rightServices.js b/client/src/Services/rightServices.js index ef248e2..4056d45 100644 --- a/client/src/Services/rightServices.js +++ b/client/src/Services/rightServices.js @@ -10,8 +10,6 @@ export const createRight = async (rightDetails) => { } export const editRight = async (rightDetails, rightId) => { try { - console.log("details", rightDetails) - console.log("right id", rightId) const response = await thaliaAPI.put(`/admin/rights/${rightId}`, rightDetails, { withCredentials: true }); return response.data; } catch (error) { From 5ce3e6b60b5a68e6d95a52b7aa464f4e4a6440b9 Mon Sep 17 00:00:00 2001 From: Amarnath AS Date: Sun, 10 Mar 2024 00:16:01 +0530 Subject: [PATCH 07/26] feat: admin body topic creation component --- client/src/components/AddBody/AddBody.jsx | 32 ++++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/client/src/components/AddBody/AddBody.jsx b/client/src/components/AddBody/AddBody.jsx index 2a382e9..bd9c9f6 100644 --- a/client/src/components/AddBody/AddBody.jsx +++ b/client/src/components/AddBody/AddBody.jsx @@ -1,10 +1,13 @@ import { useState } from "react"; import { Modal } from "flowbite-react"; +import { addTopic } from "../../Services/bodyServices"; +import { toast } from "react-toastify"; +// eslint-disable-next-line react/prop-types function AddBody({ openModal, setOpenModal }) { const [formData, setFormData] = useState({ - body_name: "", - body_desc: "", + name: "", + content: "", }); const handleChange = (e) => { const { name, value } = e.target; @@ -13,6 +16,18 @@ function AddBody({ openModal, setOpenModal }) { [name]: value, }); }; + const handleAdd = () => { + const addNew = async () => { + const response = await addTopic(formData); + if (response.success === true) { + formData.name = ""; + formData.content = ""; + setOpenModal(false); + toast.success(response.message); + } + }; + addNew(); + }; return ( <> setOpenModal(false)}> @@ -26,9 +41,9 @@ function AddBody({ openModal, setOpenModal }) { @@ -36,8 +51,8 @@ function AddBody({ openModal, setOpenModal }) { - From f7dcea18b47fb8dbb0a8beba0388252e23481697 Mon Sep 17 00:00:00 2001 From: Amarnath AS Date: Sun, 10 Mar 2024 00:17:37 +0530 Subject: [PATCH 08/26] feat: admin body topic edit api integration --- client/src/components/EditBody/EditBody.jsx | 45 ++++++++++++++------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/client/src/components/EditBody/EditBody.jsx b/client/src/components/EditBody/EditBody.jsx index 37a2115..f21d876 100644 --- a/client/src/components/EditBody/EditBody.jsx +++ b/client/src/components/EditBody/EditBody.jsx @@ -1,19 +1,22 @@ -import { useState, useEffect } from "react"; import { Modal } from "flowbite-react"; +import { useState, useEffect } from "react"; +import { toast } from "react-toastify"; +import { editBody } from "../../Services/bodyServices"; -function EditBody({ bodyDetails, openModal, setOpenModal }) { +// eslint-disable-next-line react/prop-types +function EditBody({ setOpenModal, openModal, bodyDetails }) { const [formData, setFormData] = useState({ - body_name: "", - body_desc: "", + name: "", + content: "", }); useEffect(() => { if (bodyDetails) { - // eslint-disable-next-line react/prop-types - formData.body_name = bodyDetails?.name; - // eslint-disable-next-line react/prop-types - formData.body_desc = bodyDetails?.description; + setFormData({ + name: bodyDetails?.name || "", + content: bodyDetails?.content || "", + }); } - }, [formData, bodyDetails]); + }, [bodyDetails]); const handleChange = (e) => { const { name, value } = e.target; setFormData({ @@ -21,6 +24,17 @@ function EditBody({ bodyDetails, openModal, setOpenModal }) { [name]: value, }); }; + + const handleEdit = async () => { + const response = await editBody(formData, bodyDetails?._id); + if (response.success === true) { + toast.success(response.message); + formData.name = ""; + formData.content = ""; + setOpenModal(false); + } + }; + return ( <> setOpenModal(false)}> @@ -34,9 +48,9 @@ function EditBody({ bodyDetails, openModal, setOpenModal }) { @@ -44,15 +58,18 @@ function EditBody({ bodyDetails, openModal, setOpenModal }) { - From 5d14df13b710a41c37f37cc472a98f66148811f1 Mon Sep 17 00:00:00 2001 From: Amarnath AS Date: Sun, 10 Mar 2024 00:19:26 +0530 Subject: [PATCH 09/26] feat: admin user managment updation --- .../pages/AdminPages/Managment/Managment.jsx | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/client/src/pages/AdminPages/Managment/Managment.jsx b/client/src/pages/AdminPages/Managment/Managment.jsx index 132c02b..c43ecd8 100644 --- a/client/src/pages/AdminPages/Managment/Managment.jsx +++ b/client/src/pages/AdminPages/Managment/Managment.jsx @@ -5,7 +5,6 @@ function Managment() { const [openModal, setOpenModal] = useState(false); const [reportObject, setReportObject] = useState(); const handleModal = () => { - console.log("Handle Modal Called"); setOpenModal(true); }; return ( @@ -19,7 +18,6 @@ function Managment() {

User Managment

-
@@ -41,28 +39,7 @@ function Managment() { - - - - - - - - - + - - - - - - - - + {bodyDeatails.map((data, index) => { + return ( + <> + + + + + + + + + + ); + })}
- Amarnath as - SilverLaptop - - - -
From 21094c0adfc706c082dc64c908b4548ed6b1eb5d Mon Sep 17 00:00:00 2001 From: Amarnath AS Date: Sun, 10 Mar 2024 00:21:15 +0530 Subject: [PATCH 10/26] feat: admin body topic management --- client/src/pages/AdminPages/MyBody/MyBody.jsx | 106 +++++++++++++----- 1 file changed, 78 insertions(+), 28 deletions(-) diff --git a/client/src/pages/AdminPages/MyBody/MyBody.jsx b/client/src/pages/AdminPages/MyBody/MyBody.jsx index 02a0d85..f870ed8 100644 --- a/client/src/pages/AdminPages/MyBody/MyBody.jsx +++ b/client/src/pages/AdminPages/MyBody/MyBody.jsx @@ -1,20 +1,59 @@ -import { useState } from "react"; -import EditRight from "../../../components/EditRight/EditRight"; +import { useEffect, useState } from "react"; +import EditBody from "../../../components/EditBody/EditBody"; import AddBody from "../../../components/AddBody/AddBody"; +import { getTopics } from "../../../Services/bodyServices"; +import { deleteBody } from "../../../Services/bodyServices"; +import timeFormat from "../../../utils/timeFormat"; +import { toast } from "react-toastify"; function MyBody() { const [openModal, setOpenModal] = useState(false); - // eslint-disable-next-line no-unused-vars - const [rightDetails, setRightDetails] = useState(); + const [bodyDeatails, setBodyDetails] = useState([]); + + const [editBody, setEditBody] = useState(); + const [editModal, setEditModal] = useState(false); + const handleModal = () => { setOpenModal(true); }; + const handleEditModal = (bodyId) => { + setEditModal(true); + const bodyToEdit = bodyDeatails.find((body) => { + return body?._id === bodyId; + }); + setEditBody(bodyToEdit); + }; + useEffect(() => { + const getData = async () => { + const response = await getTopics(); + if (response.success === true) { + setBodyDetails(response.contents); + } + }; + getData(); + }, [ + openModal, + setOpenModal, + setBodyDetails, + setEditModal, + editModal, + setEditBody, + ]); + const handleDelete = async (bodyId) => { + const response = await deleteBody(bodyId); + if (response.success === true) { + setBodyDetails((prevDetails) => + prevDetails.filter((body) => body?._id !== bodyId) + ); + toast.success(response.message); + } + }; return ( <> -
@@ -55,26 +94,37 @@ function MyBody() {
- 1 - Dealing with Period Cramps18-03-2003 - - -
+ {index + 1} + {data?.name} + {timeFormat(data.createdAt)} + + + +
From c29073b699dfeedbc7967344d7fd47c8b442be06 Mon Sep 17 00:00:00 2001 From: Amarnath AS Date: Sun, 10 Mar 2024 00:25:01 +0530 Subject: [PATCH 11/26] feat: admin rights management code updated --- client/src/pages/AdminPages/Rights/Rights.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/pages/AdminPages/Rights/Rights.jsx b/client/src/pages/AdminPages/Rights/Rights.jsx index 64130f4..8519aca 100644 --- a/client/src/pages/AdminPages/Rights/Rights.jsx +++ b/client/src/pages/AdminPages/Rights/Rights.jsx @@ -24,7 +24,6 @@ function Rights() { setEditRight(rightToEdit); }; useEffect(() => { - console.log("Runnning.."); const getRights = async () => { const response = await getRight(); setRightDetails(response.rights); From b5e784fac8d843e116221093d45b807fc3aa6629 Mon Sep 17 00:00:00 2001 From: Amarnath AS Date: Sun, 10 Mar 2024 00:26:24 +0530 Subject: [PATCH 12/26] feat: admin body management service integration --- client/src/Services/bodyServices.js | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 client/src/Services/bodyServices.js diff --git a/client/src/Services/bodyServices.js b/client/src/Services/bodyServices.js new file mode 100644 index 0000000..950d103 --- /dev/null +++ b/client/src/Services/bodyServices.js @@ -0,0 +1,38 @@ +import thaliaAPI from "../API/thaliaAPI"; + +export const getTopics = async () => { + try { + const response = await thaliaAPI.get("/admin/my-body", { withCredentials: true }); + return response.data; + } catch (error) { + return error; + } +} + +export const addTopic = async (formData) => { + try { + const response = await thaliaAPI.post("/admin/my-body", formData, { withCredentials: true }); + return response.data; + } catch (error) { + return error; + } +} + +export const deleteBody = async (bodyId) => { + try { + const response = await thaliaAPI.delete(`/admin/my-body/${bodyId}`, { withCredentials: true }); + return response.data; + } catch (error) { + return error; + } +} + +export const editBody = async (formData, bodyId) => { + try { + const response = await thaliaAPI.put(`/admin/my-body/${bodyId}`, formData); + return response.data; + } catch (error) { + console.log("error=>", error) + return error; + } +} \ No newline at end of file From 1b591dbc7dd88d5a9ee48c688f48d4bfbb8aa421 Mon Sep 17 00:00:00 2001 From: Amarnath AS Date: Sun, 10 Mar 2024 00:27:17 +0530 Subject: [PATCH 13/26] admin: admin user managment services integration --- client/src/Services/userService.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 client/src/Services/userService.js diff --git a/client/src/Services/userService.js b/client/src/Services/userService.js new file mode 100644 index 0000000..e69de29 From 5006fdda4593fe11d01b0094c324d7cefc7d10ae Mon Sep 17 00:00:00 2001 From: Sreesanjay Date: Sun, 10 Mar 2024 01:25:50 +0530 Subject: [PATCH 14/26] feat: added like discussion --- server/controller/discussion.js | 614 +++++++++++++++++--------------- server/routes/communityRoute.js | 10 +- 2 files changed, 325 insertions(+), 299 deletions(-) diff --git a/server/controller/discussion.js b/server/controller/discussion.js index a7fc8d0..d315201 100644 --- a/server/controller/discussion.js +++ b/server/controller/discussion.js @@ -1,4 +1,6 @@ -const Discussion = require("../models/discussionModel") +const Discussion = require("../models/discussionModel"); +const Members = require("../models/membersModel"); +const mongoose = require('mongoose') /** * @desc function creating discussion @@ -6,17 +8,116 @@ const Discussion = require("../models/discussionModel") * @access private */ const createDiscussion = async (req, res, next) => { - const { content, community_id, user_id } = req.body; - if (!content || !community_id || !user_id) { - res.status(400); - return next(new Error('Invalid details')); + try { + const { content, community_id, user_id } = req.body; + if (!content || !community_id || !user_id) { + res.status(400); + throw new Error('details missing') + } + const newDiscussion = await new Discussion(req.body).save() + if (newDiscussion) { + const discussion = await Discussion.aggregate([ + { + $match: { + _id: newDiscussion._id + } + }, + { + $lookup: { + from: "profiles", + localField: 'user_id', + foreignField: 'user_id', + as: 'userProfile', + pipeline: [ + { + $lookup: { + from: "users", + localField: 'user_id', + foreignField: '_id', + as: 'user', + } + }, + { + $unwind: { + path: '$user' + } + }, + { + $project: { + username: 1, + profile_img: 1, + fullname: 1, + user_id: 1, + email: '$user.email' + } + } + ] + } + }, + { + $unwind: { + path: '$userProfile' + } + } + ]) + if (discussion) { + res.status(200).json({ + success: true, + message: 'new discussion added', + discussion: discussion[0] + }) + } + } + } catch (error) { + next(error.message) } - const newDiscussion = await new Discussion(req.body).save() - if (newDiscussion) { - const discussion = await Discussion.aggregate([ + +} + +/** + * @desc function discussions of a community + * @route GET /api/community/discussions/:id + * @access private + */ + +const getDiscussions = async (req, res, next) => { + try { + const { id } = req.params; + const page = req.query.page; + if (!id) { + res.status(400); + throw new Error("community not found") + } + if (!page) { + res.status(400); + throw new Error("page not found") + } + + + const discussions = await Discussion.aggregate([ { $match: { - _id: newDiscussion._id + community_id: new mongoose.Types.ObjectId(id), + is_delete: false + } + }, + { + $sort: { + createdAt: -1 + } + }, + { + $skip: (page - 1) * 10 + }, + { + $limit: 10 + }, + { + $lookup: { + from: "comments", + localField: '_id', + foreignField: 'discussion_id', + as: "comments", } }, { @@ -55,312 +156,233 @@ const createDiscussion = async (req, res, next) => { $unwind: { path: '$userProfile' } + }, + { + $project: { + _id: 1, + content: 1, + user_id: 1, + likes: 1, + community_id: 1, + content_type: 1, + file_type: 1, + caption: 1, + is_delete: 1, + createdAt: 1, + userProfile: 1, + comments: { $size: "$comments" }, + } } ]) - if (discussion) { + + + if (discussions) { res.status(200).json({ - status: 'created', - message: 'new discussion added', - discussion: discussion[0] + success: true, + message: 'discussion fetched', + discussions }) + } else { + throw new Error('Internal server error') } - } + } catch (error) { + next(error.message) + } } /** - * @desc function discussions of a community - * @route GET /api/community/discussions/:id + * @desc requst for recent discussions of a community + * @route GET /api/community/discussions/recent * @access private */ +const getRecentDiscussion = async (req, res, next) => { + try { + const page = req.query.page + if (!page) { + throw new Error('pagination not found') + } -const getDiscussions = async (req, res, next) => { - const { id } = req.params; - if (!id) { - res.status(400); - return next(new Error('community not found')) - } + const community = await Members.find({ user_id: req.user?._id, status: 'active' }) + const communityId = community.map((item) => item.community_id); - const discussions = await Discussion.aggregate([ - { - $match: { - community_id: new ObjectId(id), - is_delete: false - } - }, - { - $sort: { - createdAt: -1 - } - }, - { - skip: (page - 1) * 10 - }, - { - $limit: 10 - }, - { - $lookup: { - from: "comments", - localField: '_id', - foreignField: 'post_id', - as: "comments", - } - }, - { - $lookup: { - from: "userprofiles", - localField: 'user_id', - foreignField: 'user_id', - as: 'userProfile', - pipeline: [ - { - $lookup: { - from: "users", - localField: 'user_id', - foreignField: '_id', - as: 'user', - } - }, - { - $unwind: { - path: '$user' - } - }, - { - $project: { - username: 1, - profile_img: 1, - fullname: 1, - user_id: 1, - verified: 1, - email: '$user.email' + const discussions = await Discussion.aggregate([ + { + $match: { + community_id: { $in: communityId }, + is_delete: false + } + }, + { + $sort: { + createdAt: -1 + } + }, + { + $skip: (page - 1) * 10 + }, + { + $limit: 10 + }, + { + $lookup: { + from: "comments", + localField: '_id', + foreignField: 'discussion_id', + as: "comments", + } + }, + { + $lookup: { + from: "profiles", + localField: 'user_id', + foreignField: 'user_id', + as: 'userProfile', + pipeline: [ + { + $lookup: { + from: "users", + localField: 'user_id', + foreignField: '_id', + as: 'user', + } + }, + { + $unwind: { + path: '$user' + } + }, + { + $project: { + username: 1, + profile_img: 1, + fullname: 1, + user_id: 1, + verified: 1, + email: '$user.email' + } } - } - ] - } - }, - { - $unwind: { - path: '$userProfile' - } - }, - { - $project: { - _id: 1, - content: 1, - user_id: 1, - likes: 1, - community_id: 1, - content_type: 1, - file_type: 1, - caption: 1, - is_delete: 1, - createdAt: 1, - userProfile: 1, - comments: { $size: "$comments" }, + ] + } + }, + { + $unwind: { + path: '$userProfile' + } + }, + { + $project: { + _id: 1, + content: 1, + user_id: 1, + likes: 1, + community_id: 1, + content_type: 1, + file_type: 1, + caption: 1, + is_delete: 1, + createdAt: 1, + userProfile: 1, + comments: { $size: "$comments" }, + } } - } - ]) + ]) - if (discussions) { - res.status(200).json({ - status: 'ok', - message: 'discussion fetched', - discussions - }) - } else { - next(new Error('Internal server error')) + if (discussions) { + res.status(200).json({ + success: true, + message: 'recent discussion fetched', + discussions + }) + } else { + throw new Error('Internal server error') + } + } catch (error) { + next(error.message) } } -) - -// /** -// * @desc requst for recent discussions of a community -// * @route GET /api/community/discussions/recent -// * @access private -// */ -// export const getRecentDiscussion: RequestHandler = asyncHandler( -// async (req: Request, res: Response, next: NextFunction): Promise => { -// const page = (req.query.page && typeof (req.query.page) === "string") ? req.query.page : null -// const pageSize = 3; -// const query = page ? { -// createdAt: { $lt: new Date(page) } -// } : {} -// const community = await Members.find({ user_id: req.user?._id, status: 'active' }) -// const communityId = community.map((item) => item.community_id); - -// const discussions = await Discussion.aggregate([ -// { -// $match: { -// community_id: { $in: communityId }, -// is_delete: false -// } -// }, -// { -// $sort: { -// createdAt: -1 -// } -// }, -// { -// $match: query -// }, -// { -// $limit: pageSize -// }, -// { -// $lookup: { -// from: "comments", -// localField: '_id', -// foreignField: 'post_id', -// as: "comments", -// } -// }, -// { -// $lookup: { -// from: "userprofiles", -// localField: 'user_id', -// foreignField: 'user_id', -// as: 'userProfile', -// pipeline: [ -// { -// $lookup: { -// from: "users", -// localField: 'user_id', -// foreignField: '_id', -// as: 'user', -// } -// }, -// { -// $unwind: { -// path: '$user' -// } -// }, -// { -// $project: { -// username: 1, -// profile_img: 1, -// fullname: 1, -// user_id: 1, -// verified: 1, -// email: '$user.email' -// } -// } -// ] -// } -// }, -// { -// $unwind: { -// path: '$userProfile' -// } -// }, -// { -// $project: { -// _id: 1, -// content: 1, -// user_id: 1, -// likes: 1, -// community_id: 1, -// content_type: 1, -// file_type: 1, -// caption: 1, -// is_delete: 1, -// createdAt: 1, -// userProfile: 1, -// comments: { $size: "$comments" }, -// } -// } -// ]) - - -// if (discussions) { -// res.status(200).json({ -// status: 'ok', -// message: 'discussion fetched', -// discussions -// }) -// } else { -// next(new Error('Internal server error')) -// } -// } -// ) - -// /** -// * @desc function for deleting a discussions -// * @route DELETE /api/community/discussions/:id -// * @access private -// */ -// export const deleteDiscussion: RequestHandler = asyncHandler( -// async (req: Request, res: Response, next: NextFunction): Promise => { -// const { id } = req.params; -// if (!id) { -// res.status(400); -// return next(new Error('discussion not found')) -// } -// const deletedDiscussion = await Discussion.findOneAndUpdate({ _id: id }, { $set: { is_delete: true } }, { new: true }) -// if (deletedDiscussion) { -// res.status(200).json({ -// status: 'ok', -// message: 'discussion deleted', -// deletedDiscussion -// }) -// } else { -// next(new Error('Internal server error')) -// } -// } -// ) +/** + * @desc function for deleting a discussions + * @route DELETE /api/community/discussions/:id + * @access private + */ +const deleteDiscussion = async (req, res, next) => { + try { + const { id } = req.params; + if (!id) { + res.status(400); + throw new Error('discussion not found') + } + const deletedDiscussion = await Discussion.findOneAndUpdate({ _id: id }, { $set: { is_delete: true } }, { new: true }) + if (deletedDiscussion) { + res.status(200).json({ + success: true, + message: 'discussion deleted', + deletedDiscussion + }) + } else { + throw new Error('internal server error') + } + } catch (error) { + next(error.message) + } +} -// /** -// * @desc function for like a discussions -// * @route DELETE /api/community/discussions/like/:id -// * @access private -// */ -// export const likeDiscussion: RequestHandler = asyncHandler( -// async (req: Request, res: Response, next: NextFunction): Promise => { -// const { id } = req.params; -// if (!id) { -// res.status(400); -// return next(new Error('discussion not found')) -// } -// const likedDiscussion = await Discussion.findOneAndUpdate({ _id: id }, { $addToSet: { likes: req.user?._id } }, { new: true }) -// if (likedDiscussion) { -// res.status(200).json({ -// status: 'ok', -// message: 'discussion liked', -// likedDiscussion -// }) -// } else { -// next(new Error('Internal server error')) -// } -// } -// ) +/** + * @desc function for like a discussions + * @route PUT /api/community/discussions/like/:id + * @access private + */ +const likeDiscussion = async (req, res, next) => { + try { + const { id } = req.params; + if (!id) { + res.status(400); + throw new Error('discussion not found') + } + const likedDiscussion = await Discussion.findOneAndUpdate({ _id: id }, { $addToSet: { likes: req.user?._id } }, { new: true }) + if (likedDiscussion) { + res.status(200).json({ + success: true, + message: 'discussion liked', + likedDiscussion + }) + } else { + throw new Error('internal server error') + } + } catch (error) { + next(error.message) + } +} -// /** -// * @desc function for dislike a discussions -// * @route DELETE /api/community/discussions/dislike/:id -// * @access private -// */ -// export const dislikeDiscussion: RequestHandler = asyncHandler( -// async (req: Request, res: Response, next: NextFunction): Promise => { -// const { id } = req.params; -// if (!id) { -// res.status(400); -// return next(new Error('discussion not found')) -// } -// const likedDiscussion = await Discussion.findOneAndUpdate({ _id: id }, { $pull: { likes: req.user?._id } }, { new: true }) -// if (likedDiscussion) { -// res.status(200).json({ -// status: 'ok', -// message: 'discussion disliked', -// likedDiscussion -// }) -// } else { -// next(new Error('Internal server error')) -// } -// } -// ) +/** + * @desc function for dislike a discussions + * @route PUT /api/community/discussions/dislike/:id + * @access private + */ +const dislikeDiscussion = async (req, res, next) => { + try { + const { id } = req.params; + if (!id) { + res.status(400); + throw new Error('discussion not found') + } + const likedDiscussion = await Discussion.findOneAndUpdate({ _id: id }, { $pull: { likes: req.user?._id } }, { new: true }) + if (likedDiscussion) { + res.status(200).json({ + success: true, + message: 'discussion disliked', + likedDiscussion + }) + } else { + throw new Error('internal server error') + } + } catch (error) { + next(error.message) + } +} // /** // * @desc rquest for add commment on a discussions @@ -682,5 +704,9 @@ const getDiscussions = async (req, res, next) => { module.exports = { - createDiscussion + createDiscussion, + getDiscussions, + getRecentDiscussion, + deleteDiscussion, + likeDiscussion } \ No newline at end of file diff --git a/server/routes/communityRoute.js b/server/routes/communityRoute.js index 1ceeb2c..e0a5058 100644 --- a/server/routes/communityRoute.js +++ b/server/routes/communityRoute.js @@ -2,7 +2,7 @@ const express = require('express'); const { isLogedIn } = require('../middlewares/authMiddleware'); const router = express.Router(); const { createCommunity, getSuggestions, joinCommunity, acceptJoin, getmyCommunities } = require('../controller/community') -const { createDiscussion } = require('../controller/discussion') +const { createDiscussion, getDiscussions, getRecentDiscussion, deleteDiscussion, likeDiscussion } = require('../controller/discussion') // const { getDiscussions, createDiscussion, getRecentDiscussion, deleteDiscussion, likeDiscussion, dislikeDiscussion } = require('../controller/discussion') router.get('/get-suggestions', isLogedIn, getSuggestions) @@ -13,10 +13,10 @@ router.get('/my-communities', isLogedIn, getmyCommunities) //discussion -// router.get('/discussions/recent', isLogedIn, getRecentDiscussion) -// router.get('/discussions/:id', isLogedIn, getDiscussions) +router.get('/discussions/recent', isLogedIn, getRecentDiscussion) +router.get('/discussions/:id', isLogedIn, getDiscussions) router.post('/discussions', isLogedIn, createDiscussion) -// router.delete('/discussions/:id', isLogedIn, deleteDiscussion) -// router.put('/discussions/like/:id', isLogedIn, likeDiscussion) +router.delete('/discussions/:id', isLogedIn, deleteDiscussion) +router.put('/discussions/like/:id', isLogedIn, likeDiscussion) // router.put('/discussions/dislike/:id', isLogedIn, dislikeDiscussion) module.exports = router; \ No newline at end of file From 5607de8a078e47fede8c16428785b7600de7f5b8 Mon Sep 17 00:00:00 2001 From: Izam Mohammed Date: Sun, 10 Mar 2024 02:10:21 +0530 Subject: [PATCH 15/26] fix: updated the cors in AI server --- ai_server/ai_server/settings.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ai_server/ai_server/settings.py b/ai_server/ai_server/settings.py index 8b04ffe..33fba6e 100644 --- a/ai_server/ai_server/settings.py +++ b/ai_server/ai_server/settings.py @@ -127,4 +127,7 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" -CORS_ORIGIN_ALLOW_ALL = True \ No newline at end of file +CORS_ALLOWED_ORIGINS = [ + "http://localhost:4000", + "https://thalia.vercel.app", +] \ No newline at end of file From eb4d2f2ec6fe5a3ff213fe96c6b43b51061b7835 Mon Sep 17 00:00:00 2001 From: Sreesanjay Date: Sun, 10 Mar 2024 02:17:46 +0530 Subject: [PATCH 16/26] feat: added create comment and get comment api --- server/controller/discussion.js | 491 ++++++++++++++++---------------- server/models/commentModel.js | 27 ++ server/routes/communityRoute.js | 10 +- 3 files changed, 287 insertions(+), 241 deletions(-) diff --git a/server/controller/discussion.js b/server/controller/discussion.js index d315201..25ec014 100644 --- a/server/controller/discussion.js +++ b/server/controller/discussion.js @@ -1,5 +1,6 @@ const Discussion = require("../models/discussionModel"); const Members = require("../models/membersModel"); +const Comment = require("../models/commentModel"); const mongoose = require('mongoose') /** @@ -369,12 +370,12 @@ const dislikeDiscussion = async (req, res, next) => { res.status(400); throw new Error('discussion not found') } - const likedDiscussion = await Discussion.findOneAndUpdate({ _id: id }, { $pull: { likes: req.user?._id } }, { new: true }) - if (likedDiscussion) { + const dislikedDiscussion = await Discussion.findOneAndUpdate({ _id: id }, { $pull: { likes: req.user?._id } }, { new: true }) + if (dislikedDiscussion) { res.status(200).json({ success: true, message: 'discussion disliked', - likedDiscussion + dislikedDiscussion }) } else { throw new Error('internal server error') @@ -384,247 +385,257 @@ const dislikeDiscussion = async (req, res, next) => { } } -// /** -// * @desc rquest for add commment on a discussions -// * @route POST /api/community/discussions/comment -// * @access private -// */ -// export const addComment: RequestHandler = asyncHandler( -// async (req: Request, res: Response, next: NextFunction): Promise => { -// const { discussion_id } = req.body; -// if (!discussion_id) { -// res.status(400) -// return next(new Error("Invalid discussion")); -// } -// const newComment = await new Comment({ -// user_id: req.user?._id, -// post_id: req.body.discussion_id, -// content: req.body.content -// }) -// if (req.body.reply) { -// newComment.reply = req.body.reply -// } -// const comment = await newComment.save() +/** + * @desc rquest for add commment on a discussions + * @route POST /api/community/discussions/comment + * @access private + */ +const addComment = async (req, res, next) => { + try { + const { discussion_id } = req.body; + if (!discussion_id) { + res.status(400) + throw new Error('discussion not found') + } + const newComment = new Comment({ + user_id: req.user?._id, + discussion_id: req.body.discussion_id, + content: req.body.content + }) + if (req.body.reply) { + newComment.reply = req.body.reply + } + const comment = await newComment.save() -// if (comment) { -// const resComment = await Comment.aggregate([ -// { -// $match: { -// _id: comment._id -// } -// }, -// { -// $lookup: { -// from: 'userprofiles', -// localField: 'user_id', -// foreignField: 'user_id', -// as: 'user_details', -// pipeline: [ -// { -// $lookup: { -// from: 'users', -// localField: 'user_id', -// foreignField: '_id', -// as: "email", -// pipeline: [ -// { -// $project: { -// _id: 0, -// email: 1 -// } -// } -// ] - -// } -// }, -// { -// $unwind: { -// path: "$email" -// } -// }, -// { -// $project: { -// username: 1, -// profile_img: 1, -// email: '$email.email' -// } -// }, - -// ] -// } -// }, { -// $unwind: { -// path: '$user_details' -// } -// }, - -// ]) -// res.status(200).json({ -// status: 'ok', -// message: 'new Comment added', -// comment: resComment[0] -// }) -// } else { -// next(new Error('Internal server error')) -// } -// } -// ) + if (comment) { + const resComment = await Comment.aggregate([ + { + $match: { + _id: comment._id + } + }, + { + $lookup: { + from: 'profiles', + localField: 'user_id', + foreignField: 'user_id', + as: 'user_details', + pipeline: [ + { + $lookup: { + from: 'users', + localField: 'user_id', + foreignField: '_id', + as: "email", + pipeline: [ + { + $project: { + _id: 0, + email: 1 + } + } + ] -// /** -// * @desc rquest for fetching comments of a discussion -// * @route GET /api/community/discussions/comment/:id -// * @access private -// */ -// export const getComments: RequestHandler = asyncHandler( -// async (req: Request, res: Response, next: NextFunction): Promise => { -// const { id } = req.params; -// if (!id) { -// res.status(400) -// return next(new Error("Invalid discussion")); -// } + } + }, + { + $unwind: { + path: "$email" + } + }, + { + $project: { + username: 1, + profile_img: 1, + fullname: 1, + email: '$email.email' + } + }, + ] + } + }, { + $unwind: { + path: '$user_details' + } + }, -// const comments = await Comment.aggregate([ -// { -// $match: { -// post_id: new ObjectId(id) -// } -// }, -// { -// $lookup: { -// from: 'userprofiles', -// localField: 'user_id', -// foreignField: 'user_id', -// as: 'user_details', -// pipeline: [ -// { -// $lookup: { -// from: 'users', -// localField: 'user_id', -// foreignField: '_id', -// as: "email", -// pipeline: [ -// { -// $project: { -// _id: 0, -// email: 1 -// } -// } -// ] - -// } -// }, -// { -// $unwind: { -// path: "$email" -// } -// }, -// { -// $project: { -// username: 1, -// profile_img: 1, -// email: '$email.email' -// } -// }, - -// ] -// } -// }, { -// $unwind: { -// path: '$user_details' -// } -// }, - -// ]) -// if (comments) { -// res.status(200).json({ -// status: 'ok', -// message: 'comments fetched', -// comment: comments -// }) -// } else { -// next(new Error('Internal server error')) -// } -// } -// ) + ]) + res.status(200).json({ + success: true, + message: 'new Comment added', + comment: resComment[0] + }) + } else { + throw new Error('internal server error') + } + } catch (error) { + next(error.message) + } +} -// /** -// * @desc rquest for fetching replyies of comment -// * @route GET /api/community/discussions/comment/reply/:id -// * @access private -// */ -// export const getReplyCommemts: RequestHandler = asyncHandler( -// async (req: Request, res: Response, next: NextFunction): Promise => { -// const { id } = req.params; -// if (!id) { -// res.status(400) -// return next(new Error("Invalid comment")); -// } +/** + * @desc rquest for fetching comments of a discussion + * @route GET /api/community/discussions/comment/:id + * @access private + */ +const getComments = async (req, res, next) => { + try { + const { id } = req.params; + if (!id) { + res.status(400) + throw new Error('discussion not found') + } -// const comments = await Comment.aggregate([ -// { -// $match: { -// reply: new ObjectId(id) -// } -// }, -// { -// $lookup: { -// from: 'userprofiles', -// localField: 'user_id', -// foreignField: 'user_id', -// as: 'user_details', -// pipeline: [ -// { -// $lookup: { -// from: 'users', -// localField: 'user_id', -// foreignField: '_id', -// as: "email", -// pipeline: [ -// { -// $project: { -// _id: 0, -// email: 1 -// } -// } -// ] - -// } -// }, -// { -// $unwind: { -// path: "$email" -// } -// }, -// { -// $project: { -// username: 1, -// profile_img: 1, -// email: '$email.email' -// } -// }, - -// ] -// } -// }, { -// $unwind: { -// path: '$user_details' -// } -// }, - -// ]) -// if (comments) { -// res.status(200).json({ -// status: 'ok', -// message: 'reply comment fetched', -// comment: comments -// }) -// } else { -// next(new Error('Internal server error')) -// } -// } -// ) + const comments = await Comment.aggregate([ + { + $match: { + discussion_id: new mongoose.Types.ObjectId(id) + } + }, + { + $lookup: { + from: 'profiles', + localField: 'user_id', + foreignField: 'user_id', + as: 'user_details', + pipeline: [ + { + $lookup: { + from: 'users', + localField: 'user_id', + foreignField: '_id', + as: "email", + pipeline: [ + { + $project: { + _id: 0, + email: 1 + } + } + ] + + } + }, + { + $unwind: { + path: "$email" + } + }, + { + $project: { + username: 1, + profile_img: 1, + fullname: 1, + email: '$email.email' + } + }, + + ] + } + }, { + $unwind: { + path: '$user_details' + } + }, + + ]) + if (comments) { + res.status(200).json({ + success: true, + message: 'comments fetched', + comment: comments + }) + } else { + throw new Error('Internal server error') + } + } catch (error) { + next(error.message) + } +} + + +/** + * @desc rquest for fetching replyies of comment + * @route GET /api/community/discussions/comment/reply/:id + * @access private + */ +const getReplyCommemts = async (req, res, next) => { + try { + const { id } = req.params; + if (!id) { + res.status(400) + throw new Error('comment not found') + } + + + const comments = await Comment.aggregate([ + { + $match: { + reply: new mongoose.Types.ObjectId(id) + } + }, + { + $lookup: { + from: 'profiles', + localField: 'user_id', + foreignField: 'user_id', + as: 'user_details', + pipeline: [ + { + $lookup: { + from: 'users', + localField: 'user_id', + foreignField: '_id', + as: "email", + pipeline: [ + { + $project: { + _id: 0, + email: 1 + } + } + ] + + } + }, + { + $unwind: { + path: "$email" + } + }, + { + $project: { + username: 1, + fullname: 1, + profile_img: 1, + email: '$email.email' + } + }, + + ] + } + }, { + $unwind: { + path: '$user_details' + } + }, + + ]) + if (comments) { + res.status(200).json({ + success: true, + message: 'reply comment fetched', + comment: comments + }) + } else { + throw new Error('Internal server error') + } + } catch (error) { + next(error.message) + } +} // /** @@ -708,5 +719,9 @@ module.exports = { getDiscussions, getRecentDiscussion, deleteDiscussion, - likeDiscussion + likeDiscussion, + dislikeDiscussion, + addComment, + getComments, + getReplyCommemts } \ No newline at end of file diff --git a/server/models/commentModel.js b/server/models/commentModel.js index e69de29..aa17d76 100644 --- a/server/models/commentModel.js +++ b/server/models/commentModel.js @@ -0,0 +1,27 @@ +const mongoose = require("mongoose"); + +const commentSchema = new mongoose.Schema({ + discussion_id: { + type: mongoose.Types.ObjectId, + ref: 'Discussion' + }, + user_id: { + type: mongoose.Types.ObjectId, + ref: 'User' + }, + content: { + type: String, + required: true + }, + reply: { + type: mongoose.Types.ObjectId + }, + likes: [ + { + type: mongoose.Types.ObjectId, + ref: 'User' + } + ] +}, { timestamps: true }); + +module.exports = mongoose.model("Comment", commentSchema); \ No newline at end of file diff --git a/server/routes/communityRoute.js b/server/routes/communityRoute.js index e0a5058..790e64a 100644 --- a/server/routes/communityRoute.js +++ b/server/routes/communityRoute.js @@ -2,8 +2,7 @@ const express = require('express'); const { isLogedIn } = require('../middlewares/authMiddleware'); const router = express.Router(); const { createCommunity, getSuggestions, joinCommunity, acceptJoin, getmyCommunities } = require('../controller/community') -const { createDiscussion, getDiscussions, getRecentDiscussion, deleteDiscussion, likeDiscussion } = require('../controller/discussion') -// const { getDiscussions, createDiscussion, getRecentDiscussion, deleteDiscussion, likeDiscussion, dislikeDiscussion } = require('../controller/discussion') +const { createDiscussion, getDiscussions, getRecentDiscussion, deleteDiscussion, likeDiscussion, dislikeDiscussion, addComment, getComments, getReplyCommemts } = require('../controller/discussion') router.get('/get-suggestions', isLogedIn, getSuggestions) router.post('/', isLogedIn, createCommunity) @@ -18,5 +17,10 @@ router.get('/discussions/:id', isLogedIn, getDiscussions) router.post('/discussions', isLogedIn, createDiscussion) router.delete('/discussions/:id', isLogedIn, deleteDiscussion) router.put('/discussions/like/:id', isLogedIn, likeDiscussion) -// router.put('/discussions/dislike/:id', isLogedIn, dislikeDiscussion) +router.put('/discussions/dislike/:id', isLogedIn, dislikeDiscussion) + +router.post('/discussions/comment', isLogedIn, addComment) +router.get('/discussions/comment/:id', isLogedIn, getComments) +router.get('/discussions/comment/reply/:id', isLogedIn, getReplyCommemts) + module.exports = router; \ No newline at end of file From c249cd62cf6d11fabbc2b6126f45a7bac45bd093 Mon Sep 17 00:00:00 2001 From: Amarnath AS Date: Sun, 10 Mar 2024 02:46:37 +0530 Subject: [PATCH 17/26] feat: admin user mangement service --- client/src/Services/userService.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/client/src/Services/userService.js b/client/src/Services/userService.js index e69de29..a68d726 100644 --- a/client/src/Services/userService.js +++ b/client/src/Services/userService.js @@ -0,0 +1,29 @@ +import thaliaAPI from "../API/thaliaAPI"; + +export const getUsers = async () => { + try { + const response = await thaliaAPI.get("/admin/users", { withCredentials: true }); + return response.data; + } catch (error) { + return error; + } +} + +export const blockUser = async (userId) => { + try { + const response = await thaliaAPI.put(`/admin/users/block/${userId}`, { withCredentials: true }); + return response.data; + } catch (error) { + return error; + } +} + +export const unBlockUser = async (userId) => { + try { + const response = await thaliaAPI.put(`/admin/users/unblock/${userId}`, { withCredentials: true }); + return response.data; + } catch (error) { + return error; + } +} + From bc80cfbd1692e0cfa80b5da0b3500d5015486d8f Mon Sep 17 00:00:00 2001 From: Amarnath AS Date: Sun, 10 Mar 2024 02:48:22 +0530 Subject: [PATCH 18/26] feat: admin Add body management --- client/src/components/AddBody/AddBody.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/components/AddBody/AddBody.jsx b/client/src/components/AddBody/AddBody.jsx index bd9c9f6..760184f 100644 --- a/client/src/components/AddBody/AddBody.jsx +++ b/client/src/components/AddBody/AddBody.jsx @@ -40,7 +40,7 @@ function AddBody({ openModal, setOpenModal }) {

Name of the Topic

- - - From ab589e9cc0fb3865495b79632eaa2fad141ea19f Mon Sep 17 00:00:00 2001 From: Amarnath AS Date: Sun, 10 Mar 2024 02:58:53 +0530 Subject: [PATCH 26/26] fix: admin my body page update --- client/src/pages/AdminPages/MyBody/MyBody.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/pages/AdminPages/MyBody/MyBody.jsx b/client/src/pages/AdminPages/MyBody/MyBody.jsx index f870ed8..afdd993 100644 --- a/client/src/pages/AdminPages/MyBody/MyBody.jsx +++ b/client/src/pages/AdminPages/MyBody/MyBody.jsx @@ -56,7 +56,7 @@ function MyBody() { bodyDetails={editBody ? editBody : null} /> -
+
{/* Text Components */}