195 lines
4.9 KiB
JavaScript
195 lines
4.9 KiB
JavaScript
// services/user.service.js
|
||
const userDB = require("../db/user.db")
|
||
const dealDB = require("../db/deal.db")
|
||
const commentDB = require("../db/comment.db")
|
||
const dealService = require("./deal.service")
|
||
|
||
const PROFILE_PAGE_SIZE = 15
|
||
|
||
function normalizePage(value) {
|
||
const num = Number(value)
|
||
if (!Number.isInteger(num) || num < 1) return 1
|
||
return num
|
||
}
|
||
|
||
function buildPagination({ page, total, limit }) {
|
||
const safeTotal = Number.isFinite(total) ? Math.max(0, total) : 0
|
||
const safeLimit = Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : PROFILE_PAGE_SIZE
|
||
return {
|
||
page,
|
||
total: safeTotal,
|
||
totalPages: safeTotal === 0 ? 0 : Math.ceil(safeTotal / safeLimit),
|
||
limit: safeLimit,
|
||
}
|
||
}
|
||
|
||
async function getUserProfileByUsername(userName) {
|
||
const username = String(userName).trim()
|
||
if (!username) throw new Error("username zorunlu")
|
||
|
||
const user = await userDB.findUser(
|
||
{ username },
|
||
{
|
||
select: {
|
||
id: true,
|
||
username: true,
|
||
email: true,
|
||
avatarUrl: true,
|
||
createdAt: true,
|
||
userBadges: {
|
||
orderBy: { earnedAt: "desc" },
|
||
select: {
|
||
earnedAt: true,
|
||
badge: { select: { id: true, name: true, iconUrl: true, description: true } },
|
||
},
|
||
},
|
||
},
|
||
}
|
||
)
|
||
|
||
if (!user) {
|
||
const err = new Error("Kullanıcı bulunamadı.")
|
||
err.statusCode = 404
|
||
throw err
|
||
}
|
||
|
||
const commentsPage = 1
|
||
const dealsPage = 1
|
||
|
||
const [dealAgg, totalComments, comments, userDeals] = await Promise.all([
|
||
dealDB.aggregateDeals({ userId: user.id, status: { in: ["ACTIVE", "EXPIRED"] } }),
|
||
commentDB.countComments({ userId: user.id }),
|
||
commentDB.findComments(
|
||
{ userId: user.id },
|
||
{
|
||
orderBy: { createdAt: "desc" },
|
||
skip: (commentsPage - 1) * PROFILE_PAGE_SIZE,
|
||
take: PROFILE_PAGE_SIZE,
|
||
include: {
|
||
user: { select: { id: true, username: true, avatarUrl: true } },
|
||
deal: { select: { id: true, title: true } },
|
||
},
|
||
}
|
||
),
|
||
dealService.getDeals({
|
||
preset: "USER_PUBLIC",
|
||
targetUserId: user.id,
|
||
viewer: null,
|
||
page: dealsPage,
|
||
limit: PROFILE_PAGE_SIZE,
|
||
}),
|
||
])
|
||
|
||
const totalDeals = dealAgg?._count?._all ?? 0
|
||
const stats = {
|
||
totalLikes: dealAgg?._sum?.score ?? 0,
|
||
totalComments: totalComments ?? 0,
|
||
totalShares: totalDeals,
|
||
totalDeals,
|
||
}
|
||
|
||
return {
|
||
user,
|
||
stats,
|
||
deals: userDeals.results,
|
||
comments,
|
||
badges: user.userBadges || [],
|
||
dealsPagination: buildPagination({
|
||
page: userDeals.page ?? dealsPage,
|
||
total: userDeals.total ?? 0,
|
||
limit: PROFILE_PAGE_SIZE,
|
||
}),
|
||
commentsPagination: buildPagination({
|
||
page: commentsPage,
|
||
total: totalComments ?? 0,
|
||
limit: PROFILE_PAGE_SIZE,
|
||
}),
|
||
}
|
||
}
|
||
|
||
async function getUserCommentsByUsername(userName, { page = 1, limit = PROFILE_PAGE_SIZE } = {}) {
|
||
const username = String(userName).trim()
|
||
if (!username) throw new Error("username zorunlu")
|
||
|
||
const user = await userDB.findUser(
|
||
{ username },
|
||
{ select: { id: true } }
|
||
)
|
||
if (!user) {
|
||
const err = new Error("Kullanici bulunamadi.")
|
||
err.statusCode = 404
|
||
throw err
|
||
}
|
||
|
||
const safePage = normalizePage(page)
|
||
const safeLimit = PROFILE_PAGE_SIZE
|
||
const skip = (safePage - 1) * safeLimit
|
||
|
||
const [total, results] = await Promise.all([
|
||
commentDB.countComments({ userId: user.id }),
|
||
commentDB.findComments(
|
||
{ userId: user.id },
|
||
{
|
||
orderBy: { createdAt: "desc" },
|
||
skip,
|
||
take: safeLimit,
|
||
include: {
|
||
user: { select: { id: true, username: true, avatarUrl: true } },
|
||
deal: { select: { id: true, title: true } },
|
||
},
|
||
}
|
||
),
|
||
])
|
||
|
||
return {
|
||
page: safePage,
|
||
total: total ?? 0,
|
||
totalPages: total ? Math.ceil(total / safeLimit) : 0,
|
||
limit: safeLimit,
|
||
results,
|
||
}
|
||
}
|
||
|
||
async function getUserDealsByUsername(userName, { page = 1, limit = PROFILE_PAGE_SIZE, viewer = null } = {}) {
|
||
const username = String(userName).trim()
|
||
if (!username) throw new Error("username zorunlu")
|
||
|
||
const user = await userDB.findUser(
|
||
{ username },
|
||
{ select: { id: true } }
|
||
)
|
||
if (!user) {
|
||
const err = new Error("Kullanici bulunamadi.")
|
||
err.statusCode = 404
|
||
throw err
|
||
}
|
||
|
||
const safePage = normalizePage(page)
|
||
const safeLimit = PROFILE_PAGE_SIZE
|
||
|
||
const isSelfProfile = viewer?.userId && Number(viewer.userId) === Number(user.id)
|
||
const preset = isSelfProfile ? "MY" : "USER_PUBLIC"
|
||
|
||
const payload = await dealService.getDeals({
|
||
preset,
|
||
targetUserId: user.id,
|
||
viewer,
|
||
page: safePage,
|
||
limit: safeLimit,
|
||
})
|
||
|
||
return {
|
||
page: payload.page ?? safePage,
|
||
total: payload.total ?? 0,
|
||
totalPages: payload.totalPages ?? 0,
|
||
limit: safeLimit,
|
||
results: payload.results ?? [],
|
||
}
|
||
}
|
||
|
||
module.exports = {
|
||
getUserProfileByUsername,
|
||
getUserCommentsByUsername,
|
||
getUserDealsByUsername,
|
||
}
|