diff --git a/db/client.js b/db/client.js new file mode 100644 index 0000000..2797c67 --- /dev/null +++ b/db/client.js @@ -0,0 +1,3 @@ +const { PrismaClient } = require("@prisma/client") +const prisma = new PrismaClient() +module.exports = prisma diff --git a/db/comment.db.js b/db/comment.db.js new file mode 100644 index 0000000..2da0569 --- /dev/null +++ b/db/comment.db.js @@ -0,0 +1,28 @@ +const prisma = require("./client") + +async function findComments(where, options = {}) { + return prisma.comment.findMany({ + where, + include: options.include || undefined, + select: options.select || undefined, + orderBy: options.orderBy || { createdAt: "desc" }, + }) +} + +async function createComment(data, options = {}) { + return prisma.comment.create({ + data, + include: options.include || undefined, + select: options.select || undefined, + }) +} + +async function deleteComment(where) { + return prisma.comment.delete({ where }) +} + +module.exports = { + findComments, + createComment, + deleteComment, +} diff --git a/db/deal.db.js b/db/deal.db.js new file mode 100644 index 0000000..39acf29 --- /dev/null +++ b/db/deal.db.js @@ -0,0 +1,82 @@ +const prisma = require("./client") + +async function findDeals(where = {}, options = {}) { + return prisma.deal.findMany({ + where, + include: options.include || undefined, + select: options.select || undefined, + orderBy: options.orderBy || { createdAt: "desc" }, + skip: options.skip || 0, + take: options.take || undefined, + }) +} + +async function findDeal(where, options = {}) { + return prisma.deal.findUnique({ + where, + include: options.include || undefined, + select: options.select || undefined, + }) +} + +async function createDeal(data, options = {}) { + return prisma.deal.create({ + data, + include: options.include || undefined, + select: options.select || undefined, + }) +} + +async function updateDeal(where, data, options = {}) { + return prisma.deal.update({ + where, + data, + include: options.include || undefined, + select: options.select || undefined, + }) +} + +async function countDeals(where = {}) { + return prisma.deal.count({ where }) +} + +async function findVotes(where = {}, options = {}) { + return prisma.dealVote.findMany({ + where, + include: options.include || undefined, + select: options.select || undefined, + }) +} + +async function createVote(data, options = {}) { + return prisma.dealVote.create({ + data, + include: options.include || undefined, + select: options.select || undefined, + }) +} + +async function updateVote(where, data, options = {}) { + return prisma.dealVote.update({ + where, + data, + include: options.include || undefined, + select: options.select || undefined, + }) +} + +async function countVotes(where = {}) { + return prisma.dealVote.count({ where }) +} + +module.exports = { + findDeals, + findDeal, + createDeal, + updateDeal, + countDeals, + findVotes, + createVote, + updateVote, + countVotes, +} diff --git a/db/user.db.js b/db/user.db.js new file mode 100644 index 0000000..51d1466 --- /dev/null +++ b/db/user.db.js @@ -0,0 +1,24 @@ +const { PrismaClient } = require("@prisma/client") +const prisma = new PrismaClient() + +async function findUser(where, options = {}) { + return prisma.user.findUnique({ + where, + include: options.include || undefined, + select: options.select || undefined, + }) +} + +async function updateUser(where, data, options = {}) { + return prisma.user.update({ + where, + data, + include: options.include || undefined, + select: options.select || undefined, + }) +} + +module.exports = { + findUser, + updateUser, +} diff --git a/routes/authRoutes.js b/routes/authRoutes.js index 3e397b9..96672fe 100644 --- a/routes/authRoutes.js +++ b/routes/authRoutes.js @@ -65,7 +65,7 @@ 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 }, + select: { id: true, username: true, email: true,avatarUrl:true }, }) if (!user) return res.status(404).json({ error: "Kullanıcı bulunamadı" }) diff --git a/routes/deal/dealRoutes.js b/routes/deal/dealRoutes.js index f08cf1b..f6556a8 100644 --- a/routes/deal/dealRoutes.js +++ b/routes/deal/dealRoutes.js @@ -1,6 +1,6 @@ const express = require("express") const router = express.Router() -const { getAllDeals, getDealById, createDeal } = require("../../services/deal/dealService") +const { getAllDeals, getDealById, createDeal,searchDeals } = require("../../services/deal/dealService") const authMiddleware = require("../../middleware/authMiddleware") router.get("/", async (req, res) => { @@ -15,6 +15,25 @@ router.get("/", async (req, res) => { } }) + +router.get("/search", async (req, res) => { + try { + const query = req.query.q || "" + const page = Number(req.query.page) || 1 + const limit = 10 + + if (!query.trim()) { + return res.json({ results: [], total: 0, totalPages: 0, page }) + } + + const data = await searchDeals(query, 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) diff --git a/routes/user/userRoutes.js b/routes/user/userRoutes.js new file mode 100644 index 0000000..fec874b --- /dev/null +++ b/routes/user/userRoutes.js @@ -0,0 +1,63 @@ +// routes/profileRoutes.js +const express = require("express") +const { PrismaClient } = require("@prisma/client") +const prisma = new PrismaClient() +const router = express.Router() + +// Belirli bir kullanıcının profil detayları +router.get("/:userName", async (req, res) => { + console.log("İstek geldi:", req.params.userName) + try { + const username = req.params.userName + const user = await prisma.user.findUnique({ + where: { username: username }, + select: { + id: true, + username: true, + avatarUrl: true, + createdAt: true, + }, + }) + + if (!user) return res.status(404).json({ message: "Kullanıcı bulunamadı." }) + + // Kullanıcının paylaştığı fırsatlar + const deals = await prisma.deal.findMany({ + where: { userId: user.id }, + orderBy: { createdAt: "desc" }, + select: { + id: true, + title: true, + price: true, + createdAt: true, + score: true, + images: { + orderBy: { order: "asc" }, // küçük order en önde + take: 1, // sadece ilk görsel + select: { imageUrl: true }, + }, + }, + }) + + + // Kullanıcının yaptığı yorumlar + const comments = await prisma.comment.findMany({ + where: { userId:user.id }, + orderBy: { createdAt: "desc" }, + select: { + id: true, + text: true, + dealId: true, + createdAt: true, + deal: { select: { title: true } }, + }, + }) + + res.json({ user, deals, comments }) + } catch (err) { + console.error(err) + res.status(500).json({ message: "Profil bilgileri alınamadı.", error: err.message }) + } +}) + +module.exports = router diff --git a/server.js b/server.js index ecd0f06..87bba4a 100644 --- a/server.js +++ b/server.js @@ -2,23 +2,26 @@ const express = require("express") const cors = require("cors") require("dotenv").config() -const userRoutes = require("./routes/userRoutes") +const userRoutesneedRefactor = require("./routes/userRoutes") const dealRoutes = require("./routes/deal/dealRoutes") const authRoutes = require("./routes/authRoutes") const dealVoteRoutes = require("./routes/deal/voteRoutes") const commentRoutes = require("./routes/deal/commentRoutes") const accountSettingsRoutes = require("./routes/account/accountSettingsRoutes") +const userRoutes = require("./routes/user/userRoutes") + const app = express() app.use(cors()) app.use(express.json()) app.use(express.urlencoded({ extended: true })) -app.use("/api/users", userRoutes) +app.use("/api/users", userRoutesneedRefactor) app.use("/api/deals", dealRoutes) app.use("/api/auth", authRoutes) app.use("/api/deal-votes", dealVoteRoutes) app.use("/api/comments", commentRoutes) app.use("/api/account", accountSettingsRoutes) +app.use("/api/user", userRoutes) app.listen(3000, () => console.log("Server running on http://localhost:3000")) diff --git a/services/deal/commentService.js b/services/deal/commentService.js index f59cd83..3b0f2b1 100644 --- a/services/deal/commentService.js +++ b/services/deal/commentService.js @@ -1,6 +1,5 @@ -// services/deal/commentService.js -const { PrismaClient } = require("@prisma/client") -const prisma = new PrismaClient() +const dealDB = require("../../db/deal.db") +const commentDB = require("../../db/comment.db") function assertPositiveInt(v, name = "id") { const n = Number(v) @@ -11,56 +10,51 @@ function assertPositiveInt(v, name = "id") { async function getCommentsByDealId(dealId) { const id = assertPositiveInt(dealId, "dealId") - // Deal mevcut mu kontrol et - const deal = await prisma.deal.findUnique({ where: { id } }) + const deal = await dealDB.findDeal({ id }) if (!deal) throw new Error("Deal bulunamadı.") - return prisma.comment.findMany({ - where: { dealId: id }, - include: { user: { select: { username: true } } }, - orderBy: { createdAt: "desc" }, - }) + const include = { user: { select: { username: true, avatarUrl: true } } } + return commentDB.findComments({ dealId: id }, { include }) } 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 } }) + const deal = await dealDB.findDeal({ 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 include = { user: { select: { username: true, avatarUrl: true } } } + const data = { + text: text.trim(), + userId: uId, + dealId: dId, + } - const comment = await prisma.comment.create({ - data: { - text: text.trim(), - userId: uId, - dealId: dId, - }, - include: { - user: { select: { username: true } }, - }, - }) - - return comment + return commentDB.createComment(data, { include }) } 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.") + const comments = await commentDB.findComments( + { id: cId }, + { select: { userId: true } } + ) - await prisma.comment.delete({ where: { id: cId } }) + if (!comments || comments.length === 0) throw new Error("Yorum bulunamadı.") + if (comments[0].userId !== uId) throw new Error("Bu yorumu silme yetkin yok.") + + await commentDB.deleteComment({ id: cId }) return { message: "Yorum silindi." } } -module.exports = { getCommentsByDealId, createComment, deleteComment } +module.exports = { + getCommentsByDealId, + createComment, + deleteComment, +} diff --git a/services/deal/dealService.js b/services/deal/dealService.js index 6aa2003..cc12c9d 100644 --- a/services/deal/dealService.js +++ b/services/deal/dealService.js @@ -1,12 +1,16 @@ -const { PrismaClient } = require("@prisma/client") -const prisma = new PrismaClient() +const dealDB = require("../../db/deal.db") - -async function getAllDeals(page = 1, limit = 10) { +async function searchDeals(query, page = 1, limit = 10) { const skip = (page - 1) * limit + const where = { + OR: [ + { title: { contains: query, mode: "insensitive" } }, + { description: { contains: query, mode: "insensitive" } }, + ], + } const [deals, total] = await Promise.all([ - prisma.deal.findMany({ + dealDB.findDeals(where, { skip, take: limit, orderBy: { createdAt: "desc" }, @@ -14,12 +18,40 @@ async function getAllDeals(page = 1, limit = 10) { user: { select: { username: true } }, images: { orderBy: { order: "asc" }, - take: 1, // sadece kapak fotoğrafı + take: 1, select: { imageUrl: true }, }, }, }), - prisma.deal.count(), + dealDB.countDeals(where), + ]) + + return { + page, + total, + totalPages: Math.ceil(total / limit), + results: deals, + } +} + +async function getAllDeals(page = 1, limit = 10) { + const skip = (page - 1) * limit + + const [deals, total] = await Promise.all([ + dealDB.findDeals({}, { + skip, + take: limit, + orderBy: { createdAt: "desc" }, + include: { + user: { select: { username: true } }, + images: { + orderBy: { order: "asc" }, + take: 1, + select: { imageUrl: true }, + }, + }, + }), + dealDB.countDeals(), ]) return { @@ -31,76 +63,71 @@ async function getAllDeals(page = 1, limit = 10) { } async function getDealById(id) { - return prisma.deal.findUnique({ - where: { id: Number(id) }, - include: { - user: { select: { username: true } }, - images: { - orderBy: { order: "asc" }, // tüm fotoğrafları sırayla getir - select: { id: true, imageUrl: true, order: true }, + return dealDB.findDeal( + { id: Number(id) }, + { + include: { + user: { select: { username: true } }, + images: { + orderBy: { order: "asc" }, + select: { id: true, imageUrl: true, order: 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 - }, - }) + const payload = { + title: data.title, + description: data.description, + url: data.url, + price: data.price, + user: { connect: { id: userId } }, + images: data.images?.length + ? { + create: data.images.map((imgUrl, index) => ({ + imageUrl: imgUrl, + order: index, + })), + } + : undefined, + } + + return dealDB.createDeal(payload, { include: { images: true } }) } async function voteDeal(dealId, userId, voteType) { if (!dealId || !userId || !voteType) throw new Error("Eksik veri") - const existingVote = await prisma.dealVote.findFirst({ - where: { dealId, userId }, - }) + const existingVote = await dealDB.findVotes({ dealId, userId }) + const vote = existingVote[0] - if (existingVote) { - await prisma.dealVote.update({ - where: { id: existingVote.id }, - data: { voteType }, - }) + if (vote) { + await dealDB.updateVote({ id: vote.id }, { voteType }) } else { - await prisma.dealVote.create({ - data: { dealId, userId, voteType }, - }) + await dealDB.createVote({ dealId, userId, voteType }) } - const upvotes = await prisma.dealVote.count({ - where: { dealId, voteType: "UP" }, - }) - const downvotes = await prisma.dealVote.count({ - where: { dealId, voteType: "DOWN" }, - }) - + const upvotes = await dealDB.countVotes({ dealId, voteType: "UP" }) + const downvotes = await dealDB.countVotes({ dealId, voteType: "DOWN" }) const score = upvotes - downvotes - await prisma.deal.update({ - where: { id: dealId }, - data: { score }, - }) - + await dealDB.updateDeal({ id: dealId }, { 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" }, - }) + const upvotes = await dealDB.countVotes({ dealId: Number(dealId), voteType: "UP" }) + const downvotes = await dealDB.countVotes({ dealId: Number(dealId), voteType: "DOWN" }) return { upvotes, downvotes, score: upvotes - downvotes } } -module.exports = { getAllDeals, getDealById, createDeal, voteDeal, getVotes } +module.exports = { + getAllDeals, + getDealById, + createDeal, + voteDeal, + getVotes, + searchDeals, +} diff --git a/services/profile/myProfileService.js b/services/profile/myProfileService.js index 485858a..7768936 100644 --- a/services/profile/myProfileService.js +++ b/services/profile/myProfileService.js @@ -1,25 +1,30 @@ -const { PrismaClient } = require("@prisma/client") -const prisma = new PrismaClient() +const userDb = require("../../db/user.db") + +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 updateAvatarUrl(userId, url) { - return await prisma.user.update({ - where: { id: userId }, - data: { avatarUrl: url }, - select: { id: true, username: true, avatarUrl: true }, - }) + const id = assertPositiveInt(userId, "userId") + if (!url || typeof url !== "string" || !url.trim()) + throw new Error("Geçersiz URL.") + + const select = { id: true, username: true, avatarUrl: true } + return userDb.updateUser({ id }, { avatarUrl: url.trim() }, { select }) } async function getUserProfile(userId) { - return await prisma.user.findUnique({ - where: { id: userId }, - select: { - id: true, - username: true, - email: true, - avatarUrl: true, - createdAt: true, - }, - }) + const id = assertPositiveInt(userId, "userId") + const select = { + id: true, + username: true, + email: true, + avatarUrl: true, + createdAt: true, + } + return userDb.findUser({ id }, { select }) } module.exports = { diff --git a/services/supabase/supabaseUploadService.js b/services/supabase/supabaseUploadService.js index 1f8c4eb..a383dfa 100644 --- a/services/supabase/supabaseUploadService.js +++ b/services/supabase/supabaseUploadService.js @@ -5,7 +5,7 @@ const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY async function uploadProfileImage(userId, file) { const path = `avatars/${userId}_${Date.now()}.jpg` const { data, error } = await supabase.storage - .from("avatars") + .from("deal") .upload(path, file.data, { contentType: "image/jpeg", upsert: true,