Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 2 additions & 15 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,15 +1,2 @@
node_modules
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

build

npm-debug.log*
yarn-debug.log*
yarn-error.log*

package-lock.json
# Node modules
backend/node_modules/
1 change: 0 additions & 1 deletion Procfile

This file was deleted.

13 changes: 0 additions & 13 deletions README.md

This file was deleted.

6 changes: 6 additions & 0 deletions backend/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
PORT=5000
#MONGO_URI=mongodb+srv://root:[email protected]/technigo-forum

MONGO_URI=mongodb://127.0.0.1:27017/technigo-forum
## mongodb+srv://root:[email protected]/?retryWrites=true&w=majority&appName=Cluster0
JWT_SECRET=123456789
36 changes: 36 additions & 0 deletions backend/controllers/authControllers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import User from "../models/User.js";

export const signup = async (req, res) => {
try {
const { email, password } = req.body;
if (!email || !password) return res.status(400).json({ error: "Email & password required" });

const exists = await User.findOne({ email });
if (exists) return res.status(400).json({ error: "Email already registered" });

const hashed = await bcrypt.hash(password, 10);
const user = await User.create({ email, password: hashed });

res.json({ id: user._id, email: user.email, createdAt: user.createdAt });
} catch (err) {
res.status(500).json({ error: err.message });
}
};

export const login = async (req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user) return res.status(400).json({ error: "User not found" });

const ok = await bcrypt.compare(password, user.password);
if (!ok) return res.status(400).json({ error: "Invalid credentials" });

const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: "1d" });
res.json({ token, email: user.email });
} catch (err) {
res.status(500).json({ error: err.message });
}
};
31 changes: 31 additions & 0 deletions backend/controllers/commentController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Comment from "../models/Comment.js";

export const getComments = async (req, res) => {
try {
const { postId } = req.params;
const comments = await Comment.find({ post: postId })
.populate("author", "email")
.sort({ createdAt: -1 });
res.json(comments);
} catch (err) {
res.status(500).json({ error: err.message });
}
};

export const createComment = async (req, res) => {
try {
const { postId } = req.params;
const { text } = req.body;
if (!text) return res.status(400).json({ error: "Comment text required" });

const comment = await Comment.create({
text,
post: postId,
author: req.user.id,
});

res.json(await comment.populate("author", "email"));
} catch (err) {
res.status(500).json({ error: err.message });
}
};
28 changes: 28 additions & 0 deletions backend/controllers/postController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Post from "../models/Post.js";

export const getPosts = async (_req, res) => {
const posts = await Post.find().sort({ createdAt: -1 }).populate("author", "email");
res.json(posts);
};

export const createPost = async (req, res) => {
try {
const { title, content } = req.body;
if (!title || !content) return res.status(400).json({ error: "Title & content required" });

const post = await Post.create({ title, content, author: req.user.id });
res.json(post);
} catch (err) {
res.status(500).json({ error: err.message });
}
};

export const getPostById = async (req, res) => {
try {
const post = await Post.findById(req.params.id).populate("author", "email");
if (!post) return res.status(404).json({ error: "Post not found" });
res.json(post);
} catch (err) {
res.status(500).json({ error: err.message });
}
};
16 changes: 16 additions & 0 deletions backend/middleware/authMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import jwt from "jsonwebtoken";

export const authMiddleware = (req, res, next) => {
const header = req.headers.authorization || "";
const parts = header.split(" ");
if (parts[0] !== "Bearer" || !parts[1]) {
return res.status(401).json({ error: "No or bad token" });
}
try {
const decoded = jwt.verify(parts[1], process.env.JWT_SECRET);
req.user = decoded; // { id: ... }
next();
} catch {
res.status(401).json({ error: "Token invalid" });
}
};
13 changes: 13 additions & 0 deletions backend/models/Comment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import mongoose from "mongoose";

const commentSchema = new mongoose.Schema(
{
text: { type: String, required: true },
image: { type: String }, // optional image upload
author: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true },
post: { type: mongoose.Schema.Types.ObjectId, ref: "Post", required: true },
},
{ timestamps: true }
);

export default mongoose.model("Comment", commentSchema);
12 changes: 12 additions & 0 deletions backend/models/Post.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import mongoose from "mongoose";

const postSchema = new mongoose.Schema(
{
title: { type: String, required: true, trim: true },
content: { type: String, required: true },
author: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true }
},
{ timestamps: true }
);

export default mongoose.model("Post", postSchema);
11 changes: 11 additions & 0 deletions backend/models/User.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import mongoose from "mongoose";

const userSchema = new mongoose.Schema(
{
email: { type: String, required: true, unique: true, lowercase: true, trim: true },
password: { type: String, required: true }
},
{ timestamps: true }
);

export default mongoose.model("User", userSchema);
Loading