lol
This commit is contained in:
parent
b8b84a8902
commit
5892c00ae7
2
app.js
2
app.js
@ -4,6 +4,7 @@ const userRoutes = require('./src/routes/v1/userRoutes');
|
||||
const loginRoutes = require('./src/routes/v1/authRoutes');
|
||||
const carsRoutes = require('./src/routes/v1/carsRoutes');
|
||||
const collectionRoutes = require('./src/routes/v1/collectionRoutes');
|
||||
const postRoutes = require('./src/routes/v1/postsRoutes');
|
||||
const path = require('path');
|
||||
|
||||
const app = express();
|
||||
@ -27,6 +28,7 @@ app.use('/api/v1/users', userRoutes);
|
||||
app.use('/api/v1/login', loginRoutes);
|
||||
app.use('/api/v1/cars', carsRoutes);
|
||||
app.use('/api/v1/collections', collectionRoutes);
|
||||
app.use('/api/v1/posts', postRoutes);
|
||||
|
||||
app.use((req, res, next) => {
|
||||
res.status(404).json({ message: 'Route not found' });
|
||||
|
||||
@ -5,27 +5,23 @@ const user = require('../models/user');
|
||||
|
||||
exports.createCar = async (req, res) => {
|
||||
try {
|
||||
// 1) Determine imagePath:
|
||||
let imagePath;
|
||||
|
||||
if (req.file) {
|
||||
// Native flow (Android/iOS) → Multerput the file under /uploads/cars/<filename>
|
||||
imagePath = `/uploads/cars/${req.file.filename}`;
|
||||
} else if (req.body.image) {
|
||||
// Web flow → Client sent a JSON { image: "<uri>" }
|
||||
// We trust that URI (could be a data URL or blob URL) and save it directly
|
||||
imagePath = req.body.image;
|
||||
} else {
|
||||
return res.status(400).json({ message: "Image file (or image URL) is required." });
|
||||
// 1) Multer must have put the file under req.file
|
||||
if (!req.file) {
|
||||
return res.status(400).json({ message: "Image file is required." });
|
||||
}
|
||||
|
||||
// 2) Extract other fields (make, model, year, modifications)
|
||||
// 2) Validate text fields
|
||||
const { make, model, year, modifications } = req.body;
|
||||
if (!make || !model || !year || !modifications) {
|
||||
return res.status(400).json({ message: "All fields are required." });
|
||||
return res
|
||||
.status(400)
|
||||
.json({ message: "make, model, year, and modifications are required." });
|
||||
}
|
||||
|
||||
// 3) Create the Car document
|
||||
// 3) Build image path (leading slash because /uploads is served statically)
|
||||
const imagePath = `/uploads/cars/${req.file.filename}`;
|
||||
|
||||
// 4) Create the Car document
|
||||
const newCar = await Car.create({
|
||||
image: imagePath,
|
||||
make: make.trim(),
|
||||
@ -34,13 +30,15 @@ exports.createCar = async (req, res) => {
|
||||
modifications: modifications.trim(),
|
||||
});
|
||||
|
||||
// 4) Find the user ID from req.user
|
||||
// 5) Find the logged-in user's ID
|
||||
const userId = req.user.userId || req.user.id || req.user._id;
|
||||
if (!userId) {
|
||||
return res.status(400).json({ message: "User ID not found in token payload." });
|
||||
return res
|
||||
.status(400)
|
||||
.json({ message: "User ID not found in token payload." });
|
||||
}
|
||||
|
||||
// 5) Find or create the user’s Collection
|
||||
// 6) Find or create that user’s Collection
|
||||
let userCollection = await Collection.findOne({ user_id: userId });
|
||||
if (!userCollection) {
|
||||
userCollection = await Collection.create({
|
||||
@ -52,7 +50,16 @@ exports.createCar = async (req, res) => {
|
||||
await userCollection.save();
|
||||
}
|
||||
|
||||
// 6) Return success
|
||||
let user = await user.findById(userId);
|
||||
if (!user) {
|
||||
return res.status(404).json({ message: "User not found" });
|
||||
}
|
||||
|
||||
// update number of cars in the collection
|
||||
user.number_of_cars = userCollection.cars.length;
|
||||
await user.save();
|
||||
|
||||
// 7) Return success
|
||||
return res.status(201).json({
|
||||
message: "Car added successfully",
|
||||
car: newCar,
|
||||
|
||||
136
src/controllers/postsController.js
Normal file
136
src/controllers/postsController.js
Normal file
@ -0,0 +1,136 @@
|
||||
const Post = require('../models/post');
|
||||
const User = require('../models/user');
|
||||
|
||||
exports.createPost = async (req, res) => {
|
||||
try {
|
||||
if (!req.file) {
|
||||
return res.status(400).json({ message: "Image file is required." });
|
||||
}
|
||||
|
||||
// 1. Grab any text fields you sent in the body
|
||||
// (e.g. title, content, tags—whatever your schema expects)
|
||||
const { title, content } = req.body;
|
||||
|
||||
// 2. Ensure the upload succeeded
|
||||
|
||||
// 3. Build a URL/path for where the image lives
|
||||
// Using the same path logic as in your multer storage
|
||||
// E.g. if you serve /uploads as static:
|
||||
// app.use("/uploads", express.static(path.join(__dirname, "../uploads")));
|
||||
const imageUrl = `/uploads/posts/${req.file.filename}`;
|
||||
|
||||
// 4. Grab the authenticated user ID that your authMiddleware set
|
||||
const userId = req.user.userId || req.user.id || req.user._id;
|
||||
if (!userId) {
|
||||
return res
|
||||
.status(401)
|
||||
.json({ message: "User not authenticated." });
|
||||
}
|
||||
|
||||
// 5. Create and save the post document
|
||||
const newPost = new Post({
|
||||
user_id: userId,
|
||||
content,
|
||||
image: imageUrl,
|
||||
});
|
||||
await newPost.save();
|
||||
|
||||
// 6. Return the newly created post
|
||||
return res.status(201).json(newPost);
|
||||
} catch (err) {
|
||||
console.error("Error in createPost:", err);
|
||||
return res.status(500).json({
|
||||
message: "Server error creating post",
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.getPosts = async (req, res) => {
|
||||
try {
|
||||
// 1) Get userId from req.user (set by authMiddleware)
|
||||
const userId = req.user.userId || req.user.id || req.user._id;
|
||||
if (!userId) {
|
||||
return res.status(401).json({ message: "User not authenticated." });
|
||||
}
|
||||
|
||||
const user = await User.findById(userId).select("username");
|
||||
|
||||
console.log("Fetching posts for user ID:", userId);
|
||||
// 2) Fetch that user's posts, populate author info, sort newest first
|
||||
const posts = await Post.find({ user_id: userId }).sort({ timestamp: -1 })
|
||||
|
||||
console.log("Retrieved posts:", posts);
|
||||
|
||||
if (!posts || posts.length === 0) {
|
||||
return res.status(404).json({ message: "No posts found." });
|
||||
}
|
||||
|
||||
// 3) Build full URL for each image
|
||||
const host = req.get("host");
|
||||
const protocol = req.protocol;
|
||||
const postsWithFullUrl = posts.map(post => {
|
||||
// post.image is something like "/uploads/posts/<filename>"
|
||||
const fullImageUrl = `${protocol}://${host}${post.image}`;
|
||||
|
||||
return {
|
||||
_id: post._id,
|
||||
content: post.content,
|
||||
image: fullImageUrl,
|
||||
createdAt: post.timestamp,
|
||||
username: user,
|
||||
};
|
||||
});
|
||||
|
||||
// 4) Send back the array
|
||||
return res.status(200).json(postsWithFullUrl);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error retrieving posts:", error);
|
||||
return res.status(500).json({
|
||||
message: "Server error while retrieving posts",
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.getLatestPosts = async (req, res) => {
|
||||
try {
|
||||
// 1) Get the latest 10 posts, sorted by createdAt descending
|
||||
const posts = await Post.find()
|
||||
.sort({ timestamp: -1 })
|
||||
.limit(10)
|
||||
.populate("user_id", "username")
|
||||
|
||||
if (!posts || posts.length === 0) {
|
||||
return res.status(404).json({ message: "No posts found." });
|
||||
}
|
||||
|
||||
console.log("Retrieved latest posts:", posts);
|
||||
|
||||
// 2) Build full URL for each image
|
||||
const host = req.get("host");
|
||||
const protocol = req.protocol;
|
||||
const postsWithFullUrl = posts.map(post => {
|
||||
const fullImageUrl = `${protocol}://${host}${post.image}`;
|
||||
|
||||
return {
|
||||
content: post.content,
|
||||
image: fullImageUrl,
|
||||
createdAt: post.timestamp,
|
||||
username: post.user_id.username,
|
||||
profile_pic: post.user_id.profile_pic,
|
||||
};
|
||||
});
|
||||
|
||||
// 3) Send back the array
|
||||
return res.status(200).json(postsWithFullUrl);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error retrieving latest posts:", error);
|
||||
return res.status(500).json({
|
||||
message: "Server error while retrieving latest posts",
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
26
src/models/post.js
Normal file
26
src/models/post.js
Normal file
@ -0,0 +1,26 @@
|
||||
const { Schema, model } = require('mongoose');
|
||||
|
||||
const postSchema = new Schema(
|
||||
{
|
||||
user_id: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'User',
|
||||
required: true
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
maxlength: [500, 'Post content cannot exceed 500 characters']
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
timestamp: {
|
||||
type: Date,
|
||||
default: Date.now
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = model('Post', postSchema, 'posts');
|
||||
@ -50,9 +50,6 @@ const userSchema = new Schema(
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
garage: {
|
||||
type: String,
|
||||
},
|
||||
posts: {
|
||||
type: String,
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ const authMiddleware = require('../../middleware/authMiddleware');
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
// Ensure this directory exists on disk: "./uploads/cars"
|
||||
cb(null, path.join(__dirname, "../../../uploads/cars"));
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
@ -14,11 +15,12 @@ const storage = multer.diskStorage({
|
||||
if (file.mimetype === "image/png") ext = ".png";
|
||||
else if (file.mimetype === "image/jpeg") ext = ".jpg";
|
||||
|
||||
const uniqueName = Date.now() + ext;
|
||||
cb(null, uniqueName);
|
||||
// Use a timestamp as filename: e.g. "1627890123456.png"
|
||||
cb(null, `${Date.now()}${ext}`);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const allowedMimeTypes = new Set(["image/jpeg", "image/png", "image/jpg"]);
|
||||
|
||||
const upload = multer({
|
||||
@ -32,7 +34,6 @@ const upload = multer({
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
router.post('/addCar', authMiddleware, upload.single("image"), createCar);
|
||||
|
||||
router.get('/getCollection', authMiddleware, getCollection);
|
||||
|
||||
43
src/routes/v1/postsRoutes.js
Normal file
43
src/routes/v1/postsRoutes.js
Normal file
@ -0,0 +1,43 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { createPost, getPosts, getLatestPosts } = require('../../controllers/postsController');
|
||||
const multer = require("multer");
|
||||
const path = require("path");
|
||||
const authMiddleware = require('../../middleware/authMiddleware');
|
||||
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
// Ensure this directory exists on disk: "./uploads/posts"
|
||||
cb(null, path.join(__dirname, "../../../uploads/posts"));
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
let ext = ".jpg";
|
||||
if (file.mimetype === "image/png") ext = ".png";
|
||||
else if (file.mimetype === "image/jpeg") ext = ".jpg";
|
||||
|
||||
cb(null, `${Date.now()}${ext}`);
|
||||
},
|
||||
});
|
||||
|
||||
const allowedMimeTypes = new Set(["image/jpeg", "image/png", "image/jpg"]);
|
||||
|
||||
const upload = multer({
|
||||
storage,
|
||||
limits: { fileSize: 5 * 1024 * 1024 },
|
||||
fileFilter: (req, file, cb) => {
|
||||
if (!allowedMimeTypes.has(file.mimetype)) {
|
||||
return cb(new Error("Only JPG/JPEG/PNG images are allowed"), false);
|
||||
}
|
||||
cb(null, true);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
router.post('/createPost', authMiddleware, upload.single("image"), createPost);
|
||||
|
||||
router.get('/getPosts', authMiddleware, getPosts);
|
||||
|
||||
router.get('/getLatestPosts', getLatestPosts);
|
||||
|
||||
module.exports = router;
|
||||
BIN
uploads/cars/1749242596413.jpg
Normal file
BIN
uploads/cars/1749242596413.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 175 KiB |
BIN
uploads/posts/1749279281769.jpg
Normal file
BIN
uploads/posts/1749279281769.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 454 KiB |
BIN
uploads/posts/1749279310017.jpg
Normal file
BIN
uploads/posts/1749279310017.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 454 KiB |
BIN
uploads/posts/1749279365619.jpg
Normal file
BIN
uploads/posts/1749279365619.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 454 KiB |
BIN
uploads/posts/1749279458888.jpg
Normal file
BIN
uploads/posts/1749279458888.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 454 KiB |
BIN
uploads/posts/1749282223166.jpg
Normal file
BIN
uploads/posts/1749282223166.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 218 KiB |
Loading…
x
Reference in New Issue
Block a user