diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..509fe35
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,26 @@
+## Related Issue
+[Cite any related issue(s) this pull request addresses. If none, simply state βNoneβ]
+
+## Description
+[Please include a brief description of the changes or features added]
+
+## Type of PR
+
+- [ ] Bug fix
+- [ ] Feature enhancement
+- [ ] Documentation update
+- [ ] Other (specify): _______________
+
+## Screenshots / videos (if applicable)
+[Attach any relevant screenshots or videos demonstrating the changes]
+
+## Checklist:
+- [ ] I have performed a self-review of my code
+- [ ] I have read and followed the Contribution Guidelines.
+- [ ] I have tested the changes thoroughly before submitting this pull request.
+- [ ] I have provided relevant issue numbers, screenshots, and videos after making the changes.
+- [ ] I have commented my code, particularly in hard-to-understand areas.
+
+
+## Additional context:
+[Include any additional information or context that might be helpful for reviewers.]
diff --git a/.github/workflows/auto-comment-pr-merge.yml b/.github/workflows/auto-comment-pr-merge.yml
new file mode 100644
index 0000000..f07afe1
--- /dev/null
+++ b/.github/workflows/auto-comment-pr-merge.yml
@@ -0,0 +1,21 @@
+name: Auto Comment on PR Merge
+
+on:
+ pull_request:
+ types: [closed]
+
+jobs:
+ comment:
+ if: github.event.pull_request.merged == true
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Add Comment to Merged PR
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ curl -X POST \
+ -H "Authorization: token $GITHUB_TOKEN" \
+ -H "Accept: application/vnd.github.v3+json" \
+ -d '{"body":"π Your pull request has been successfully merged! π Thank you for your contribution to our project. Your efforts are greatly appreciated. Keep up the fantastic work! π"}' \
+ "https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index cee5c73..6041c6f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -24,6 +24,40 @@ in case you are stuck:
Petari - The Food Donation Management System
+### Alternatively, contribute using GitHub Desktop
+
+1. **Open GitHub Desktop:**
+ Launch GitHub Desktop and log in to your GitHub account if you haven't already.
+
+2. **Clone the Repository:**
+ - If you haven't cloned the Petari repository yet, you can do so by clicking on the "File" menu and selecting "Clone Repository."
+ - Choose the Petari repository from the list of repositories on GitHub and clone it to your local machine.
+
+3. **Switch to the Correct Branch:**
+ - Ensure you are on the branch that you want to submit a pull request for.
+ - If you need to switch branches, you can do so by clicking on the "Current Branch" dropdown menu and selecting the desired branch.
+
+4. **Make Changes:**
+ Make your changes to the code or files in the repository using your preferred code editor.
+
+5. **Commit Changes:**
+ - In GitHub Desktop, you'll see a list of the files you've changed. Check the box next to each file you want to include in the commit.
+ - Enter a summary and description for your changes in the "Summary" and "Description" fields, respectively. Click the "Commit to Table of Contents
+
+- [Introduction](#introduction)
+- [Tech Stack](#tech-stack)
+
+ - [Frontend](#frontend)
+ - [Backend](#backend)
+- [Features](#features)
+- [Contribution Guidelines](#contribution-guidelines)
+ - [How Can You Contribute?](#how-can-you-contribute)
+- [Getting Started](#getting-started)
+- [Code Style Guidelines](#code-style-guidelines)
+- [Code Review Process](#code-review-process)
+- [Community Guidelines](#community-guidelines)
+- [Output Screenshot](#output-screenshot)
+
## Introduction
-
+
PETARI, The Food Donate WebApp, is an initiative by an organization aiming to redistribute excess food from various events to those in need. The project aligns with India's Sustainable Development Goals to achieve a hunger-free world and zero food waste. By leveraging technology, PETARI seeks to bridge the gap between surplus food and hunger, thereby benefiting society and the environment.
## Tech Stack
-
+
### Frontend
-- HTML
-- CSS
-- Bootstrap
-- JavaScript
+
+
+
### Backend
-- Node.js
-- EJS
-- Express.js
-- MongoDB
-- Authentication (Auth 2.0)
+
+
+
+
+
+
-# Contribution Guidelines
+
+# Features
+
+- Redistribution of Excess Food:
+ Petari focuses on collecting excess food from weddings, parties, and events to redistribute it to individuals who are hungry, thereby reducing food waste and ensuring that surplus food benefits those in need.
+- Societal Impact:
The organization aims to bring benefits across society by providing access to food for individuals who may not have adequate means to access it, addressing food insecurity and hunger issues.
+- Alignment with Sustainable Development Goals:
Petari's mission aligns with India's Sustainable Development Goals, particularly focusing on making the world hunger-free and reducing food waste to contribute to a sustainable and equitable society.
+- Environmental Consciousness:
By redistributing excess food and reducing food waste, Petari helps alleviate the pressure on finite natural resources and minimizes the environmental impact associated with food wastage.
+- Economic Impact:
Through its activities, Petari not only addresses social issues related to hunger but also contributes to economic sustainability by efficiently utilizing excess resources and reducing wastage.
+- Collaboration with Events:
Petari likely collaborates with various events, such as weddings and parties, to collect surplus food, emphasizing the importance of partnerships and community involvement in achieving its goals.
+
+
+
+
+# Contribution Guidelines
+
Thank you for considering contributing to PETARI! We appreciate your efforts to make a positive impact on society through food redistribution and combating hunger. By contributing to PETARI, you are helping us move closer to our goal of creating a hunger-free world and reducing food waste.
## How Can You Contribute?
-
+
There are several ways you can contribute to PETARI:
1. **Code Contributions**: Help improve the PETARI codebase by fixing bugs, adding new features, or enhancing existing functionalities.
@@ -37,8 +75,10 @@ There are several ways you can contribute to PETARI:
5. **Feedback**: Provide feedback on the existing features, suggest new ideas, or share your thoughts on how PETARI can be further improved.
-## Getting Started
+
+## Getting Started
+
If you're new to contributing to open-source projects, don't worry! Here's how you can get started:
1. **Fork the Repository**: Fork the PETARI repository to your GitHub account.
@@ -164,9 +204,11 @@ If you're new to contributing to open-source projects, don't worry! Here's how y
15. **Create a Pull Request**: Open a pull request from your forked repository to the main PETARI repository. Provide a clear description of your changes in the pull request. Follow these steps
- Add the issue number, that you have been assigned[Formate:- Isuue number #(your issue number)]
- Brief description of the changes
+
+
## Code Style Guidelines
-
+
To maintain consistency and readability, please follow these code style guidelines:
- Use meaningful variable and function names.
@@ -174,16 +216,19 @@ To maintain consistency and readability, please follow these code style guidelin
- Write clear and concise comments to explain complex logic or algorithms.
## Code Review Process
-
+
All contributions to PETARI will go through a code review process to ensure code quality, consistency, and adherence to project standards. Your contributions are valuable, and we appreciate your patience during the review process.
## Community Guidelines
+
PETARI is committed to fostering an inclusive and welcoming community. We encourage respectful and constructive communication among contributors. Please refer to our [Code of Conduct]-(https://github.com/Sahil1786/Petari/blob/dffa12d5f33b3227ec287af602762ef1f7bc3f89/Code_of_conduct.md) for more information.
+
-## Output Screenshot
+## Output Screenshot
+
### 1. Index Page
The index page serves as the main landing page for PETARI. It showcases the mission and purpose of the organization, along with relevant information about its activities.
@@ -205,3 +250,5 @@ Admins have special privileges and access to manage the platform. The admin logi
![Admin Login Page](https://github.com/Sahil1786/Petari/assets/111786720/fb1cc46a-e3ad-40fd-93c6-268849e05e91)
**Please follow me and give a star to my repository
+
+
diff --git a/app.js b/app.js
index e4331e0..70e2d1b 100644
--- a/app.js
+++ b/app.js
@@ -60,4 +60,7 @@ app.listen( process.env.port|| 3000,function(){
console.log("server is running on port 3000 ");
});
-
\ No newline at end of file
+// Route for policies.ejs
+app.get('/policies', (req, res) => {
+ res.render('policies'); // Ensure policies.ejs is in the views directory
+});
\ No newline at end of file
diff --git a/model/query.js b/model/query.js
index 9fa0ab9..1d80237 100644
--- a/model/query.js
+++ b/model/query.js
@@ -7,6 +7,12 @@ const querySchema = new mongoose.Schema(
subject: String,
message: String,
approved: { type: Boolean, default: false },
+ // adding models for storing ANSWERE ans USER_ID
+ answere: String,
+ user_id: {
+ type: mongoose.Schema.Types.ObjectId,
+ ref: "User",
+ },
},
{ timestamps: true }
);
diff --git a/model/user.js b/model/user.js
index 01c6015..9f12416 100644
--- a/model/user.js
+++ b/model/user.js
@@ -31,6 +31,8 @@ const userSchema = new mongoose.Schema({
approved: { type: Boolean, default: false },
// googleId: String,
// profile: String,
+ resetTokenExpiration: Date,
+ resetToken:String
});
const User = new mongoose.model("User", userSchema);
diff --git a/public/css/admin_css.css b/public/css/admin_css.css
index a37489a..4ad6d37 100644
--- a/public/css/admin_css.css
+++ b/public/css/admin_css.css
@@ -5,6 +5,46 @@ body{
background: #ececec;
}
+/* Dark Mode */
+
+.dark-mode {
+ background-color: #121212;
+ color: #e0e0e0;
+}
+
+.dark-mode #darkModeToggle {
+ background-color: #333; /* Dark background color */
+}
+
+.dark-mode #darkModeIcon {
+ color: #e0e0e0; /* Dark mode icon color */
+}
+
+/* Dark Mode Toggle Button - Hover */
+#darkModeToggle:hover {
+ background-color: #555; /* Dark background color on hover */
+}
+
+/* Dark Mode Toggle Button */
+#darkModeToggle {
+ width: 50px;
+ height: 50px;
+ border: none; /* Remove border */
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ z-index: 1000; /* Ensure it's above other content */
+}
+
+#darkModeIcon {
+ font-size: 24px;
+}
+
+.dark-mode .custom-box {
+ background-color: #333 !important; /* Dark mode background color for the login container */
+ color: #e0e0e0; /* Dark mode text color for the login container */
+}
+
/*------------ Login container ------------*/
.box-area{
diff --git a/public/css/policies.css b/public/css/policies.css
new file mode 100644
index 0000000..7982c1b
--- /dev/null
+++ b/public/css/policies.css
@@ -0,0 +1,24 @@
+.container{
+ margin: 40px;
+ font-family: 'Poppins', sans-serif;
+ font-size: 18px;
+}
+
+.section{
+ padding: 15px;
+}
+
+.heading{
+ font-size: 25px;
+ text-decoration: underline;
+ color: rgb(4, 101, 10);
+
+}
+
+.content{
+ padding: 15px;
+}
+
+hr#line{
+ border: 1px solid rgb(4, 101, 10);
+}
\ No newline at end of file
diff --git a/public/css/style.css b/public/css/style.css
index dfc6e44..dd753ab 100644
--- a/public/css/style.css
+++ b/public/css/style.css
@@ -29,29 +29,11 @@ body{
}
body {
background-color:#ECF2FF;
- }
- header{
- background-color: #24252A;
- }
-
-.max-width{
- max-width: 1300px;
- padding: 0 80px;
- margin: auto;
-}
-.about{
- font-family: 'Poppins', sans-serif;
-}
-.about .about-content{
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- justify-content: space-between;
-}
+ }
/* landing section */
.hero{
- height: 90vh;
+ height: 100vh;
display: flex;
align-items: center;
}
@@ -97,11 +79,51 @@ body{
transition: all 0.3s ease 0s;
margin-bottom: 40px;
}
-/* */
+/* about section */
+.about{
+ font-family: 'Poppins', sans-serif;
+ display: flex;
+ padding: 20px;
+}
+.hero2_img{
+ width: 500px;
+ height: 500px;
+ border-radius: 50%;
+ margin-left: 80px;
+}
+.about-txt{
+ display: flex;
+ flex-wrap: wrap;
+ margin-left: 50px;
+ margin-top: 70px;
+}
+#more {display: none;}
+#myBtn {cursor: pointer;}
+/* contact section */
+.contact{
+ font-family: 'Poppins', sans-serif;
+ display: flex;
+ padding: 20px;
+ align-items: center;
+ gap: 500px;
+ justify-content: center;
+}
+.contact1{
+ display: block;
+ margin-top: 70px;
+ font-size:medium;
+}
+.contact2{
+ margin-top: 70px;
+ width: 400px;
+}
+.address-info{
+ display: block;
+}
/* all similar content styling codes */
-section{
+/* section{
padding: 100px 0;
}
.max-width{
@@ -139,7 +161,7 @@ section .title{
background: #111;
transform: translateX(-50%);
} */
-section .title::after{
+/* section .title::after{
position: absolute;
bottom: -8px;
left: 50%;
@@ -149,14 +171,11 @@ section .title::after{
background: #fff;
transform: translateX(-50%);
}
-
+ */
/* about section styling */
-.about .title::after{
- content: "Who We are";
-}
-.about .about-content .left{
+/* .about .about-content .left{
width: 45%;
}
.about .about-content .left img{
@@ -194,11 +213,11 @@ section .title::after{
.about .about-content .right a:hover{
color: crimson;
background: none;
-}
+} */
/* contact section styling */
-.contact .title::after{
+/* .contact .title::after{
content: "Get In Touch";
}
.contact .contact-content .column{
@@ -290,7 +309,7 @@ section .title::after{
background: crimson;
border: 2px solid crimson;
transition: all 0.3s ease;
-}
+} */
@@ -298,7 +317,7 @@ section .title::after{
/* footer section styling */
footer{
- background: #111;
+ background: #353535;
padding: 15px 23px;
color: #fff;
text-align: center;
@@ -328,4 +347,127 @@ body{
#contact {
margin-bottom: 50px; /* Adjust the value as needed */
-}
\ No newline at end of file
+}
+
+body {
+ transition: background-color 0.3s, color 0.3s;
+}
+
+.dark-mode {
+ background-color: #121212;
+ color: #e0e0e0;
+}
+
+.navbar.bg-body-secondary {
+ background-color: var(--bs-body-bg);
+}
+
+.dark-mode .navbar.bg-body-secondary {
+ background-color: #1c1c1c;
+}
+
+.dark-mode .hero_text,
+.dark-mode .hero_text2,
+.dark-mode .hero_text3 {
+ color: #e0e0e0;
+}
+
+/* Dark mode styles */
+.dark-mode .navbar {
+ background-color: #333 !important;
+}
+
+.dark-mode .navbar .navbar-brand,
+.dark-mode .navbar .nav-link,
+.dark-mode .navbar .btn {
+ color: #e0e0e0;
+}
+
+.dark-mode .navbar-toggler {
+ border-color: #e0e0e0;
+}
+
+.dark-mode .navbar-toggler-icon {
+ filter: invert(1);
+}
+
+.dark-mode .contact .text {
+ color: #e0e0e0;
+}
+
+.dark-mode .title {
+ color: #e0e0e0;
+}
+
+.dark-mode .icons .info .head,
+.dark-mode .icons .info .sub-title {
+ color: #e0e0e0;
+}
+@media (min-width: 768px) {
+ #myBtn { display: none; }
+ #dots { display: none; }
+ #more { display: inline; }
+}
+@media (max-width: 768px) {
+ .hero{
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ margin-top: 120px;
+ }
+ .hero_img{
+ width: 300px;
+ height: 300px;
+ margin-left: 0px;
+ }
+ .left{
+ display: none;
+ }
+ .hero_text{
+ margin-left: auto;
+ }
+ .hero_text2{
+ margin-left: auto;
+ }
+ .hero_text3{
+ margin-left: auto;
+ }
+ .hero_btn{
+ margin-left: auto;
+ }
+ /* about section */
+ .abt-txt{
+ margin-top: 20px;
+ }
+ .about{
+ flex-direction: column-reverse;
+ text-align: center;
+ align-items: center;
+ justify-content: center;
+ }
+ .hero2_img{
+ width: 280px;
+ height: 280px;
+ margin-left: 0px;
+ }
+ .about-txt{
+ margin-left: auto;
+ font-size:17px;
+ margin-top: 0px;
+ }
+ /* contact section */
+ .contact{
+ flex-direction: column;
+ text-align: center;
+ align-items: center;
+ justify-content: center;
+ gap: 10px;
+ }
+ .con-txt{
+ margin-top: 20px;
+ }
+ .contact2{
+ width: 350px;
+ }
+}
diff --git a/routers/NgoRoutes.js b/routers/NgoRoutes.js
index 8f7d274..61706c9 100644
--- a/routers/NgoRoutes.js
+++ b/routers/NgoRoutes.js
@@ -1,8 +1,8 @@
const express = require("express");
const router = new express.Router();
const fs = require("fs");
-const path = require('path');
-const Handlebars = require('handlebars');
+const path = require("path");
+const Handlebars = require("handlebars");
const bcrypt = require("bcrypt");
const saltRounds = 10;
@@ -19,19 +19,29 @@ router.post("/NGO-login", async (req, res) => {
const username = req.body.username;
const password = req.body.password;
const ngo = await NGO.findOne({ username: username, password: password });
+
try {
- const dooner = await User.find(); // Assuming User is your Mongoose model for users
-
- res.render("NGO-Dashboard", {
- fullName: ngo.NGOName,
- email: ngo.username,
- id: ngo.NGOID,
- phoneNo: ngo.Mobile,
- address: ngo.NGOLocation,
- Donation: dooner,
- Pickup: dooner,
- complain: "",
- });
+ if (ngo) {
+ //checking NGO is APPROVED or NOT
+ if (ngo.approved == false) {
+ res.status(500).json({ messaage: "NGO is send for approval" });
+ }
+
+ const dooner = await User.find(); // Assuming User is your Mongoose model for users
+
+ res.render("NGO-Dashboard", {
+ fullName: ngo.NGOName,
+ email: ngo.username,
+ id: ngo.NGOID,
+ phoneNo: ngo.Mobile,
+ address: ngo.NGOLocation,
+ Donation: dooner,
+ Pickup: dooner,
+ complain: "",
+ });
+ } else {
+ res.status(404).json({ message: "NGO is not registered" });
+ }
} catch (err) {
console.error(err);
res.status(500).send("An internal server error occurred.");
@@ -61,24 +71,28 @@ router.post("/NGO-Registarion", async (req, res) => {
// Save the new NGO to the database
await newNGO.save();
- const templatePath = path.join(__dirname, '../views', 'Email.template.handlebars');
- const templateContent = fs.readFileSync(templatePath, 'utf8');
-
-// Compile the Handlebars template with the provided context data
-const compiledHtml = Handlebars.compile(templateContent)({
- user: {
- _id: newNGO.NgoID, // Example ID
- username: newNGO.NGOName, // Example username
- email: newNGO.username, // Example email
- fname: newNGO.NGOName // Example first name
- }
- });
+ const templatePath = path.join(
+ __dirname,
+ "../views",
+ "Email.template.handlebars"
+ );
+ const templateContent = fs.readFileSync(templatePath, "utf8");
+
+ // Compile the Handlebars template with the provided context data
+ const compiledHtml = Handlebars.compile(templateContent)({
+ user: {
+ _id: newNGO.NgoID, // Example ID
+ username: newNGO.NGOName, // Example username
+ email: newNGO.username, // Example email
+ fname: newNGO.NGOName, // Example first name
+ },
+ });
// Send an email to the admin for approval
const mailOptions = {
to: newNGO.username, // Admin's email address
subject: "New NGO Registration",
text: "A new NGO registration is pending approval. Login to the admin panel to review and approve.",
- html: compiledHtml
+ html: compiledHtml,
// Include any necessary information in the email body
};
transporter.transporter.sendMail(mailOptions, function (error, info) {
diff --git a/routers/adminRoutes.js b/routers/adminRoutes.js
index 150352a..1e6061e 100644
--- a/routers/adminRoutes.js
+++ b/routers/adminRoutes.js
@@ -54,8 +54,8 @@ router.post("/admin-login", async (req, res) => {
const dooner = await User.find(); // Assuming User is your Mongoose model for users
const ngo = await NGO.find();
- const query1 = await problem.find();
-
+ //return UNRESOLVED query
+ const query1 = await problem.find({ answere: { $exists: false } });
res.render("Admin_Dashboard", {
name: admin.fullName,
email: admin.email,
@@ -141,7 +141,8 @@ router.post("/approve-ngo/:id/:userId", async (req, res) => {
const dooner = await User.find(); // Assuming User is your Mongoose model for users
const ngo = await NGO.find();
- const query1 = await problem.find();
+ //return UNRESOLVED query
+ const query1 = await problem.find({ answere: { $exists: false } });
res.render("Admin_Dashboard", {
name: admin.fullName,
email: admin.fullName,
@@ -178,7 +179,8 @@ router.post("/decline-ngo/:id/:userId", async (req, res) => {
const dooner = await User.find(); // Assuming User is your Mongoose model for users
const ngo = await NGO.find();
- const query1 = await problem.find();
+ //return UNRESOLVED query
+ const query1 = await problem.find({ answere: { $exists: false } });
res.render("Admin_Dashboard", {
name: admin.fullName,
email: admin.fullName,
@@ -215,7 +217,8 @@ router.post("/decline-donor/:id/:userId", async (req, res) => {
const dooner = await User.find(); // Assuming User is your Mongoose model for users
const ngo = await NGO.find();
- const query1 = await problem.find();
+ //return UNRESOLVED query
+ const query1 = await problem.find({ answere: { $exists: false } });
res.render("Admin_Dashboard", {
name: admin.fullName,
email: admin.fullName,
@@ -253,7 +256,8 @@ router.post("/accept-donor/:id/:userId", async (req, res) => {
const dooner = await User.find(); // Assuming User is your Mongoose model for users
const ngo = await NGO.find();
- const query1 = await problem.find();
+ //return UNRESOLVED query
+ const query1 = await problem.find({ answere: { $exists: false } });
res.render("Admin_Dashboard", {
name: admin.fullName,
email: admin.fullName,
@@ -289,7 +293,8 @@ router.post("/delete-complain/:id/:userId", async (req, res) => {
const dooner = await User.find(); // Assuming User is your Mongoose model for users
const ngo = await NGO.find();
- const query1 = await problem.find();
+ //return UNRESOLVED query
+ const query1 = await problem.find({ answere: { $exists: false } });
res.render("Admin_Dashboard", {
name: admin.fullName,
email: admin.fullName,
@@ -325,7 +330,8 @@ router.post("/accept-complain/:id/:userId", async (req, res) => {
const dooner = await User.find(); // Assuming User is your Mongoose model for users
const ngo = await NGO.find();
- const query1 = await problem.find();
+ //return UNRESOLVED query
+ const query1 = await problem.find({ answere: { $exists: false } });
res.render("Admin_Dashboard", {
name: admin.fullName,
email: admin.fullName,
@@ -343,71 +349,78 @@ router.post("/accept-complain/:id/:userId", async (req, res) => {
});
//making a POST method for RESPONDE to email
-router.post("/complains-response/:email/:userId", async (req, res) => {
+router.post("/complains-response/:email/:userId/:id", async (req, res) => {
const email = req.params.email;
const answere = req.body.answere;
const userId = req.params.userId;
- console.log(email, answere, userId);
+ const compId = req.params.id;
- //sending email to the COMPLAIN email
try {
- const transporter = nodemailer.createTransport({
- service: "gmail",
- host: "smtp.gmail.com",
- port: 465,
- secure: true,
- auth: {
- user: process.env.mail_id,
- pass: process.env.pass_id,
- },
- });
-
- let MailGenerator = new Mailgen({
- theme: "default",
- product: {
- name: "PETARI",
- link: "https://mailgen.js",
- },
- });
-
- let response = {
- body: {
- name: "",
- intro: "Welcome to PETARI! We're very excited to have you on board.",
- action: {
- instructions: answere,
- button: {
- color: "#22BC66", // Optional action button color
- text: "Have a good day",
- link: "",
+ //checking user EXIST or NOT
+ const userExist = await User.findOne({ email });
+ if (userExist) {
+ const complaint = await Query.findByIdAndUpdate(compId, {
+ answere,
+ });
+ } else {
+ //sending email to the COMPLAIN email
+ const transporter = nodemailer.createTransport({
+ service: "gmail",
+ host: "smtp.gmail.com",
+ port: 465,
+ secure: true,
+ auth: {
+ user: process.env.mail_id,
+ pass: process.env.pass_id,
+ },
+ });
+ let MailGenerator = new Mailgen({
+ theme: "default",
+ product: {
+ name: "PETARI",
+ link: "https://mailgen.js",
+ },
+ });
+ let response = {
+ body: {
+ name: "",
+ intro: "Welcome to PETARI! We're very excited to have you on board.",
+ action: {
+ instructions: answere,
+ button: {
+ color: "#22BC66",
+ text: "Have a good day",
+ link: "",
+ },
},
+ outro: "Thankyou for a part of PETARI",
},
- outro: "Thankyou for a part of PETARI",
- },
- };
-
- let mail = MailGenerator.generate(response);
-
- let message = {
- to: email,
- subject: "Petari Support team",
- html: mail,
- };
+ };
+ let mail = MailGenerator.generate(response);
+ let message = {
+ to: email,
+ subject: "Petari Support team",
+ html: mail,
+ };
+ transporter
+ .sendMail(message)
+ .then(() => {
+ console.log("email is send successfully");
+ })
+ .catch((error) => {
+ console.log("Email is not send", error);
+ });
+
+ //DELETING complain after response because user does not exist
+ await Query.findByIdAndDelete(compId);
+ }
- transporter
- .sendMail(message)
- .then(() => {
- console.log("email is send successfully");
- })
- .catch((error) => {
- console.log("Email is not send", error);
- });
const admin = await Admin.findById(userId);
console.log("admin details in approve-ngo", admin);
const dooner = await User.find(); // Assuming User is your Mongoose model for users
const ngo = await NGO.find();
- const query1 = await problem.find();
+ const query1 = await problem.find({ answere: { $exists: false } });
res.render("Admin_Dashboard", {
name: admin.fullName,
email: admin.fullName,
diff --git a/routers/userRoutes.js b/routers/userRoutes.js
index 673704c..1463311 100644
--- a/routers/userRoutes.js
+++ b/routers/userRoutes.js
@@ -1,9 +1,11 @@
const express = require("express");
const router = new express.Router();
+const path = require("path");
const bcrypt = require("bcrypt");
const saltRounds = 10;
const jwt = require("jsonwebtoken");
+const nodemailer = require("nodemailer");
const User = require("../model/user");
const Query = require("../model/query"); // Adjust the path based on your project structure
@@ -36,18 +38,34 @@ router.get("/success", function (req, res) {
});
router.post("/", async function (req, res) {
+ const email = req.body.Email;
try {
- const newQuery = new Query({
- name: req.body.Fname,
- email: req.body.Email,
- subject: req.body.sub,
- message: req.body.sms,
- });
+ //finding the user EXIST or NOT in DATABASE
+ const userExist = await User.findOne({ email });
+ if (userExist) {
+ const newQuery = new Query({
+ name: req.body.Fname,
+ email: req.body.Email,
+ subject: req.body.sub,
+ message: req.body.sms,
+ user_id: userExist._id,
+ });
+
+ await newQuery.save();
+ console.log(newQuery);
+ } else {
+ const newQuery = new Query({
+ name: req.body.Fname,
+ email: req.body.Email,
+ subject: req.body.sub,
+ message: req.body.sms,
+ });
- await newQuery.save();
+ await newQuery.save();
+ console.log(newQuery);
+ }
res.status(200).send("Successfully Received Message... Thank You!");
- console.log(newQuery);
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
@@ -67,12 +85,14 @@ router.post("/login", async function (req, res) {
const result = await bcrypt.compare(password, foundUser.password);
+ const userQuerys = await Query.find({ user_id: foundUser._id });
if (result) {
return res.render("UserDashBoard", {
fullName: foundUser.fullName,
email: foundUser.email,
phoneNo: foundUser.Mobile,
address: foundUser.address,
+ complain: userQuerys,
});
} else {
return res.render("loginError", { message: "Incorrect password" });
@@ -83,83 +103,6 @@ router.post("/login", async function (req, res) {
}
});
-router.route("/forgot-password").get(async (req, res) => {
- res.render("forget-password");
-});
-
-router.route("/reset-password").get(async (req, res) => {
- const { email, token } = req.query;
-
- try {
- const user = await User.findOne({
- email,
- resetToken: token,
- resetTokenExpiration: { $gt: Date.now() },
- });
-
- if (!user) {
- return res.status(400).send("Invalid or expired reset token");
- }
-
- // Verify the token
- try {
- const decodedToken = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET);
- // Process the decoded token (e.g., extract information from it)
- console.log(decodedToken);
- // Continue with the reset-password logic
- res.render("reset-password", { email, token });
- } catch (error) {
- // Handle JWT verification errors
- console.error("JWT verification error:", error.message);
- // You might want to send an error response or redirect the user
- res.status(401).send("Unauthorized");
- }
- } catch (error) {
- console.error(error);
- res.status(500).send("Internal Server Error");
- }
-});
-
-router.post(async (req, res) => {
- const { email, token, newPassword } = req.body;
-
- try {
- // Verify the token again
- const user = await User.findOne({
- email,
- resetToken: token,
- resetTokenExpiration: { $gt: Date.now() },
- });
-
- if (!user) {
- return res.status(400).send("Invalid or expired reset token");
- }
-
- try {
- const decodedToken = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET);
- // Process the decoded token (e.g., extract information from it)
- console.log(decodedToken);
-
- // Update the user's password and reset the resetToken fields
- const hash = await bcrypt.hash(newPassword, saltRounds);
- user.password = hash;
- user.resetToken = null;
- user.resetTokenExpiration = null;
- await user.save();
-
- res.redirect("/login"); // Redirect to login page or any other desired page
- } catch (error) {
- // Handle JWT verification errors
- console.error("JWT verification error:", error.message);
- // You might want to send an error response or redirect the user
- res.status(401).send("Unauthorized");
- }
- } catch (error) {
- console.error(error);
- res.status(500).send("Internal Server Error");
- }
-});
-
// extra details added for the user
router.post("/add-details", async (req, res) => {
try {
@@ -284,6 +227,7 @@ router.get("/logout", function (req, res) {
// user Registration
router.post("/User_singUp", async function (req, res) {
const { username } = req.body;
+ const fullName = req.body.fname;
try {
// Check if the email already exists
@@ -310,43 +254,63 @@ router.post("/User_singUp", async function (req, res) {
password: hash,
});
+ // creating a message for USER
+ const message = `Thank you, ${(fullName).toUpperCase()}, for connecting with the PETARI organization.`
+
await newUser.save().then((user) => {
let mailOptions = {
to: user.email,
subject: "Welcome To Petari",
template: "Email.template",
- context: {
- user: {
- fname: user.fullName,
- _id: user._id,
- username: user.fullName,
- email: user.email,
- },
- year: new Date().getFullYear(),
- },
+ // context: {
+ // user: {
+ // fname: user.fullName,
+ // _id: user._id,
+ // username: user.fullName,
+ // email: user.email,
+ // },
+ // year: new Date().getFullYear(),
+ // },
+ text: message,
attachments: [
{
filename: "logo.png",
- path: path.join(__dirname, "public", "img", "logo.png"),
+ path: path.join(__dirname, "..", "public", "img", "logo.png"),
cid: "logo",
},
],
};
+
+ const transporter = nodemailer.createTransport({
+ service: "gmail",
+ host: "smtp.gmail.com",
+ port: 465,
+ secure: true,
+ auth: {
+ user: process.env.mail_id,
+ pass: process.env.pass_id,
+ },
+ });
+
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
- console.log("Email sent: " + info.response);
+ console.log("Email sent successfully: " + info.response);
}
});
});
+ const foundUser = await User.findOne({ email: username });
+
+ const userQuerys = await Query.find({ user_id: foundUser._id });
+
return res.render("UserDashBoard", {
- fullName: req.body.fname,
- email: username,
- phoneNo: req.body.phn,
- address: req.body.address,
- // Do not include 'profile' here unless it's relevant to registration
+ fullName: foundUser.fullName,
+ email: foundUser.email,
+ phoneNo: foundUser.Mobile,
+ address: foundUser.address,
+ complain: userQuerys,
});
} catch (error) {
console.error("Error during user registration:", error);
@@ -354,7 +318,12 @@ router.post("/User_singUp", async function (req, res) {
}
});
-router.post(async (req, res) => {
+router.route("/forgot-password").get(async (req, res) => {
+ res.render("forget-password");
+});
+
+//send Email for the reset password
+router.route("/forgot-password").post(async (req, res) => {
const { email } = req.body;
try {
const user = await User.findOne({ email });
@@ -370,6 +339,9 @@ router.post(async (req, res) => {
);
user.resetTokenExpiration = Date.now() + 300000; // 5 minutes
+ user.resetToken = resetToken;
+
+ console.log("use after setting ", user);
await user.save();
// Send the reset link to the user via email
@@ -393,7 +365,7 @@ router.post(async (req, res) => {
attachments: [
{
filename: "logo.png",
- path: path.join(__dirname, "public", "img", "logo.png"),
+ path: path.join("public", "img", "logo.png"),
cid: "logo",
},
],
@@ -414,4 +386,111 @@ router.post(async (req, res) => {
}
});
+// verify Email and render reset password page
+router.route("/reset-password").get(async (req, res) => {
+ const { email, token } = req.query;
+ try {
+ const user = await User.findOne({
+ email,
+ resetToken: token,
+ resetTokenExpiration: { $gt: Date.now() },
+ });
+
+ if (!user) {
+ return res.status(400).send("Invalid or expired reset token");
+ }
+
+ // Verify the token
+ try {
+ const decodedToken = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET);
+ // Process the decoded token (e.g., extract information from it)
+ console.log(decodedToken);
+ // Continue with the reset-password logic
+ res.render("set_password", { email, token });
+ } catch (error) {
+ // Handle JWT verification errors
+ console.error("JWT verification error:", error.message);
+ // You might want to send an error response or redirect the user
+ res.status(401).send("Unauthorized");
+ }
+ } catch (error) {
+ console.error(error);
+ res.status(500).send("Internal Server Error");
+ }
+});
+
+//verify the password
+router.route("/reset-password").post(async (req, res) => {
+ const { email, token } = req.query;
+ const { newPassword } = req.body;
+ // console.log(" User Info",email,token,newPassword);
+
+ try {
+ // Verify the token again
+ const user = await User.findOne({
+ email,
+ resetToken: token,
+ resetTokenExpiration: { $gt: Date.now() },
+ });
+
+ if (!user) {
+ return res.status(400).send("Invalid or expired reset token");
+ }
+
+ try {
+ const decodedToken = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET);
+ // Process the decoded token (e.g., extract information from it)
+ console.log(decodedToken);
+
+ // Update the user's password and reset the resetToken fields
+ const hash = await bcrypt.hash(newPassword, saltRounds);
+ user.password = hash;
+ user.resetToken = null;
+ user.resetTokenExpiration = null;
+ await user.save();
+
+ return res.render("UserDashBoard", {
+ fullName: user.fullName,
+ email: user.email,
+ phoneNo: user.Mobile,
+ address: user.address,
+ });
+
+ // Redirect to login page or any other desired page
+ } catch (error) {
+ // Handle JWT verification errors
+ console.error("JWT verification error:", error.message);
+ // You might want to send an error response or redirect the user
+ res.status(401).send("Unauthorized");
+ }
+ } catch (error) {
+ console.error(error);
+ res.status(500).send("Internal Server Error");
+ }
+});
+
+//making a POST method for DELETING the COMPLAINt
+router.post("/delete-query/:id/:email", async (req, res) => {
+ const compId = req.params.id;
+ const email = req.params.email;
+ try {
+ const dele = await Query.findByIdAndDelete(compId);
+
+ //rendering USER DASHBOARD
+ const foundUser = await User.findOne({ email });
+ const userQuerys = await Query.find({ user_id: foundUser._id });
+
+ return res.render("UserDashBoard", {
+ fullName: foundUser.fullName,
+ email: foundUser.email,
+ phoneNo: foundUser.Mobile,
+ address: foundUser.address,
+ complain: userQuerys,
+ });
+ } catch (error) {
+ console.error(error);
+ res.status(500).send("Internal Server Error");
+ }
+});
+
module.exports = router;
diff --git a/views/Admin_Dashboard.ejs b/views/Admin_Dashboard.ejs
index 48b34ae..12ca23c 100644
--- a/views/Admin_Dashboard.ejs
+++ b/views/Admin_Dashboard.ejs
@@ -670,7 +670,8 @@