From 6ab79a7812e1329adcf6434857486de1aeedf7ee Mon Sep 17 00:00:00 2001
From: Wendy Gardiel <34959525+whend12@users.noreply.github.com>
Date: Wed, 9 Apr 2025 14:29:37 +0700
Subject: [PATCH] BE notfix

---
 .gitignore                    |  2 ++
 controllers/blogController.js | 52 ++++++++++++++++++++++++++++++-----
 index.js                      |  5 ++++
 models/blogModel.js           |  5 ++++
 package-lock.json             | 23 ++++++++++++++++
 package.json                  |  1 +
 routes/blogRoutes.js          |  8 ++++--
 user.rest                     |  9 +++---
 8 files changed, 90 insertions(+), 15 deletions(-)

diff --git a/.gitignore b/.gitignore
index 5871fca..be139a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -115,3 +115,5 @@ dist
 .yarn/build-state.yml
 .yarn/install-state.gz
 .pnp.*
+
+uploads/
\ No newline at end of file
diff --git a/controllers/blogController.js b/controllers/blogController.js
index b2e94e0..6f00a17 100644
--- a/controllers/blogController.js
+++ b/controllers/blogController.js
@@ -26,20 +26,35 @@ export const getBlogById = async (req, res) => {
   }
 };
 
+// Get blog by slug
+export const getBlogBySlug = async (req, res) => {
+  try {
+    const blog = await blogModel.findOne({
+      where: { slug: req.params.slug },
+      include: [{ model: blogImage, as: "images" }],
+    });
+
+    if (!blog) return res.status(404).json({ message: "Blog not found" });
+
+    res.json(blog);
+  } catch (error) {
+    res.status(500).json({ message: error.message });
+  }
+};
+
 // Create a new blog
 export const createBlog = async (req, res) => {
   try {
     const { title, description } = req.body;
 
-    // Pastikan ada file yang diunggah
     if (!req.files || req.files.length === 0) {
       return res.status(400).json({ message: "Minimal 1 gambar diperlukan!" });
     }
 
-    // Simpan data blog
-    const blog = await blogModel.create({ title, description });
+    const slug = generateSlug(title); // 🔥 generate slug di sini
+
+    const blog = await blogModel.create({ title, description, slug });
 
-    // Simpan gambar ke database
     const imagePaths = req.files.map((file) => ({
       blogId: blog.id,
       imageUrl: `/uploads/${file.filename}`,
@@ -47,9 +62,8 @@ export const createBlog = async (req, res) => {
 
     await blogImage.bulkCreate(imagePaths);
 
-    // Ambil data blog beserta gambar setelah disimpan
     const newBlog = await blogModel.findByPk(blog.id, {
-      include: [{ model: blogImage, as: "images" }], // Pastikan alias sesuai
+      include: [{ model: blogImage, as: "images" }],
     });
 
     res.status(201).json({
@@ -61,12 +75,36 @@ export const createBlog = async (req, res) => {
   }
 };
 
+const generateSlug = (title) => {
+  return title
+    .toLowerCase()
+    .replace(/\s+/g, "-")
+    .replace(/[^\w-]+/g, "");
+};
+
 // Update a blog
 export const updateBlog = async (req, res) => {
   try {
     const blog = await blogModel.findByPk(req.params.id);
     if (!blog) return res.status(404).json({ message: "Blog not found" });
-    await blog.update(req.body);
+
+    const { title, description, slug } = req.body;
+
+    // Tentukan slug baru (jika ada title baru dan tidak ada slug manual)
+    let updatedSlug = blog.slug; // default: slug lama
+    if (title && !slug) {
+      updatedSlug = generateSlug(title);
+    } else if (slug) {
+      updatedSlug = slug;
+    }
+
+    // Update data
+    await blog.update({
+      title: title ?? blog.title,
+      description: description ?? blog.description,
+      slug: updatedSlug,
+    });
+
     res.json(blog);
   } catch (error) {
     res.status(500).json({ message: error.message });
diff --git a/index.js b/index.js
index f7cab93..f2eb7f4 100644
--- a/index.js
+++ b/index.js
@@ -3,11 +3,14 @@ import db from "./config/database.js";
 import dotenv from "dotenv";
 import router from "./routes/index.js"; // Hanya import 1 router
 import cors from "cors";
+import cookieParser from "cookie-parser";
+import path from "path";
 
 const app = express();
 dotenv.config();
 
 const connectToDatabase = async () => {
+  // await db.sync({ force: true });
   try {
     await db.authenticate();
     console.log("Database connected...");
@@ -18,8 +21,10 @@ const connectToDatabase = async () => {
 
 connectToDatabase();
 
+app.use(cookieParser());
 app.use(cors());
 app.use(express.json());
 app.use(router);
+app.use("/uploads", express.static(path.join(process.cwd(), "uploads")));
 
 app.listen(5000, () => console.log("server running at port 5000"));
diff --git a/models/blogModel.js b/models/blogModel.js
index d389d9a..36c1b82 100644
--- a/models/blogModel.js
+++ b/models/blogModel.js
@@ -13,6 +13,11 @@ const Blog = db.define("blog", {
     type: DataTypes.TEXT,
     allowNull: false,
   },
+  slug: {
+    type: DataTypes.STRING,
+    allowNull: false,
+    unique: true,
+  },
 });
 
 // Definisi relasi dengan alias 'images'
diff --git a/package-lock.json b/package-lock.json
index 95b0965..a1f0b12 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
       "license": "ISC",
       "dependencies": {
         "bcrypt": "^5.1.1",
+        "cookie-parser": "^1.4.7",
         "cors": "^2.8.5",
         "dotenv": "^16.4.7",
         "express": "^4.21.2",
@@ -455,6 +456,28 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/cookie-parser": {
+      "version": "1.4.7",
+      "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
+      "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
+      "license": "MIT",
+      "dependencies": {
+        "cookie": "0.7.2",
+        "cookie-signature": "1.0.6"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/cookie-parser/node_modules/cookie": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+      "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/cookie-signature": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
diff --git a/package.json b/package.json
index 0019ad3..b805649 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
   },
   "dependencies": {
     "bcrypt": "^5.1.1",
+    "cookie-parser": "^1.4.7",
     "cors": "^2.8.5",
     "dotenv": "^16.4.7",
     "express": "^4.21.2",
diff --git a/routes/blogRoutes.js b/routes/blogRoutes.js
index 331ee7e..8aa2fdc 100644
--- a/routes/blogRoutes.js
+++ b/routes/blogRoutes.js
@@ -2,6 +2,7 @@ import express from "express";
 import {
   getAllBlogs,
   getBlogById,
+  getBlogBySlug,
   createBlog,
   updateBlog,
   deleteBlog,
@@ -13,8 +14,9 @@ const router = express.Router();
 
 router.get("/blog", getAllBlogs);
 router.get("/blog/:id", getBlogById);
-router.post("/blog", verifyToken, upload.array("images", 5), createBlog);
-router.patch("/blog/:id", verifyToken, updateBlog);
-router.delete("/blog/:id", verifyToken, deleteBlog);
+router.get("/blog/slug/:slug", getBlogBySlug);
+router.post("/blog", upload.array("images", 5), createBlog);
+router.put("/blog/:id", updateBlog);
+router.delete("/blog/:id", deleteBlog);
 
 export default router;
diff --git a/user.rest b/user.rest
index 2e9d6d6..f174244 100644
--- a/user.rest
+++ b/user.rest
@@ -1,9 +1,9 @@
-POST http://localhost:5000/user/register
+POST http://localhost:5000/users/register
 Content-type: application/json
 
 {
-    "name" : "admin2",
-    "email" : "admin2@admin.com",
+    "name" : "admin",
+    "email" : "admin@admin.com",
     "password" : "admin123",
     "confirmPassword" : "admin123"
 }
@@ -20,6 +20,5 @@ Content-Type: application/json
 
 ###
 
-GET http://localhost:5000/users
-Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsIm5hbWUiOiJhZG1pbiIsImVtYWlsIjoiYWRtaW5AYWRtaW4uY29tIiwiaWF0IjoxNzQzMDQ0NDg5LCJleHAiOjE3NDMwNDQ1MDl9.m_tpB5DPpFDIaSWQki8jCKWqCbSzsBaKqh3W35a32XI
+GET http://localhost:5000/users/token