Skip to content

Commit

Permalink
Merge pull request #24 from scienmanas/mvp
Browse files Browse the repository at this point in the history
Mvp
  • Loading branch information
scienmanas authored Dec 14, 2024
2 parents 4b7185b + a046394 commit 08d62f0
Show file tree
Hide file tree
Showing 120 changed files with 5,281 additions and 39,362 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div align="center">
<img src="https://github.com/user-attachments/assets/68574249-3ed4-4651-bdba-84791185ee7b" alt="Logo">
<img src="images/logo.png" alt="Logo">
</div>

# 🔰 Certiailer
Expand All @@ -9,6 +9,7 @@ An all in one tool to generate certificates is mass and mail them. Moreover the
## Divisions

CertiMailer is an open source project with a website as well as script version. The whole project is divided into two division for differnt users:

- `Python Script`: For advanced user who want to use the codebase or make their own.
- `Web version`: A web version is made hosted on free tier of different services. Intended for normal users.

Expand All @@ -19,12 +20,11 @@ CertiMailer is an open source project with a website as well as script version.
- Mailny python and its differnt libraries.

### Website

- **Client:** Next JS, TailwindCSS.
- **Server:** Node, Express.
- **Datebase:** Mongo DB, Google cloud storage bucket.



## 🔨 Setting Up

To set up the project locally, follow the steps mentioned in their respective folders (for `python script` and `web version`).
Expand All @@ -34,8 +34,7 @@ To set up the project locally, follow the steps mentioned in their respective fo
- `Fully customizable`: The python script is fully customizable (developer, get your hands dirty).
- `id verification, automatic generation, automatic mailing, etc`.

## 📁 File Structure

## 📁 File Structure

```
.
Expand All @@ -52,6 +51,7 @@ To set up the project locally, follow the steps mentioned in their respective fo
├── LICENSE
└── README.md
```

- For detail view of file structure for each part look into that specific part respectively.

## 🔥 Contributing
Expand Down
Binary file removed Website/Backend/Manas.pdf
Binary file not shown.
65 changes: 65 additions & 0 deletions Website/Backend/helpers/mailer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import nodemailer from "nodemailer";
import multer from "multer";

const PORT: number = 465;
const storage = multer.memoryStorage(); // Store the files in memory
const upload = multer({ storage });

export async function sendMail({
fromName = "",
toName = "",
toEmail,
subject,
message,
file,
}: {
fromName: string;
toName?: string;
toEmail: string;
subject: string;
message: string;
file?: Express.Multer.File;
}): Promise<void> {
const EMAIL = process.env.ADMIN_EMAIL;
const PASSWORD = process.env.ADMIN_APP_PASSWORD;

if (!EMAIL || !PASSWORD) {
throw new Error(
"Email credentials are not set in the environment variables."
);
}

// Create transporter
const transporter = nodemailer.createTransport({
host: "smtppro.zoho.in",
port: PORT,
secure: true, // Use SSL
auth: {
user: EMAIL,
pass: PASSWORD,
},
});

// Mail options
const mailOptions: nodemailer.SendMailOptions = {
from: `${fromName} <${EMAIL}>`,
to: `${toName} <${toEmail}>`,
replyTo: `Manas <[email protected]>`,
subject: subject,
text: message,
};

// Attach the file if present
if (file) {
mailOptions.attachments = [
{
filename: file.originalname,
content: file.buffer,
encoding: "base64",
},
];
}

// Send the mail
await transporter.sendMail(mailOptions);
}
8 changes: 6 additions & 2 deletions Website/Backend/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import express, { Express, Request, Response } from "express";
import cors from "cors";
import { config } from "dotenv";
import { connectToDB } from "./config/db";
import cookieParser from "cookie-parser";
// Routes import
import certificatesRoute from "./routes/certificate";
import authRoute from "./routes/auth";
import sendEmailsRoute from "./routes/sendEmails";
import UserRoute from "./routes/user";
import userRoute from "./routes/user";
import utilsRoute from "./routes/utils";

// Load the env
config();
Expand All @@ -28,12 +30,14 @@ const corsConfiguration = {
// middleware to use import routes and enable cors
app.use(express.json());
app.use(cors(corsConfiguration));
app.use(cookieParser());

// Routes
app.use("/api/certificate", certificatesRoute);
app.use("/api/auth", authRoute);
app.use("/api/send-email", sendEmailsRoute);
app.use("/api/user", UserRoute);
app.use("/user", userRoute);
app.use("/api/utils", utilsRoute);

// Landing endpoint
app.get("/", (req: Request, res: Response) => {
Expand Down
2 changes: 1 addition & 1 deletion Website/Backend/lib/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ export type waitlistParams = {

export type newsLetterParams = {
email: string;
};
};
50 changes: 46 additions & 4 deletions Website/Backend/middlewares/protectRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,52 @@
import { createHash } from "crypto";
import { Request, Response, NextFunction } from "express";
import jwt from "jsonwebtoken";
import User from "../models/user";
import { ObjectId } from "mongoose";

export const protectUserRoutes = (
req: Request,
interface CustomRequest extends Request {
user?: ObjectId;
}

interface JwtPayload {
user: {
_id: string;
};
}

const JWT_SECRET: string = process.env.JWT_SECRET as string;

export const protectUserRoutes = async (
req: CustomRequest,
res: Response,
next: NextFunction
) => {
// To be updates
// Get the user from the jwt token
const token: string = req.header("auth-token") as string;
if (!token) {
return res.status(401).json({ message: "Unauthorised - No Token" });
}

try {
const decode = jwt.verify(token, JWT_SECRET) as JwtPayload;

// For no valid token got
if (!decode) {
return res.status(401).json({ message: "Unauthorised - Invalid Token" });
}

// Find the user in database and check whther he is correct
const findUser = await User.findById(decode.user._id);
if (!findUser) {
return res.status(401).json({ message: "Unauthorised" });
}

req.user = findUser._id;
next();
} catch (error) {
console.log(error);
res.status(401).status(401).json({ message: "Unathorised" });
}
};

export const protectAdminRoutes = (
Expand All @@ -15,7 +55,9 @@ export const protectAdminRoutes = (
next: NextFunction
) => {
// Get the header
const ADMIN_AUTH_KEY: string | undefined = req.header("admin-auth-token") as string;
const ADMIN_AUTH_KEY: string | undefined = req.header(
"admin-auth-token"
) as string;
if (ADMIN_AUTH_KEY === undefined) {
res.status(401).json({ message: "Access Denied" });
return;
Expand Down
20 changes: 20 additions & 0 deletions Website/Backend/models/flagged-user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import mongoose from "mongoose";

const flaggedUserchema = new mongoose.Schema(
{
email: { type: String, required: true },
registered: { type: String, required: true, enum: ["yes", "no"] },
time_stamp: { type: String, require: true, default: Date.now },
severity: {
type: String,
required: true,
enum: ["yellow", "red"],
},
},
{
collection: "flagged",
}
);

export default mongoose.models.FlaggedUser ||
mongoose.model("FlaggedUser", flaggedUserchema);
16 changes: 9 additions & 7 deletions Website/Backend/models/newsletter.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import mongoose from "mongoose";

const newsLetterSchema = new mongoose.Schema(
{
email: { type: String, required: true, unique: false }
},
{
collection: 'newsletter'
}
{
email: { type: String, required: true, unique: false },
date: { type: Date, default: Date.now },
},
{
collection: "newsletter",
}
);

export default mongoose.models.newsLetter || mongoose.model('newsLetter', newsLetterSchema)
export default mongoose.models.newsLetter ||
mongoose.model("newsLetter", newsLetterSchema);
17 changes: 17 additions & 0 deletions Website/Backend/models/otp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import mongoose, { Schema } from "mongoose";

const OtpSchema = new mongoose.Schema({
_id: {
type: Schema.Types.ObjectId,
required: true,
default:() => new mongoose.Types.ObjectId(),
},
user_id: {
type: Schema.Types.ObjectId,
required: true,
},
otp: { type: Number, required: true },
time_stamp: { type: String, required: true, default: Date.now() },
});

export default mongoose.models.Otp || mongoose.model("OTP", OtpSchema);
36 changes: 36 additions & 0 deletions Website/Backend/models/pending-user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import mongoose, { Schema } from "mongoose";

// In this password is not needed as it will be automatically generated by system, aslo user reaches this syaye only when he has confirmed OTP
// also recapta will be added

const pendingUserSchema = new mongoose.Schema(
{
_id: {
type: Schema.Types.ObjectId,
required: true,
default: () => new mongoose.Types.ObjectId(),
},
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
applier_type: { type: String, required: true, default: "none" },
logo_url: { type: String, required: true, default: "none" },
status: {
type: String,
required: true,
enum: ["verified", "unverified"],
default: "unverified",
},
about: { type: String, required: true, default: "none" },
website: { type: String, required: true, default: "none" },
designation: { type: String, required: true, default: "none" },
reason: { type: String, required: true, default: "none" },
schema_complete: { type: Boolean, required: true, default: false },
date_of_request: { type: String, required: true, default: Date.now },
},
{
collection: "pendingusers",
}
);

export default mongoose.models.PendingUser ||
mongoose.model("PendingUser", pendingUserSchema);
7 changes: 6 additions & 1 deletion Website/Backend/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ const userSchema = new mongoose.Schema(
default: () => new mongoose.Types.ObjectId(),
},
name: { type: String, required: true },
logo_url: { types: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
logo_url: { type: String, required: true },
status: { type: String, enum: ["verified", "unverified"], required: true },
about: { type: String, required: true },
type: { type: String, required: true },
website: { type: String, required: true },
},
{
collection: "user",
Expand Down
14 changes: 0 additions & 14 deletions Website/Backend/models/waitlist.ts

This file was deleted.

Loading

0 comments on commit 08d62f0

Please sign in to comment.