Add avatarUrl field to User schema and Supabase setup
This commit is contained in:
parent
fcd683ed67
commit
8ed231c5f2
12
package-lock.json
generated
12
package-lock.json
generated
|
|
@ -13,7 +13,8 @@
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
"jsonwebtoken": "^9.0.2"
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"zod": "^4.1.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/cors": "^2.8.19",
|
"@types/cors": "^2.8.19",
|
||||||
|
|
@ -1742,6 +1743,15 @@
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zod": {
|
||||||
|
"version": "4.1.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz",
|
||||||
|
"integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
"jsonwebtoken": "^9.0.2"
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"zod": "^4.1.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/cors": "^2.8.19",
|
"@types/cors": "^2.8.19",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- A unique constraint covering the columns `[dealId,userId]` on the table `DealVote` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "DealVote_dealId_userId_key" ON "DealVote"("dealId", "userId");
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Comment" (
|
||||||
|
"id" SERIAL NOT NULL,
|
||||||
|
"text" TEXT NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"userId" INTEGER NOT NULL,
|
||||||
|
"dealId" INTEGER NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Comment_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Comment" ADD CONSTRAINT "Comment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Comment" ADD CONSTRAINT "Comment_dealId_fkey" FOREIGN KEY ("dealId") REFERENCES "Deal"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "User" ADD COLUMN "avatarUrl" VARCHAR(512);
|
||||||
|
|
@ -18,37 +18,53 @@ model User {
|
||||||
username String @unique
|
username String @unique
|
||||||
email String @unique
|
email String @unique
|
||||||
passwordHash String
|
passwordHash String
|
||||||
|
avatarUrl String? @db.VarChar(512)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
Deal Deal[]
|
Deal Deal[]
|
||||||
votes DealVote[]
|
votes DealVote[]
|
||||||
|
comments Comment[]
|
||||||
}
|
}
|
||||||
|
|
||||||
model Deal {
|
model Deal {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
title String
|
title String
|
||||||
description String?
|
description String?
|
||||||
url String?
|
url String?
|
||||||
imageUrl String?
|
imageUrl String?
|
||||||
price Float?
|
price Float?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
userId Int
|
userId Int
|
||||||
|
score Int @default(0)
|
||||||
|
|
||||||
// yeni alan:
|
user User @relation(fields: [userId], references: [id])
|
||||||
score Int @default(0)
|
votes DealVote[]
|
||||||
|
comments Comment[] // ← burası eklendi
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
votes DealVote[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
model DealVote {
|
model DealVote {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
dealId Int
|
dealId Int
|
||||||
userId Int
|
userId Int
|
||||||
voteType String // "UP" veya "DOWN"
|
voteType String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
deal Deal @relation(fields: [dealId], references: [id])
|
deal Deal @relation(fields: [dealId], references: [id])
|
||||||
user User @relation(fields: [userId], references: [id])
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
|
||||||
|
@@unique([dealId, userId]) // aynı kullanıcı aynı ilana bir kez oy verebilir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
model Comment {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
text String
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
userId Int
|
||||||
|
dealId Int
|
||||||
|
|
||||||
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
deal Deal @relation(fields: [dealId], references: [id])
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ const bcrypt = require("bcryptjs");
|
||||||
const jwt = require("jsonwebtoken");
|
const jwt = require("jsonwebtoken");
|
||||||
const { PrismaClient } = require("@prisma/client");
|
const { PrismaClient } = require("@prisma/client");
|
||||||
const generateToken = require("../utils/generateToken");
|
const generateToken = require("../utils/generateToken");
|
||||||
|
const authMiddleware = require("../middleware/authMiddleware");
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
@ -60,4 +61,19 @@ router.post("/login", async (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
router.get("/me", authMiddleware, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const user = await prisma.user.findUnique({
|
||||||
|
where: { id: req.user.userId },
|
||||||
|
select: { id: true, username: true, email: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!user) return res.status(404).json({ error: "Kullanıcı bulunamadı" })
|
||||||
|
res.json(user)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
res.status(500).json({ error: "Sunucu hatası" })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
||||||
46
routes/deal/commentRoutes.js
Normal file
46
routes/deal/commentRoutes.js
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
const express = require("express")
|
||||||
|
const authMiddleware = require("../../middleware/authMiddleware")
|
||||||
|
const {
|
||||||
|
getCommentsByDealId,
|
||||||
|
createComment,
|
||||||
|
deleteComment,
|
||||||
|
} = require("../../services/deal/commentService")
|
||||||
|
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
router.get("/:dealId", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const comments = await getCommentsByDealId(req.params.dealId)
|
||||||
|
res.json(comments)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
res.status(500).json({ error: "Sunucu hatası" })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.post("/", authMiddleware, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { dealId, text } = req.body
|
||||||
|
const userId = req.user.userId
|
||||||
|
if (!text?.trim()) return res.status(400).json({ error: "Yorum boş olamaz." })
|
||||||
|
|
||||||
|
const comment = await createComment({ dealId, userId, text })
|
||||||
|
res.json(comment)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
res.status(500).json({ error: err.message || "Sunucu hatası" })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.delete("/:id", authMiddleware, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = await deleteComment(req.params.id, req.user.userId)
|
||||||
|
res.json(result)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
const status = err.message.includes("yetkin") ? 403 : 404
|
||||||
|
res.status(status).json({ error: err.message })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
39
routes/deal/dealRoutes.js
Normal file
39
routes/deal/dealRoutes.js
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
const express = require("express")
|
||||||
|
const router = express.Router()
|
||||||
|
const { getAllDeals, getDealById, createDeal } = require("../../services/deal/dealService")
|
||||||
|
const authMiddleware = require("../../middleware/authMiddleware")
|
||||||
|
|
||||||
|
router.get("/", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const page = Number(req.query.page) || 1
|
||||||
|
const limit = 10
|
||||||
|
const data = await getAllDeals(page, limit)
|
||||||
|
res.json(data)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
res.status(500).json({ error: "Sunucu hatası" })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get("/:id", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const deal = await getDealById(req.params.id)
|
||||||
|
if (!deal) return res.status(404).json({ error: "Deal bulunamadı" })
|
||||||
|
res.json(deal)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
res.status(500).json({ error: "Sunucu hatası" })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.post("/", authMiddleware, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const userId = req.user.userId
|
||||||
|
const deal = await createDeal(req.body, userId)
|
||||||
|
res.json(deal)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
res.status(500).json({ error: "Sunucu hatası" })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
module.exports = router
|
||||||
51
routes/deal/voteRoutes.js
Normal file
51
routes/deal/voteRoutes.js
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
const express = require("express")
|
||||||
|
const authMiddleware = require("../../middleware/authMiddleware")
|
||||||
|
const { voteDeal, getVotes } = require("../../services/deal/dealService")
|
||||||
|
const { z } = require("zod")
|
||||||
|
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
// Şema tanımı
|
||||||
|
const voteSchema = z.object({
|
||||||
|
dealId: z.number().int().positive(),
|
||||||
|
voteType: z.enum(["UP", "DOWN"]),
|
||||||
|
})
|
||||||
|
|
||||||
|
// Oy verme
|
||||||
|
router.post("/", authMiddleware, async (req, res) => {
|
||||||
|
const parsed = voteSchema.safeParse(req.body)
|
||||||
|
if (!parsed.success) {
|
||||||
|
return res.status(400).json({
|
||||||
|
error: "Geçersiz veri",
|
||||||
|
details: parsed.error.errors.map((e) => e.message),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const { dealId, voteType } = parsed.data
|
||||||
|
const userId = req.user.userId
|
||||||
|
|
||||||
|
try {
|
||||||
|
const score = await voteDeal(dealId, userId, voteType)
|
||||||
|
res.json({ score })
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
res.status(500).json({ error: "Sunucu hatası" })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Belirli deal için oyları çek
|
||||||
|
router.get("/:dealId", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const dealId = Number(req.params.dealId)
|
||||||
|
if (isNaN(dealId) || dealId <= 0)
|
||||||
|
return res.status(400).json({ error: "Geçersiz dealId" })
|
||||||
|
|
||||||
|
const data = await getVotes(dealId)
|
||||||
|
res.json(data)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
res.status(500).json({ error: "Sunucu hatası" })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
const express = require("express");
|
|
||||||
const { PrismaClient } = require("@prisma/client");
|
|
||||||
const router = express.Router();
|
|
||||||
const prisma = new PrismaClient();
|
|
||||||
const authMiddleware = require("../middleware/authMiddleware");
|
|
||||||
|
|
||||||
|
|
||||||
router.get("/", async (req, res) => {
|
|
||||||
const deals = await prisma.deal.findMany({ include: { user: true } });
|
|
||||||
res.json(deals);
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post("/",authMiddleware, async (req, res) => {
|
|
||||||
const { title, description, url, imageUrl, price, userId } = req.body;
|
|
||||||
const deal = await prisma.deal.create({
|
|
||||||
data: { title, description, url, imageUrl, price, userId },
|
|
||||||
});
|
|
||||||
res.json(deal);
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = router;
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
const express = require("express");
|
|
||||||
const { PrismaClient } = require("@prisma/client");
|
|
||||||
const authMiddleware = require("../middleware/authMiddleware");
|
|
||||||
|
|
||||||
const router = express.Router();
|
|
||||||
const prisma = new PrismaClient();
|
|
||||||
|
|
||||||
// Oy verme
|
|
||||||
router.post("/", authMiddleware, async (req, res) => {
|
|
||||||
console.log("body:", req.body);
|
|
||||||
console.log("user:", req.user);
|
|
||||||
try {
|
|
||||||
const { dealId, voteType } = req.body;
|
|
||||||
const userId = req.user.userId;
|
|
||||||
if (!dealId || !userId || !voteType)
|
|
||||||
return res.status(400).json({ error: "Eksik veri." });
|
|
||||||
|
|
||||||
const existingVote = await prisma.dealVote.findFirst({
|
|
||||||
where: { dealId, userId },
|
|
||||||
});
|
|
||||||
|
|
||||||
let vote;
|
|
||||||
if (existingVote) {
|
|
||||||
// Aynı kullanıcı aynı ilana yeniden oy verirse güncelle
|
|
||||||
vote = await prisma.dealVote.update({
|
|
||||||
where: { id: existingVote.id },
|
|
||||||
data: { voteType },
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
vote = await prisma.dealVote.create({
|
|
||||||
data: { dealId, userId, voteType },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toplam oy sayısını güncelle
|
|
||||||
const upvotes = await prisma.dealVote.count({
|
|
||||||
where: { dealId, voteType: "UP" },
|
|
||||||
});
|
|
||||||
const downvotes = await prisma.dealVote.count({
|
|
||||||
where: { dealId, voteType: "DOWN" },
|
|
||||||
});
|
|
||||||
|
|
||||||
await prisma.deal.update({
|
|
||||||
where: { id: dealId },
|
|
||||||
data: { score: upvotes - downvotes },
|
|
||||||
});
|
|
||||||
|
|
||||||
res.json({ vote, score: upvotes - downvotes });
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
res.status(500).json({ error: "Sunucu hatası." });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Belirli bir deal için oyları çek
|
|
||||||
router.get("/:dealId", async (req, res) => {
|
|
||||||
try {
|
|
||||||
const { dealId } = req.params;
|
|
||||||
|
|
||||||
const upvotes = await prisma.dealVote.count({
|
|
||||||
where: { dealId: parseInt(dealId), voteType: "UP" },
|
|
||||||
});
|
|
||||||
const downvotes = await prisma.dealVote.count({
|
|
||||||
where: { dealId: parseInt(dealId), voteType: "DOWN" },
|
|
||||||
});
|
|
||||||
|
|
||||||
res.json({ upvotes, downvotes, score: upvotes - downvotes });
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
res.status(500).json({ error: "Sunucu hatası." });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
module.exports = router;
|
|
||||||
|
|
@ -3,9 +3,10 @@ const cors = require("cors");
|
||||||
require("dotenv").config();
|
require("dotenv").config();
|
||||||
|
|
||||||
const userRoutes = require("./routes/userRoutes");
|
const userRoutes = require("./routes/userRoutes");
|
||||||
const dealRoutes = require("./routes/dealRoutes");
|
const dealRoutes = require("./routes/deal/dealRoutes");
|
||||||
const authRoutes = require("./routes/authRoutes");
|
const authRoutes = require("./routes/authRoutes");
|
||||||
const dealVoteRoutes = require("./routes/dealVoteRoutes");
|
const dealVoteRoutes = require("./routes/deal/voteRoutes");
|
||||||
|
const commentRoutes = require("./routes/deal/commentRoutes")
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
|
@ -16,5 +17,6 @@ app.use("/api/users", userRoutes);
|
||||||
app.use("/api/deals", dealRoutes);
|
app.use("/api/deals", dealRoutes);
|
||||||
app.use("/api/auth", authRoutes);
|
app.use("/api/auth", authRoutes);
|
||||||
app.use("/api/deal-votes", dealVoteRoutes);
|
app.use("/api/deal-votes", dealVoteRoutes);
|
||||||
|
app.use("/api/comments", commentRoutes)
|
||||||
|
|
||||||
app.listen(3000, () => console.log("Server running on http://localhost:3000"));
|
app.listen(3000, () => console.log("Server running on http://localhost:3000"));
|
||||||
|
|
|
||||||
66
services/deal/commentService.js
Normal file
66
services/deal/commentService.js
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
// services/deal/commentService.js
|
||||||
|
const { PrismaClient } = require("@prisma/client")
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
function assertPositiveInt(v, name = "id") {
|
||||||
|
const n = Number(v)
|
||||||
|
if (!Number.isInteger(n) || n <= 0) throw new Error(`Geçersiz ${name}.`)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getCommentsByDealId(dealId) {
|
||||||
|
const id = assertPositiveInt(dealId, "dealId")
|
||||||
|
|
||||||
|
// Deal mevcut mu kontrol et
|
||||||
|
const deal = await prisma.deal.findUnique({ where: { id } })
|
||||||
|
if (!deal) throw new Error("Deal bulunamadı.")
|
||||||
|
|
||||||
|
return prisma.comment.findMany({
|
||||||
|
where: { dealId: id },
|
||||||
|
include: { user: { select: { username: true } } },
|
||||||
|
orderBy: { createdAt: "desc" },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createComment({ dealId, userId, text }) {
|
||||||
|
// Basit doğrulamalar
|
||||||
|
const dId = assertPositiveInt(dealId, "dealId")
|
||||||
|
const uId = assertPositiveInt(userId, "userId")
|
||||||
|
if (!text || typeof text !== "string" || !text.trim())
|
||||||
|
throw new Error("Yorum boş olamaz.")
|
||||||
|
|
||||||
|
// Deal var mı kontrol et
|
||||||
|
const deal = await prisma.deal.findUnique({ where: { id: dId } })
|
||||||
|
if (!deal) throw new Error("Deal bulunamadı.")
|
||||||
|
|
||||||
|
// (Opsiyonel) Kullanıcı var mı kontrolü (ek güvenlik)
|
||||||
|
const user = await prisma.user.findUnique({ where: { id: uId } })
|
||||||
|
if (!user) throw new Error("Kullanıcı bulunamadı.")
|
||||||
|
|
||||||
|
const comment = await prisma.comment.create({
|
||||||
|
data: {
|
||||||
|
text: text.trim(),
|
||||||
|
userId: uId,
|
||||||
|
dealId: dId,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
user: { select: { username: true } },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return comment
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteComment(commentId, userId) {
|
||||||
|
const cId = assertPositiveInt(commentId, "commentId")
|
||||||
|
const uId = assertPositiveInt(userId, "userId")
|
||||||
|
|
||||||
|
const comment = await prisma.comment.findUnique({ where: { id: cId } })
|
||||||
|
if (!comment) throw new Error("Yorum bulunamadı.")
|
||||||
|
if (comment.userId !== uId) throw new Error("Bu yorumu silme yetkin yok.")
|
||||||
|
|
||||||
|
await prisma.comment.delete({ where: { id: cId } })
|
||||||
|
return { message: "Yorum silindi." }
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { getCommentsByDealId, createComment, deleteComment }
|
||||||
91
services/deal/dealService.js
Normal file
91
services/deal/dealService.js
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
const { PrismaClient } = require("@prisma/client")
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
|
||||||
|
async function getAllDeals(page = 1, limit = 10) {
|
||||||
|
const skip = (page - 1) * limit
|
||||||
|
|
||||||
|
const [deals, total] = await Promise.all([
|
||||||
|
prisma.deal.findMany({
|
||||||
|
skip,
|
||||||
|
take: limit,
|
||||||
|
include: { user: { select: { username: true } } },
|
||||||
|
orderBy: { createdAt: "desc" },
|
||||||
|
}),
|
||||||
|
prisma.deal.count(),
|
||||||
|
])
|
||||||
|
|
||||||
|
return {
|
||||||
|
page,
|
||||||
|
total,
|
||||||
|
totalPages: Math.ceil(total / limit),
|
||||||
|
results: deals,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getDealById(id) {
|
||||||
|
return prisma.deal.findUnique({
|
||||||
|
where: { id: Number(id) },
|
||||||
|
include: { user: { select: { username: true } } },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createDeal(data, userId) {
|
||||||
|
return prisma.deal.create({
|
||||||
|
data: {
|
||||||
|
title: data.title,
|
||||||
|
description: data.description,
|
||||||
|
url: data.url,
|
||||||
|
imageUrl: data.imageUrl,
|
||||||
|
price: data.price,
|
||||||
|
user: { connect: { id: userId } }, // JWT’den gelen userId burada bağlanır
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function voteDeal(dealId, userId, voteType) {
|
||||||
|
if (!dealId || !userId || !voteType) throw new Error("Eksik veri")
|
||||||
|
|
||||||
|
const existingVote = await prisma.dealVote.findFirst({
|
||||||
|
where: { dealId, userId },
|
||||||
|
})
|
||||||
|
|
||||||
|
if (existingVote) {
|
||||||
|
await prisma.dealVote.update({
|
||||||
|
where: { id: existingVote.id },
|
||||||
|
data: { voteType },
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await prisma.dealVote.create({
|
||||||
|
data: { dealId, userId, voteType },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const upvotes = await prisma.dealVote.count({
|
||||||
|
where: { dealId, voteType: "UP" },
|
||||||
|
})
|
||||||
|
const downvotes = await prisma.dealVote.count({
|
||||||
|
where: { dealId, voteType: "DOWN" },
|
||||||
|
})
|
||||||
|
|
||||||
|
const score = upvotes - downvotes
|
||||||
|
|
||||||
|
await prisma.deal.update({
|
||||||
|
where: { id: dealId },
|
||||||
|
data: { score },
|
||||||
|
})
|
||||||
|
|
||||||
|
return score
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getVotes(dealId) {
|
||||||
|
const upvotes = await prisma.dealVote.count({
|
||||||
|
where: { dealId: Number(dealId), voteType: "UP" },
|
||||||
|
})
|
||||||
|
const downvotes = await prisma.dealVote.count({
|
||||||
|
where: { dealId: Number(dealId), voteType: "DOWN" },
|
||||||
|
})
|
||||||
|
return { upvotes, downvotes, score: upvotes - downvotes }
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { getAllDeals, getDealById, createDeal, voteDeal, getVotes }
|
||||||
Loading…
Reference in New Issue
Block a user