diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c9f697d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM node:20-alpine +# Set the working directory in the container +WORKDIR /app +# Copy package.json and package-lock.json to the working directory +COPY package*.json ./ +# Install dependencies +RUN npm install +# Copy the rest of the application code to the working directory +COPY . . +# Build the application +EXPOSE 5000 +# Set the environment variable for production +CMD [ "npm","start" ] \ No newline at end of file diff --git a/config/accont_verification_templete.js b/config/accont_verification_templete.js new file mode 100644 index 0000000..d43f967 --- /dev/null +++ b/config/accont_verification_templete.js @@ -0,0 +1,49 @@ +export const ACCOUNT_VERIFICATION_HTML_TEMPLETE = ` + + + + + Email Verification + + + +
+

Email Verification

+

Use the verification code below to confirm your email address.

+
{{otp}}
+

If you did not request this, please ignore this email.

+ +
+ +`; diff --git a/config/aws/awsconfig.js b/config/aws/awsconfig.js new file mode 100644 index 0000000..95f83d6 --- /dev/null +++ b/config/aws/awsconfig.js @@ -0,0 +1,11 @@ +import AWS from "aws-sdk"; + +//configure aws +AWS.config.update({ + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + region: process.env.AWS_REGION, +}); +const s3 = new AWS.S3(); + +export default s3; \ No newline at end of file diff --git a/db/database.js b/config/db/database.js similarity index 100% rename from db/database.js rename to config/db/database.js diff --git a/config/nodemailer.js b/config/nodemailer.js new file mode 100644 index 0000000..89d9120 --- /dev/null +++ b/config/nodemailer.js @@ -0,0 +1,16 @@ +import dotenv from "dotenv"; +import nodemailer from "nodemailer"; + +dotenv.config(); +//smtp email transport model +const transporter = nodemailer.createTransport({ + host: "smtp-relay.brevo.com", + port: process.env.SMTP_PORT, + secure: false, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SNTP_PASSWORD, + }, +}); + +export default transporter; diff --git a/config/reset_password_templete.js b/config/reset_password_templete.js new file mode 100644 index 0000000..e28fbb0 --- /dev/null +++ b/config/reset_password_templete.js @@ -0,0 +1,52 @@ +export const PASSWORD_RESET_TEMPLATE = ` + + + + + + Password Reset OTP + + + +
+

Password Reset Request

+

Use the OTP below to reset your password.

+
{{otp}}
+

If you did not request this, please ignore this email.

+ +
+ + + +`; diff --git a/controller/resourcecontroller.js b/controller/resourcecontroller.js new file mode 100644 index 0000000..499b665 --- /dev/null +++ b/controller/resourcecontroller.js @@ -0,0 +1,181 @@ +import dotenv from "dotenv"; +import s3 from "../config/aws/awsconfig.js"; +import video from "../models/video.model.js"; + +dotenv.config(); +//s3 bucket +const bucketName = process.env.AWS_BUCKET_NAME; + +//cloudfront url +const cloudFront = process.env.CLOUDFRONT_URL; +//get pre singed url +export const getPreSingedUrl = async (req, res) => { + const { userId, fileType, filename } = req.body; + if (!userId || !fileType || !filename) { + return res.status(400).json({ success: false, message: "empty parameter" }); + } + try { + const key = `reels/${userId}/${filename}`; + const params = { + Bucket: `${bucketName}`, + Key: key, + ContentType: fileType, + }; + + const uploadUrl = s3.getSignedUrl("putObject", params); + + if (!uploadUrl) { + return res + .status(400) + .json({ success: false, message: "cannot get url" }); + } + return res.status(200).json({ + success: true, + data: { + uploadUrl: uploadUrl, + videokey: key, + }, + }); + } catch (err) { + return res.status(500).json({ success: false, message: `${err}` }); + } +}; +//save metadata +export const saveMetaData = async (req, res) => { + const { userId, videoKey, title } = req.body; + if (!userId || !videoKey || !title) { + return res.status(400).json({ success: false, message: "empty parameter" }); + } + try { + const newVideo = new video({ + userId, + title, + url: videoKey, + }); + const createdVideo = await newVideo.save(); + return res.status(200).json({ + success: true, + data: { + id: createdVideo._id, + userId: createdVideo.userId, + videokey: createdVideo.url, + }, + }); + } catch (err) { + return res.status(500).json({ success: false, message: `${err}` }); + } +}; +//fetch all video data using cloudfront url +export const fetchVideoData = async (req, res) => { + const page = parseInt(req.query.page) || 1; + const limit = parseInt(req.query.limit) || 10; + + const skip = (page - 1) * limit; + try { + const videos = await video + .find({}) + .sort({ createdAt: -1 }) + .limit(limit) + .skip(skip); + + if (!videos) { + return res + .status(404) + .json({ success: false, message: "data not found" }); + } + const allVideos = videos.map((video) => ({ + reelId: video._id, + userId: video.userId, + title: video.title, + url: `${cloudFront}/${video.url}`, + joinedDate: video.createdAt, + updatedDate: video.updatedAt, + processed: video.processed, + weblink: video.weblink, + likes: video.likes, + disLikes: video.disLikes, + comments: video.comments, + tags: video.tags, + })); + + return res.status(200).json({ success: true, data: { videos: allVideos } }); + } catch (err) { + return res.status(500).json({ success: false, message: `${err}` }); + } +}; +//like reels +export const likeReels = async (req, res) => { + const { userId, reelId } = req.body; + + if (!userId || !reelId) { + return res + .status(400) + .json({ success: false, message: "invalid credientials" }); + } + + try { + const reel = await video.findById(reelId); + if (!reel) { + return res + .status(404) + .json({ success: false, message: "reel not found" }); + } + //check if like or not + const isLiked = reel.likes.includes(userId); + if (isLiked) { + //remove userid if already liked + reel.likes = reel.likes.filter((id) => id !== userId); + } else { + //add new like + reel.likes.push(userId); + } + + const updatedReel = await reel.save();`` + return res.status(200).json({ + success: true, + data: { + reel: updatedReel, + }, + }); + } catch (err) { + return res.status(500).json({ success: false, message: `${err}` }); + } +}; +//dislike reels +export const dislikeReels = async (req, res) => { + const { userId, reelId } = req.body; + + if (!userId || !reelId) { + return res + .status(400) + .json({ success: false, message: "invalid credientials" }); + } + + try { + const reel = await video.findById(reelId); + if (!reel) { + return res + .status(404) + .json({ success: false, message: "reel not found" }); + } + //check if like or not + const isdisLiked = reel.disLikes.includes(userId); + if (isdisLiked) { + //remove userid if already liked + reel.disLikes = reel.disLikes.filter((id) => id !== userId); + } else { + //add new like + reel.disLikes.push(userId); + } + + const updatedReel = await reel.save(); + return res.status(200).json({ + success: true, + data: { + reel: updatedReel, + }, + }); + } catch (err) { + return res.status(500).json({ success: false, message: `${err}` }); + } +}; diff --git a/controller/userauthcontroller.js b/controller/userauthcontroller.js new file mode 100644 index 0000000..129cb15 --- /dev/null +++ b/controller/userauthcontroller.js @@ -0,0 +1,281 @@ +import bcrypt from "bcryptjs"; +import dotenv from "dotenv"; +import jwt from "jsonwebtoken"; +import { ACCOUNT_VERIFICATION_HTML_TEMPLETE } from "../config/accont_verification_templete.js"; +import { PASSWORD_RESET_TEMPLATE } from "../config/reset_password_templete.js"; + +import transporter from "../config/nodemailer.js"; +import User from "../models/user.model.js"; +dotenv.config(); +//register new user +export const register = async (req, res) => { + const { username, email, password } = req.body; + const profileUrl = req.file ? req.file.buffer.toString("base64") : ""; + + if (!username || !email || !password) { + return res.status(400).json({ succss: false, massage: "missing details" }); + } + // const profilePic = req.file?.filename || ""; + try { + const isexistUser = await User.findOne({ email }); + if (isexistUser) { + return res + .status(400) + .json({ succss: false, massage: "user already exist" }); + } + //hash password + const salt = await bcrypt.genSalt(10); + const hasedPassword = await bcrypt.hash(password, salt); + //verify code + const verifyCode = Math.floor(10000 + Math.random() * 90000).toString(); + const codeExpireTime = Date.now() + 24 * 60 * 60 * 1000; + + //save user + const newUser = new User({ + username, + email, + password: hasedPassword, + profileUrl, + verifyCode, + codeExpireTime, + }); + + const createdUser = await newUser.save(); + //gen session tokens + + const newToken = await jwt.sign( + { id: createdUser._id }, + process.env.JWT_SECRET_KEY, + { expiresIn: "7d" } + ); + //send verification code + const mailReciver = { + from: process.env.APP_EMAIL, + to: createdUser.email, + subject: "Account Verification OTP", + html: ACCOUNT_VERIFICATION_HTML_TEMPLETE.replace("{{otp}}", verifyCode), + }; + //send email + await transporter.sendMail(mailReciver); + return res.status(200).json({ + succss: true, + newToken, + user: { + id: createdUser._id, + }, + }); + } catch (err) { + return res + .status(500) + .json({ succss: false, massage: `Internal server error` }); + } +}; +//verify account +export const verifyAccount = async (req, res) => { + const { userId, verifyCode } = req.body; + + if (!userId || !verifyCode) { + return res.status(400).json({ success: false, massage: "Missing Details" }); + } + + try { + const user = await User.findById(userId); + //when user not exist + if (!user) { + return res + .status(400) + .json({ success: false, massage: "User not found" }); + } + //when invalid otp + if (user.verifyCode == "" || user.verifyCode != verifyCode) { + return res.status(400).json({ success: false, massage: "Invalid OTP" }); + } + //if otp expired + if (user.codeExpireTime < Date.now()) { + return res + .status(408) + .json({ success: false, massage: "Request time out" }); + } + + //when all set + user.isVerified = true; + user.verifyCode = ""; + user.codeExpireTime = 0; + //save updated user + + await user.save(); + //welcome email + const mailReciver = { + from: process.env.APP_EMAIL, + to: user.email, + subject: "Welcome To DATE NET.", + text: `Welcome ${user.username} to Date Net forum.Your account has been verified succsussfuly.stay with us and explor more content`, + }; + //send email + await transporter.sendMail(mailReciver); + return res.status(200).json({ + success: true, + user: { + id: user._id, + username: user.username, + email: user.email, + profileUrl: user.profileUrl, + }, + }); + } catch (err) { + return res + .status(500) + .json({ success: false, massage: "Internal server error" }); + } +}; +//user login +export const login = async (req, res) => { + const { username, password } = req.body; + + if (!username || !password) { + return res + .status(400) + .json({ success: false, massage: "enter all details" }); + } + try { + const existUser = await User.findOne({ username }); + if (!existUser) { + return res + .status(400) + .json({ success: false, massage: " user not found" }); + } + //check password validation + const isValidPassword = await bcrypt.compare(password, existUser.password); + if (!isValidPassword) { + return res + .status(400) + .json({ success: false, massage: "invalid password" }); + } + //gen new token + const newToken = await jwt.sign( + { id: existUser._id }, + process.env.JWT_SECRET_KEY, + { expiresIn: "7d" } + ); + //response-succsuss + return res.status(200).json({ + success: true, + newToken, + user: { + id: existUser._id, + username: existUser.username, + email: existUser.email, + profileUrl: existUser.profileUrl, + }, + }); + } catch (err) { + return res + .status(500) + .json({ success: false, massage: "internal server error" }); + } +}; + +export const resetPasswordVerification = async (req, res) => { + const { email } = req.body; + + if (!email) { + return res + .status(400) + .json({ success: false, massage: "enter all details" }); + } + + try { + const existUser = await User.findOne({ email }); + if (!existUser) { + return res + .status(404) + .json({ success: false, massage: "User not found" }); + } + + //verify code + const verifyCode = Math.floor(10000 + Math.random() * 90000).toString(); + const codeExpireTime = Date.now() + 24 * 60 * 60 * 1000; + + existUser.verifyCode = verifyCode; + existUser.codeExpireTime = codeExpireTime; + // existUser.password = password; + //save with verificaton data + await existUser.save(); + //send verification code + const mailReciver = { + from: process.env.APP_EMAIL, + to: existUser.email, + subject: "password reset OTP", + html: PASSWORD_RESET_TEMPLATE.replace("{{otp}}", verifyCode), + }; + //send email + await transporter.sendMail(mailReciver); + return res.status(200).json({ + success: true, + user: { + id: email, + }, + }); + } catch (err) { + return res + .status(500) + .json({ success: true, massage: "internal server error" }); + } +}; + +export const resetPassword = async (req, res) => { + const { email, otp, password } = req.body; + + if (!email || !otp || !password) { + return res + .status(400) + .json({ success: false, massage: "enter all details" }); + } + + try { + const existUser = await User.findOne({ email }); + if (!existUser) { + return res + .status(404) + .json({ success: false, massage: "User not found" }); + } + + if (otp == "" || otp != existUser.verifyCode) { + return res.status(400).json({ success: false, massage: "Invalid OTP" }); + } + + if (existUser.codeExpireTime < Date.now()) { + return res + .status(408) + .json({ success: false, massage: "Request Time out" }); + } + //hash password + const salt = await bcrypt.genSalt(10); + const hasedPassword = await bcrypt.hash(password, salt); + //when all set + existUser.isVerified = true; + existUser.verifyCode = ""; + existUser.codeExpireTime = 0; + existUser.password = hasedPassword; + //save updated user + + await existUser.save(); + //welcome email + const mailReciver = { + from: process.env.APP_EMAIL, + to: existUser.email, + subject: "Password Reset Succsussfuly", + text: `${existUser.username} Your password is reset succsussfuly.Log in to your account using new creadientials`, + }; + //send email + await transporter.sendMail(mailReciver); + return res.status(200).json({ + success: true, + massage: "password reset succssfulty", + }); + } catch (err) { + return res + .status(500) + .json({ success: false, massage: "internal server error" }); + } +}; diff --git a/controller/usercontroller.js b/controller/usercontroller.js new file mode 100644 index 0000000..db7c2ca --- /dev/null +++ b/controller/usercontroller.js @@ -0,0 +1,125 @@ +import User from "../models/user.model.js"; +//get current user details +export const getCurrentUser = async (req, res) => { + const id = req.user.id; + + if (!id) { + return res + .status(401) + .json({ success: false, massage: "Invalid infomation" }); + } + try { + const existUser = await User.findById(id); + if (!existUser) { + return res.status(404).json({ succss: false, massage: "user not found" }); + } + return res.status(200).json({ + success: true, + massage: "data fetched succsussfuly", + user: existUser, + }); + } catch (err) { + return res + .status(500) + .json({ success: false, massage: "Internal server error" }); + } +}; +//get all user info : will update to all workers +export const getAllUser = async (req, res) => { + try { + const allUsers = await User.find({}); + + return res.status(200).json({ + success: true, + massage: "data fetched succsussfuly", + users: allUsers, + }); + } catch (err) { + console.log(`error from get all user ${err}`); + return res + .status(500) + .json({ success: false, massage: "Internal server error" }); + } +}; +//get user/s by username +export const getUserByUserName = async (req, res) => { + const { username } = req.params; + if (!username) { + return res.status(400).json({ success: false, massage: "empty parameter" }); + } + try { + // Create a case-insensitive regex pattern to find similar usernames + const regex = new RegExp(username, "i"); + //get similer users by alphbatically sort and limited to 10 + const user = await User.find({ username: { $regex: regex } }) + .sort({ username: 1 }) + .limit(10); + if (user === 0) { + return res + .status(404) + .json({ success: false, massage: "User not found" }); + } + return res.status(200).json({ + success: true, + massage: "data fetched succsussfuly", + users: user, + }); + } catch (err) { + return res + .status(500) + .json({ success: false, massage: "Internal server error" }); + } +}; +//follow and unfollow user +export const followOrUnfollowUser = async (req, res) => { + const guestid = req.params.guestid; + const userid = req.user.id; + + if (!userid || !guestid) { + return res.status(400).json({ success: false, massage: "empty parameter" }); + } + try { + const guestUser = await User.findById(guestid); + const currentUser = await User.findById(userid); + if (!guestUser || !currentUser) { + return res + .status(404) + .json({ success: false, massage: "user not found" }); + } + //check already following + if (guestUser.followers.includes(userid)) { + //unfollow user + //remove followres + guestUser.followers = guestUser.followers.filter((id) => id !== userid); + + await guestUser.save(); + //remove followings + currentUser.following = currentUser.following.filter( + (id) => id !== guestid + ); + + await currentUser.save(); + + return res.status(200).json({ + success: true, + massage: "user unfollow", + users: guestUser, + }); + } + //follow user + guestUser.followers.push(userid); + await guestUser.save(); + + currentUser.following.push(guestid); + await currentUser.save(); + return res.status(200).json({ + success: true, + massage: "user follow", + users: guestUser, + }); + } catch (err) { + return res + .status(500) + .json({ success: false, massage: "Internal server error" }); + } +}; diff --git a/demo.js b/demo.js new file mode 100644 index 0000000..80ee5f1 --- /dev/null +++ b/demo.js @@ -0,0 +1,240 @@ +// // server.js (Express.js with MongoDB and AWS S3) +// const express = require('express'); +// const mongoose = require('mongoose'); +// const cors = require('cors'); +// const AWS = require('aws-sdk'); +// const { v4: uuidv4 } = require('uuid'); +// const ffmpeg = require('fluent-ffmpeg'); +// const fs = require('fs'); +// const path = require('path'); + +// const app = express(); +// app.use(express.json()); +// app.use(cors()); + +// // MongoDB Connection (can be Atlas for even more scalability) +// const mongoURI = 'mongodb://localhost:27017/videoApp'; +// mongoose.connect(mongoURI); + +// // Configure AWS +// AWS.config.update({ +// accessKeyId: process.env.AWS_ACCESS_KEY_ID, +// secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, +// region: process.env.AWS_REGION || 'us-east-1' +// }); + +// const s3 = new AWS.S3(); +// const cloudfront = new AWS.CloudFront(); + +// // S3 bucket name +// const BUCKET_NAME = process.env.S3_BUCKET_NAME || 'your-video-bucket'; +// // CloudFront distribution domain +// const CLOUDFRONT_URL = process.env.CLOUDFRONT_URL || 'https://your-distribution.cloudfront.net'; + +// // Video Schema +// const videoSchema = new mongoose.Schema({ +// userId: { type: String, required: true }, +// videoKey: { type: String, required: true }, // S3 key +// thumbnailKey: { type: String }, // S3 key for thumbnail +// description: { type: String, required: true }, +// likesCount: { type: Number, default: 0 }, +// commentsCount: { type: Number, default: 0 }, +// sharesCount: { type: Number, default: 0 }, +// processed: { type: Boolean, default: false }, +// createdAt: { type: Date, default: Date.now } +// }); + +// const Video = mongoose.model('Video', videoSchema); + +// // Routes +// // Generate pre-signed URL for direct S3 upload +// app.post('/api/videos/get-upload-url', async (req, res) => { +// try { +// const { userId, fileType, fileName } = req.body; +// const key = `videos/${userId}/${uuidv4()}-${fileName}`; + +// const params = { +// Bucket: BUCKET_NAME, +// Key: key, +// ContentType: fileType, +// Expires: 300 // URL expires in 5 minutes +// }; + +// const uploadUrl = s3.getSignedUrl('putObject', params); + +// res.json({ +// uploadUrl, +// key +// }); +// } catch (error) { +// res.status(500).json({ message: 'Error generating upload URL', error: error.message }); +// } +// }); + +// // Save video metadata after upload +// app.post('/api/videos/metadata', async (req, res) => { +// try { +// const { userId, videoKey, description } = req.body; + +// // Generate a thumbnail key +// const thumbnailKey = videoKey.replace('videos/', 'thumbnails/').replace(/\.[^/.]+$/, '.jpg'); + +// // Create the video record in MongoDB +// const newVideo = new Video({ +// userId, +// videoKey, +// thumbnailKey, +// description +// }); + +// await newVideo.save(); + +// // Trigger thumbnail generation and video processing (async) +// generateThumbnail(videoKey, thumbnailKey, newVideo._id); + +// res.status(201).json({ +// message: 'Video metadata saved successfully', +// videoId: newVideo._id +// }); +// } catch (error) { +// res.status(500).json({ message: 'Error saving video metadata', error: error.message }); +// } +// }); + +// // Get videos for feed +// app.get('/api/videos', async (req, res) => { +// try { +// const page = parseInt(req.query.page) || 1; +// const limit = parseInt(req.query.limit) || 10; +// const skip = (page - 1) * limit; + +// // Only return processed videos (with thumbnails) +// const videos = await Video.find({ processed: true }) +// .sort({ createdAt: -1 }) +// .skip(skip) +// .limit(limit); + +// // Transform data to include CloudFront URLs +// const videoData = videos.map(video => ({ +// _id: video._id, +// userId: video.userId, +// videoUrl: `${CLOUDFRONT_URL}/${video.videoKey}`, +// thumbnailUrl: `${CLOUDFRONT_URL}/${video.thumbnailKey}`, +// videoKey: video.videoKey, +// description: video.description, +// likesCount: video.likesCount, +// commentsCount: video.commentsCount, +// sharesCount: video.sharesCount, +// createdAt: video.createdAt +// })); + +// res.json({ data: videoData }); +// } catch (error) { +// res.status(500).json({ message: 'Error fetching videos', error: error.message }); +// } +// }); + +// // Like/unlike video +// app.post('/api/videos/:id/like', async (req, res) => { +// try { +// const video = await Video.findById(req.params.id); +// if (!video) { +// return res.status(404).json({ message: 'Video not found' }); +// } + +// // In a real app, you'd check if user has already liked and toggle +// video.likesCount += 1; +// await video.save(); + +// res.json({ message: 'Like toggled successfully', likesCount: video.likesCount }); +// } catch (error) { +// res.status(500).json({ message: 'Error toggling like', error: error.message }); +// } +// }); + +// // Function to generate a thumbnail from video +// async function generateThumbnail(videoKey, thumbnailKey, videoId) { +// try { +// // Create temp directory if it doesn't exist +// const tempDir = path.join(__dirname, 'temp'); +// if (!fs.existsSync(tempDir)) { +// fs.mkdirSync(tempDir); +// } + +// // Download video from S3 to temp location +// const videoPath = path.join(tempDir, `video-${uuidv4()}.mp4`); +// const thumbnailPath = path.join(tempDir, `thumbnail-${uuidv4()}.jpg`); + +// const videoObject = await s3.getObject({ +// Bucket: BUCKET_NAME, +// Key: videoKey +// }).promise(); + +// fs.writeFileSync(videoPath, videoObject.Body); + +// // Use ffmpeg to generate thumbnail +// await new Promise((resolve, reject) => { +// ffmpeg(videoPath) +// .on('end', resolve) +// .on('error', reject) +// .screenshots({ +// timestamps: ['00:00:01.000'], +// filename: path.basename(thumbnailPath), +// folder: path.dirname(thumbnailPath), +// size: '320x240' +// }); +// }); + +// // Upload thumbnail to S3 +// await s3.putObject({ +// Bucket: BUCKET_NAME, +// Key: thumbnailKey, +// Body: fs.readFileSync(thumbnailPath), +// ContentType: 'image/jpeg' +// }).promise(); + +// // Update video record as processed +// await Video.findByIdAndUpdate(videoId, { processed: true }); + +// // Clean up temporary files +// fs.unlinkSync(videoPath); +// fs.unlinkSync(thumbnailPath); +// } catch (error) { +// console.error('Error generating thumbnail:', error); +// } +// } + +// // Start server +// const PORT = process.env.PORT || 3000; +// app.listen(PORT, () => { +// console.log(`Server running on port ${PORT}`); +// }); + +// // ----- AWS EC2 Deployment Guide ----- +// // 1. Launch an EC2 instance (t2.medium or better recommended for video processing) +// // 2. Set up security groups to allow HTTP/HTTPS traffic +// // 3. Install Node.js, MongoDB, and FFmpeg on the instance: +// // $ sudo apt update +// // $ sudo apt install -y nodejs npm mongodb ffmpeg +// // $ sudo systemctl enable mongodb +// // $ sudo systemctl start mongodb +// // 4. Set up PM2 for process management: +// // $ sudo npm install -g pm2 +// // 5. Clone your repo and install dependencies: +// // $ git clone your-repo-url +// // $ cd your-app +// // $ npm install +// // 6. Set environment variables: +// // $ export AWS_ACCESS_KEY_ID=your-access-key +// // $ export AWS_SECRET_ACCESS_KEY=your-secret-key +// // $ export AWS_REGION=your-region +// // $ export S3_BUCKET_NAME=your-bucket +// // $ export CLOUDFRONT_URL=your-distribution-url +// // 7. Start with PM2: +// // $ pm2 start server.js +// // $ pm2 startup +// // $ pm2 save +// // 8. Set up Nginx as a reverse proxy (optional) + + +// // --- Main App Entry Point --- diff --git a/jenkinsfile b/jenkinsfile new file mode 100644 index 0000000..8b07c0b --- /dev/null +++ b/jenkinsfile @@ -0,0 +1,37 @@ +pipeline { + agent any + + stages { + stage('SCM Checkout') { + steps { + retry(3) { + git branch: 'main', url: 'https://github.com/HGSChandeepa/test-node' + } + } + } + stage('Build Docker Image') { + steps { + bat 'docker build -t adomicarts/nodeapp-cuban:%BUILD_NUMBER% .' + } + } + stage('Login to Docker Hub') { + steps { + withCredentials([string(credentialsId: 'samin-docker', variable: 'samindocker')]) { + script { + bat "docker login -u adomicarts -p %samindocker%" + } + } + } + } + stage('Push Image') { + steps { + bat 'docker push adomicarts/nodeapp-cuban:%BUILD_NUMBER%' + } + } + } + post { + always { + bat 'docker logout' + } + } +} \ No newline at end of file diff --git a/middleware/auth.js b/middleware/auth.js new file mode 100644 index 0000000..93ee6c4 --- /dev/null +++ b/middleware/auth.js @@ -0,0 +1,32 @@ +import { response } from "express"; +import jwt from "jsonwebtoken"; +const jwtAuth = (req, res, next) => { + const token = req.header("Authorization"); + // const token = authHeader && authHeader.split(" ")[1]; + if (!token) { + return res + .status(401) + .json({ succss: false, massage: " authorization denied,Invalid user" }); + } + try { + const decodeToken = jwt.verify(token, process.env.JWT_SECRET_KEY); + console.log(decodeToken); + req.user = decodeToken; + next(); + } catch (err) { + console.error("Token verification error:", err.message); + + // Check if the error is due to token expiration + if (err.name === "jwt expired") { + return response + .status(401) + .json({ succss: false, massage: "Token has expired" }); + } + + // For other errors, respond with a generic message + return res + .status(400) + .json({ succss: false, massage: "Token is not valid" }); + } +}; +export default jwtAuth; diff --git a/middleware/uploads.js b/middleware/uploads.js new file mode 100644 index 0000000..37e780f --- /dev/null +++ b/middleware/uploads.js @@ -0,0 +1,16 @@ +// import multer from "multer"; +// import path from "path"; + +// const storage = multer.diskStorage({ +// destination: (req, file, cb) => { +// cb(null, "uploads/"); // Make sure this folder exists +// }, +// filename: (req, file, cb) => { +// cb(null, Date.now() + path.extname(file.originalname)); +// }, +// }); + +// const upload = multer({ storage }); +import multer from "multer"; +const upload = multer({ storage: multer.memoryStorage() });//store in memory +export default upload; diff --git a/models/user.model.js b/models/user.model.js new file mode 100644 index 0000000..fd6232a --- /dev/null +++ b/models/user.model.js @@ -0,0 +1,81 @@ +import mongoose from "mongoose"; +//user model +const UserSchema = new mongoose.Schema( + { + profileUrl: { + type: String, + + trim: true, + }, + username: { + type: String, + required: true, + trim: true, + unique: true, + }, + email: { + type: String, + required: true, + trim: true, + unique: true, + }, + password: { + type: String, + required: true, + trim: true, + unique: true, + }, + isCreator: { + type: Boolean, + default: false, + }, + serviceDiscription: { + type: String, + default: "", + trim: true, + }, + bio: { + type: String, + default: "", + trim: true, + }, + + followers: { + type: [String], + default: [], + }, + following: { + type: [String], + default: [], + }, + + contact: { + type: Number, + default: 0, + trim: true, + }, + referenceUrl: { + type: String, + default: "", + trim: true, + }, + isVerified: { + type: Boolean, + default: false, + }, + verifyCode: { + type: String, + }, + codeExpireTime: { + type: Number, + default: 0, + }, + }, + + { + timestamps: true, //cratedAT and updatedAt + } +); + +const User = mongoose.model("User", UserSchema); +export default User; diff --git a/models/video.model.js b/models/video.model.js new file mode 100644 index 0000000..035284c --- /dev/null +++ b/models/video.model.js @@ -0,0 +1,53 @@ +import mongoose from "mongoose"; + +const videoSchema = new mongoose.Schema( + { + userId: { + type: String, + required: true, + trim: true, + }, + title: { + type: String, + default: "", + trim: true, + }, + tags: { + type: [String], + + default: [], + }, + url: { + type: String, + required: true, + trim: true, + }, + likes: { + type: [String], + + default: [], + }, + disLikes: { + type: [String], + + default: [], + }, + comments: { + type: [String], + + default: [], + }, + processed: { type: Boolean, default: false }, + weblink: { + type: String, + default: "", + trim: true, + }, + }, + { + timestamps: true, //cratedAT and updatedAt + } +); + +const video = mongoose.model("video", videoSchema); +export default video; diff --git a/package-lock.json b/package-lock.json index c61cb44..ba30383 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,14 +9,20 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "aws-sdk": "^2.1692.0", "axios": "^1.8.4", "bcryptjs": "^3.0.2", "cors": "^2.8.5", "dotenv": "^16.4.7", "express": "^5.1.0", + "fs": "^0.0.1-security", "jsonwebtoken": "^9.0.2", "mongoose": "^8.13.2", - "nodemon": "^3.1.9" + "multer": "^1.4.5-lts.2", + "nodemailer": "^6.10.0", + "nodemon": "^3.1.9", + "path": "^0.12.7", + "uuid": "^11.1.0" } }, "node_modules/@mongodb-js/saslprep": { @@ -64,11 +70,59 @@ "node": ">= 8" } }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sdk": { + "version": "2.1692.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1692.0.tgz", + "integrity": "sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw==", + "hasInstallScript": true, + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/axios": { "version": "1.8.4", "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", @@ -84,6 +138,25 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/bcryptjs": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", @@ -150,11 +223,37 @@ "node": ">=16.20.1" } }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -163,6 +262,23 @@ "node": ">= 0.8" } }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -229,6 +345,20 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, "node_modules/content-disposition": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", @@ -264,6 +394,11 @@ "node": ">=6.6.0" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -292,6 +427,22 @@ } } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -407,6 +558,14 @@ "node": ">= 0.6" } }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/express": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", @@ -494,6 +653,20 @@ } } }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/form-data": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", @@ -543,6 +716,11 @@ "node": ">= 0.8" } }, + "node_modules/fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -629,6 +807,17 @@ "node": ">=4" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -691,6 +880,11 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -709,6 +903,21 @@ "node": ">= 0.10" } }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -720,6 +929,17 @@ "node": ">=8" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -728,6 +948,23 @@ "node": ">=0.10.0" } }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -752,6 +989,50 @@ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -897,6 +1178,25 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/mongodb": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.15.0.tgz", @@ -996,6 +1296,62 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/multer": { + "version": "1.4.5-lts.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz", + "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -1004,6 +1360,14 @@ "node": ">= 0.6" } }, + "node_modules/nodemailer": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.0.tgz", + "integrity": "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/nodemon": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", @@ -1085,6 +1449,15 @@ "node": ">= 0.8" } }, + "node_modules/path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, "node_modules/path-to-regexp": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", @@ -1093,6 +1466,19 @@ "node": ">=16" } }, + "node_modules/path/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/path/node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dependencies": { + "inherits": "2.0.3" + } + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -1104,6 +1490,27 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1148,6 +1555,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -1170,6 +1586,25 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -1215,11 +1650,32 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, "node_modules/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", @@ -1266,6 +1722,22 @@ "node": ">= 18" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -1371,6 +1843,27 @@ "node": ">= 0.8" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -1433,6 +1926,11 @@ "node": ">= 0.6" } }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -1446,6 +1944,49 @@ "node": ">= 0.8" } }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -1474,10 +2015,58 @@ "node": ">=18" } }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } } } } diff --git a/package.json b/package.json index 78f9078..fd162b1 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,19 @@ "author": "", "license": "ISC", "dependencies": { + "aws-sdk": "^2.1692.0", "axios": "^1.8.4", "bcryptjs": "^3.0.2", "cors": "^2.8.5", "dotenv": "^16.4.7", "express": "^5.1.0", + "fs": "^0.0.1-security", "jsonwebtoken": "^9.0.2", "mongoose": "^8.13.2", - "nodemon": "^3.1.9" + "multer": "^1.4.5-lts.2", + "nodemailer": "^6.10.0", + "nodemon": "^3.1.9", + "path": "^0.12.7", + "uuid": "^11.1.0" } } diff --git a/readme b/readme new file mode 100644 index 0000000..c137778 --- /dev/null +++ b/readme @@ -0,0 +1,21 @@ +{ + "Version": "2008-10-17", + "Id": "PolicyForCloudFrontPrivateContent", + "Statement": [ + { + "Sid": "AllowCloudFrontServicePrincipal", + "Effect": "Allow", + "Principal": { + "Service": "cloudfront.amazonaws.com" + }, + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::datenet-video-reels/*", + "Condition": { + "StringEquals": { + "AWS:SourceArn": "arn:aws:cloudfront::954976291528:distribution/E273U9FNKDYIC4" + } + } + } + ] + } + diff --git a/routes/authroutes.js b/routes/authroutes.js new file mode 100644 index 0000000..3eead0d --- /dev/null +++ b/routes/authroutes.js @@ -0,0 +1,18 @@ +import express from "express"; +import { + login, + register, + resetPassword, + resetPasswordVerification, + verifyAccount, +} from "../controller/userauthcontroller.js"; +import upload from "../middleware/uploads.js"; + +const authRoute = express.Router(); +authRoute.post("/register", upload.single("profileUrl"), register); +authRoute.post("/login", login); +authRoute.post("/verify", verifyAccount); +authRoute.post("/user-verification", resetPasswordVerification); +authRoute.post("/reset-password", resetPassword); + +export default authRoute; diff --git a/routes/resourceroute.js b/routes/resourceroute.js new file mode 100644 index 0000000..bb0e0a5 --- /dev/null +++ b/routes/resourceroute.js @@ -0,0 +1,18 @@ +import express from "express"; +import { + dislikeReels, + fetchVideoData, + getPreSingedUrl, + likeReels, + saveMetaData, +} from "../controller/resourcecontroller.js"; +const resourceRouter = express.Router(); +//upload file +resourceRouter.post("/get-pre-signed-url", getPreSingedUrl); +resourceRouter.post("/save-metadata", saveMetaData); +resourceRouter.get("/fetch-videos", fetchVideoData); +resourceRouter.post("/like-videos", likeReels); +resourceRouter.post("/dislike-videos", dislikeReels); + +//render file +export default resourceRouter; diff --git a/routes/userroutes.js b/routes/userroutes.js new file mode 100644 index 0000000..30254d4 --- /dev/null +++ b/routes/userroutes.js @@ -0,0 +1,16 @@ +import express from "express"; +import { + followOrUnfollowUser, + getAllUser, + getCurrentUser, + getUserByUserName, +} from "../controller/usercontroller.js"; +import middleware from "../middleware/auth.js"; +const userRouter = express.Router(); + +userRouter.get("/getalluser", middleware, getAllUser); +userRouter.get("/getcurrentuser", middleware, getCurrentUser); +userRouter.get("/getuserbyusername/:username", middleware, getUserByUserName); +userRouter.post("/followuser/:guestid", middleware, followOrUnfollowUser); + +export default userRouter; diff --git a/server.js b/server.js index 00170ea..b1911ba 100644 --- a/server.js +++ b/server.js @@ -1,17 +1,28 @@ import cors from "cors"; import dotenv from "dotenv"; import express from "express"; -import { connectDB } from "./db/database.js"; +import { connectDB } from "./config/db/database.js"; +import authRoute from "./routes/authroutes.js"; +import userRouter from "./routes/userroutes.js"; +import resourceRouter from "./routes/resourceroute.js"; + dotenv.config(); //app const app = express(); const PORT = process.env.PORT || 5000; + + + +//s3 bucket +const bucketName = process.env.AWS_BUCKET_NAME; //midddleware app.use(express.json()); app.use(cors()); - +app.use("/api/auth", authRoute); +app.use("/api/user", userRouter); +app.use("/api/resources", resourceRouter); app.get("/", (req, res) => { res.send("server is ready to use"); });