first commit
This commit is contained in:
78
app/api/admin/matches/[id]/calc-points/route.ts
Normal file
78
app/api/admin/matches/[id]/calc-points/route.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import { calculateMatchPoints } from "@/lib/points";
|
||||
|
||||
export async function POST(_: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const events = await db.matchEvent.findMany({
|
||||
where: { matchId: params.id },
|
||||
include: { player: true },
|
||||
});
|
||||
|
||||
// گروهبندی رویدادها بر اساس بازیکن
|
||||
const playerEvents: Record<string, { player: any; events: any[] }> = {};
|
||||
for (const ev of events) {
|
||||
if (!playerEvents[ev.playerId]) playerEvents[ev.playerId] = { player: ev.player, events: [] };
|
||||
playerEvents[ev.playerId].events.push(ev);
|
||||
}
|
||||
|
||||
const results = [];
|
||||
|
||||
for (const [playerId, { player, events: evs }] of Object.entries(playerEvents)) {
|
||||
const goals = evs.filter((e) => e.type === "GOAL").length;
|
||||
const assists = evs.filter((e) => e.type === "ASSIST").length;
|
||||
const yellowCards = evs.filter((e) => e.type === "YELLOW_CARD" || e.type === "SECOND_YELLOW").length;
|
||||
const redCards = evs.filter((e) => e.type === "RED_CARD" || e.type === "SECOND_YELLOW").length;
|
||||
const cleanSheet = evs.some((e) => e.type === "CLEAN_SHEET");
|
||||
const penaltySaved = evs.filter((e) => e.type === "PENALTY_SAVED").length;
|
||||
const penaltyMissed = evs.filter((e) => e.type === "PENALTY_MISSED").length;
|
||||
const ownGoals = evs.filter((e) => e.type === "OWN_GOAL").length;
|
||||
const isMotm = evs.some((e) => e.type === "MOTM");
|
||||
const extraTimeBonus = evs.filter((e) => e.type === "EXTRA_TIME_BONUS").length;
|
||||
|
||||
// دقیقه بازی: اگه تعویض شده کمتر از ۹۰، وگرنه ۹۰
|
||||
const subOut = evs.find((e) => e.type === "SUBSTITUTION_OUT");
|
||||
const subIn = evs.find((e) => e.type === "SUBSTITUTION_IN");
|
||||
const injury = evs.find((e) => e.type === "INJURY_NO_SUB");
|
||||
let minutesPlayed = 90;
|
||||
if (subOut?.minute) minutesPlayed = subOut.minute;
|
||||
else if (injury?.minute) minutesPlayed = injury.minute;
|
||||
if (subIn?.minute) minutesPlayed = 90 - subIn.minute;
|
||||
|
||||
const points = await calculateMatchPoints({
|
||||
position: player.position,
|
||||
goals, assists, yellowCards, redCards, minutesPlayed,
|
||||
cleanSheet, penaltySaved, penaltyMissed, ownGoals, isMotm, extraTimeBonus,
|
||||
});
|
||||
|
||||
const stat = await db.playerMatchStat.upsert({
|
||||
where: { playerId_matchId: { playerId, matchId: params.id } },
|
||||
update: { goals, assists, yellowCards, redCards, minutesPlayed, cleanSheet, penaltySaved, penaltyMissed, ownGoals, isMotm, extraTimeBonus, points },
|
||||
create: { playerId, matchId: params.id, goals, assists, yellowCards, redCards, minutesPlayed, cleanSheet, penaltySaved, penaltyMissed, ownGoals, isMotm, extraTimeBonus, points },
|
||||
});
|
||||
|
||||
// آپدیت totalPoints بازیکن
|
||||
const agg = await db.playerMatchStat.aggregate({ where: { playerId }, _sum: { points: true } });
|
||||
await db.player.update({ where: { id: playerId }, data: { totalPoints: agg._sum.points ?? 0 } });
|
||||
|
||||
results.push(stat);
|
||||
}
|
||||
|
||||
// آپدیت امتیاز تیمهای فانتزی
|
||||
const teams = await db.team.findMany({ include: { players: { include: { player: true } } } });
|
||||
for (const team of teams) {
|
||||
let total = 0;
|
||||
for (const tp of team.players) {
|
||||
const mult = tp.isCaptain ? 2 : tp.isViceCaptain ? 1.5 : 1;
|
||||
total += tp.player.totalPoints * mult;
|
||||
}
|
||||
await db.team.update({ where: { id: team.id }, data: { totalPoints: Math.round(total) } });
|
||||
}
|
||||
|
||||
return NextResponse.json({ calculated: results.length });
|
||||
}
|
||||
13
app/api/admin/matches/[id]/events/[eventId]/route.ts
Normal file
13
app/api/admin/matches/[id]/events/[eventId]/route.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function DELETE(_: NextRequest, { params }: { params: { id: string; eventId: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
await db.matchEvent.delete({ where: { id: params.eventId } });
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
18
app/api/admin/matches/[id]/events/route.ts
Normal file
18
app/api/admin/matches/[id]/events/route.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function POST(req: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { playerId, type, minute, extraInfo } = await req.json();
|
||||
|
||||
const event = await db.matchEvent.create({
|
||||
data: { matchId: params.id, playerId, type, minute: minute ?? null, extraInfo: extraInfo || null },
|
||||
});
|
||||
|
||||
return NextResponse.json(event, { status: 201 });
|
||||
}
|
||||
23
app/api/admin/matches/[id]/lineup/route.ts
Normal file
23
app/api/admin/matches/[id]/lineup/route.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function POST(req: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const lineups: Array<{ countryId: string; formation: string; playerIds: string[] }> = await req.json();
|
||||
|
||||
// حذف ترکیبهای قبلی
|
||||
await db.matchLineup.deleteMany({ where: { matchId: params.id } });
|
||||
|
||||
for (const l of lineups) {
|
||||
await db.matchLineup.create({
|
||||
data: { matchId: params.id, countryId: l.countryId, formation: l.formation, playerIds: l.playerIds },
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
22
app/api/admin/scoring/route.ts
Normal file
22
app/api/admin/scoring/route.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function PUT(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const rules: Array<{ position: string; eventType: string; points: number }> = await req.json();
|
||||
|
||||
for (const rule of rules) {
|
||||
await db.scoringRule.upsert({
|
||||
where: { position_eventType: { position: rule.position as any, eventType: rule.eventType as any } },
|
||||
update: { points: rule.points, updatedBy: (session.user as any).id },
|
||||
create: { position: rule.position as any, eventType: rule.eventType as any, points: rule.points, updatedBy: (session.user as any).id },
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
17
app/api/admin/teams/[id]/route.ts
Normal file
17
app/api/admin/teams/[id]/route.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function PUT(req: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { status } = await req.json();
|
||||
const team = await db.team.update({
|
||||
where: { id: params.id },
|
||||
data: { status },
|
||||
});
|
||||
return NextResponse.json(team);
|
||||
}
|
||||
20
app/api/admin/teams/route.ts
Normal file
20
app/api/admin/teams/route.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function GET() {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const teams = await db.team.findMany({
|
||||
include: {
|
||||
user: { select: { name: true, email: true } },
|
||||
_count: { select: { players: true } },
|
||||
},
|
||||
orderBy: { createdAt: "desc" },
|
||||
});
|
||||
|
||||
return NextResponse.json(teams);
|
||||
}
|
||||
5
app/api/auth/[...nextauth]/route.ts
Normal file
5
app/api/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import NextAuth from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
const handler = NextAuth(authOptions);
|
||||
export { handler as GET, handler as POST };
|
||||
23
app/api/auth/register/route.ts
Normal file
23
app/api/auth/register/route.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import bcrypt from "bcryptjs";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const { name, email, password } = await req.json();
|
||||
|
||||
if (!email || !password) {
|
||||
return NextResponse.json({ error: "ایمیل و رمز عبور الزامی است" }, { status: 400 });
|
||||
}
|
||||
|
||||
const existing = await db.user.findUnique({ where: { email } });
|
||||
if (existing) {
|
||||
return NextResponse.json({ error: "این ایمیل قبلاً ثبت شده" }, { status: 400 });
|
||||
}
|
||||
|
||||
const hashed = await bcrypt.hash(password, 10);
|
||||
const user = await db.user.create({
|
||||
data: { name, email, password: hashed },
|
||||
});
|
||||
|
||||
return NextResponse.json({ id: user.id }, { status: 201 });
|
||||
}
|
||||
23
app/api/countries/[id]/route.ts
Normal file
23
app/api/countries/[id]/route.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function PUT(req: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const body = await req.json();
|
||||
const country = await db.country.update({ where: { id: params.id }, data: body });
|
||||
return NextResponse.json(country);
|
||||
}
|
||||
|
||||
export async function DELETE(_: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
await db.country.delete({ where: { id: params.id } });
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
22
app/api/countries/route.ts
Normal file
22
app/api/countries/route.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function GET() {
|
||||
const countries = await db.country.findMany({
|
||||
include: { group: true },
|
||||
orderBy: { name: "asc" },
|
||||
});
|
||||
return NextResponse.json(countries);
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const body = await req.json();
|
||||
const country = await db.country.create({ data: body });
|
||||
return NextResponse.json(country, { status: 201 });
|
||||
}
|
||||
16
app/api/gameweeks/[id]/activate/route.ts
Normal file
16
app/api/gameweeks/[id]/activate/route.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function POST(_: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
// غیرفعال کردن همه
|
||||
await db.gameweek.updateMany({ data: { isActive: false } });
|
||||
// فعال کردن این هفته
|
||||
const gw = await db.gameweek.update({ where: { id: params.id }, data: { isActive: true } });
|
||||
return NextResponse.json(gw);
|
||||
}
|
||||
19
app/api/gameweeks/route.ts
Normal file
19
app/api/gameweeks/route.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function GET() {
|
||||
const gameweeks = await db.gameweek.findMany({ orderBy: { number: "asc" } });
|
||||
return NextResponse.json(gameweeks);
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const body = await req.json();
|
||||
const gw = await db.gameweek.create({ data: body });
|
||||
return NextResponse.json(gw, { status: 201 });
|
||||
}
|
||||
20
app/api/leaderboard/route.ts
Normal file
20
app/api/leaderboard/route.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
|
||||
export async function GET() {
|
||||
const teams = await db.team.findMany({
|
||||
orderBy: { totalPoints: "desc" },
|
||||
include: { user: { select: { name: true, email: true } } },
|
||||
take: 50,
|
||||
});
|
||||
|
||||
return NextResponse.json(
|
||||
teams.map((t, i) => ({
|
||||
rank: i + 1,
|
||||
teamName: t.name,
|
||||
userName: t.user.name ?? t.user.email,
|
||||
totalPoints: t.totalPoints,
|
||||
budget: t.budget,
|
||||
}))
|
||||
);
|
||||
}
|
||||
32
app/api/matches/[id]/route.ts
Normal file
32
app/api/matches/[id]/route.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function GET(_: NextRequest, { params }: { params: { id: string } }) {
|
||||
const match = await db.match.findUnique({
|
||||
where: { id: params.id },
|
||||
include: { homeTeam: true, awayTeam: true, playerStats: { include: { player: true } } },
|
||||
});
|
||||
if (!match) return NextResponse.json({ error: "Not found" }, { status: 404 });
|
||||
return NextResponse.json(match);
|
||||
}
|
||||
|
||||
export async function PUT(req: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const body = await req.json();
|
||||
const match = await db.match.update({ where: { id: params.id }, data: body });
|
||||
return NextResponse.json(match);
|
||||
}
|
||||
|
||||
export async function DELETE(_: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
await db.match.delete({ where: { id: params.id } });
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
65
app/api/matches/[id]/stats/route.ts
Normal file
65
app/api/matches/[id]/stats/route.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import { calculatePoints } from "@/lib/points";
|
||||
|
||||
export async function POST(req: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const stats: Array<{
|
||||
playerId: string;
|
||||
goals: number;
|
||||
assists: number;
|
||||
yellowCards: number;
|
||||
redCards: number;
|
||||
minutesPlayed: number;
|
||||
cleanSheet: boolean;
|
||||
}> = await req.json();
|
||||
|
||||
const results = [];
|
||||
|
||||
for (const stat of stats) {
|
||||
const player = await db.player.findUnique({ where: { id: stat.playerId } });
|
||||
if (!player) continue;
|
||||
|
||||
const points = calculatePoints({ position: player.position, ...stat });
|
||||
|
||||
const record = await db.playerMatchStat.upsert({
|
||||
where: { playerId_matchId: { playerId: stat.playerId, matchId: params.id } },
|
||||
update: { ...stat, points },
|
||||
create: { ...stat, matchId: params.id, points },
|
||||
});
|
||||
|
||||
// آپدیت امتیاز کل بازیکن
|
||||
const totalPoints = await db.playerMatchStat.aggregate({
|
||||
where: { playerId: stat.playerId },
|
||||
_sum: { points: true },
|
||||
});
|
||||
await db.player.update({
|
||||
where: { id: stat.playerId },
|
||||
data: { totalPoints: totalPoints._sum.points ?? 0 },
|
||||
});
|
||||
|
||||
results.push(record);
|
||||
}
|
||||
|
||||
// آپدیت امتیاز تیمهای فانتزی
|
||||
await recalcTeamPoints();
|
||||
|
||||
return NextResponse.json(results);
|
||||
}
|
||||
|
||||
async function recalcTeamPoints() {
|
||||
const teams = await db.team.findMany({ include: { players: { include: { player: true } } } });
|
||||
for (const team of teams) {
|
||||
let total = 0;
|
||||
for (const tp of team.players) {
|
||||
const multiplier = tp.isCaptain ? 2 : 1;
|
||||
total += tp.player.totalPoints * multiplier;
|
||||
}
|
||||
await db.team.update({ where: { id: team.id }, data: { totalPoints: total } });
|
||||
}
|
||||
}
|
||||
29
app/api/matches/route.ts
Normal file
29
app/api/matches/route.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function GET() {
|
||||
const matches = await db.match.findMany({
|
||||
include: {
|
||||
homeTeam: true,
|
||||
awayTeam: true,
|
||||
gameweek: true,
|
||||
},
|
||||
orderBy: { matchDate: "asc" },
|
||||
});
|
||||
return NextResponse.json(matches);
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const body = await req.json();
|
||||
const match = await db.match.create({
|
||||
data: body,
|
||||
include: { homeTeam: true, awayTeam: true },
|
||||
});
|
||||
return NextResponse.json(match, { status: 201 });
|
||||
}
|
||||
35
app/api/payment/request/route.ts
Normal file
35
app/api/payment/request/route.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import { requestPayment } from "@/lib/zarinpal";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { packageId } = await req.json();
|
||||
const userId = (session.user as any).id;
|
||||
|
||||
const pkg = await db.package.findUnique({ where: { id: packageId } });
|
||||
if (!pkg || !pkg.isActive) return NextResponse.json({ error: "پکیج پیدا نشد" }, { status: 404 });
|
||||
|
||||
const callbackUrl = `${process.env.NEXTAUTH_URL}/api/payment/verify`;
|
||||
|
||||
const result = await requestPayment(pkg.price, `خرید ${pkg.name} - فانتزی جام جهانی`, callbackUrl);
|
||||
|
||||
if (!result.success) return NextResponse.json({ error: result.error }, { status: 400 });
|
||||
|
||||
// ذخیره پرداخت در دیتابیس
|
||||
await db.payment.create({
|
||||
data: {
|
||||
userId,
|
||||
packageId,
|
||||
amount: pkg.price,
|
||||
authority: result.authority,
|
||||
status: "PENDING",
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json({ paymentUrl: result.paymentUrl });
|
||||
}
|
||||
43
app/api/payment/verify/route.ts
Normal file
43
app/api/payment/verify/route.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { verifyPayment } from "@/lib/zarinpal";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const { searchParams } = new URL(req.url);
|
||||
const authority = searchParams.get("Authority");
|
||||
const status = searchParams.get("Status");
|
||||
|
||||
if (!authority) return NextResponse.redirect(new URL("/shop?status=error", req.url));
|
||||
|
||||
const payment = await db.payment.findUnique({
|
||||
where: { authority },
|
||||
include: { package: true, user: true },
|
||||
});
|
||||
|
||||
if (!payment) return NextResponse.redirect(new URL("/shop?status=error", req.url));
|
||||
|
||||
if (status !== "OK") {
|
||||
await db.payment.update({ where: { id: payment.id }, data: { status: "FAILED" } });
|
||||
return NextResponse.redirect(new URL("/shop?status=cancelled", req.url));
|
||||
}
|
||||
|
||||
const result = await verifyPayment(authority, payment.amount);
|
||||
|
||||
if (!result.success) {
|
||||
await db.payment.update({ where: { id: payment.id }, data: { status: "FAILED" } });
|
||||
return NextResponse.redirect(new URL("/shop?status=failed", req.url));
|
||||
}
|
||||
|
||||
// پرداخت موفق - آپدیت بودجه تیم
|
||||
await db.payment.update({
|
||||
where: { id: payment.id },
|
||||
data: { status: "SUCCESS", refId: result.refId },
|
||||
});
|
||||
|
||||
await db.team.updateMany({
|
||||
where: { userId: payment.userId },
|
||||
data: { budget: { increment: payment.package.budgetBonus } },
|
||||
});
|
||||
|
||||
return NextResponse.redirect(new URL(`/shop?status=success&refId=${result.refId}`, req.url));
|
||||
}
|
||||
28
app/api/players/[id]/route.ts
Normal file
28
app/api/players/[id]/route.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function PUT(req: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN") {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
const body = await req.json();
|
||||
const player = await db.player.update({
|
||||
where: { id: params.id },
|
||||
data: body,
|
||||
});
|
||||
return NextResponse.json(player);
|
||||
}
|
||||
|
||||
export async function DELETE(req: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN") {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
await db.player.delete({ where: { id: params.id } });
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
32
app/api/players/route.ts
Normal file
32
app/api/players/route.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const { searchParams } = new URL(req.url);
|
||||
const position = searchParams.get("position");
|
||||
const countryId = searchParams.get("countryId");
|
||||
|
||||
const players = await db.player.findMany({
|
||||
where: {
|
||||
...(position ? { position: position as any } : {}),
|
||||
...(countryId ? { countryId } : {}),
|
||||
},
|
||||
include: { country: true },
|
||||
orderBy: { totalPoints: "desc" },
|
||||
});
|
||||
|
||||
return NextResponse.json(players);
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN") {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
const body = await req.json();
|
||||
const player = await db.player.create({ data: body });
|
||||
return NextResponse.json(player, { status: 201 });
|
||||
}
|
||||
14
app/api/rounds/[id]/activate/route.ts
Normal file
14
app/api/rounds/[id]/activate/route.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function POST(_: NextRequest, { params }: { params: { id: string } }) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
await db.round.updateMany({ data: { isActive: false } });
|
||||
const round = await db.round.update({ where: { id: params.id }, data: { isActive: true } });
|
||||
return NextResponse.json(round);
|
||||
}
|
||||
25
app/api/rounds/route.ts
Normal file
25
app/api/rounds/route.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function GET() {
|
||||
const rounds = await db.round.findMany({ orderBy: { number: "asc" } });
|
||||
return NextResponse.json(rounds);
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN")
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { number, name, deadline } = await req.json();
|
||||
|
||||
const existing = await db.round.findUnique({ where: { number } });
|
||||
if (existing) return NextResponse.json({ error: "این شماره دور قبلاً ثبت شده" }, { status: 400 });
|
||||
|
||||
const round = await db.round.create({
|
||||
data: { number, name, deadline: new Date(deadline) },
|
||||
});
|
||||
return NextResponse.json(round, { status: 201 });
|
||||
}
|
||||
23
app/api/team/captain/route.ts
Normal file
23
app/api/team/captain/route.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function PUT(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { playerId, type } = await req.json();
|
||||
const team = await db.team.findUnique({ where: { userId: (session.user as any).id } });
|
||||
if (!team) return NextResponse.json({ error: "تیم پیدا نشد" }, { status: 404 });
|
||||
|
||||
if (type === "captain") {
|
||||
await db.teamPlayer.updateMany({ where: { teamId: team.id }, data: { isCaptain: false } });
|
||||
await db.teamPlayer.update({ where: { teamId_playerId: { teamId: team.id, playerId } }, data: { isCaptain: true } });
|
||||
} else {
|
||||
await db.teamPlayer.updateMany({ where: { teamId: team.id }, data: { isViceCaptain: false } });
|
||||
await db.teamPlayer.update({ where: { teamId_playerId: { teamId: team.id, playerId } }, data: { isViceCaptain: true } });
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
29
app/api/team/formation/route.ts
Normal file
29
app/api/team/formation/route.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import { getFormationChangeIssues, FORMATIONS } from "@/lib/teamValidation";
|
||||
|
||||
export async function PUT(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { formation } = await req.json();
|
||||
if (!FORMATIONS[formation]) return NextResponse.json({ error: "ترکیب نامعتبر" }, { status: 400 });
|
||||
|
||||
const team = await db.team.findUnique({
|
||||
where: { userId: (session.user as any).id },
|
||||
include: { players: { include: { player: true } } },
|
||||
});
|
||||
if (!team) return NextResponse.json({ error: "تیم پیدا نشد" }, { status: 404 });
|
||||
|
||||
const playerList = team.players.map((tp) => ({ position: tp.player.position, isBench: tp.isBench }));
|
||||
const issues = getFormationChangeIssues(playerList, team.formation, formation);
|
||||
|
||||
if (issues.length > 0) {
|
||||
return NextResponse.json({ error: issues.join(" | "), issues }, { status: 400 });
|
||||
}
|
||||
|
||||
const updated = await db.team.update({ where: { id: team.id }, data: { formation } });
|
||||
return NextResponse.json(updated);
|
||||
}
|
||||
65
app/api/team/players/route.ts
Normal file
65
app/api/team/players/route.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
// اضافه کردن بازیکن به تیم
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { playerId, isBench } = await req.json();
|
||||
const userId = (session.user as any).id;
|
||||
|
||||
const team = await db.team.findUnique({
|
||||
where: { userId },
|
||||
include: { players: { include: { player: true } } },
|
||||
});
|
||||
|
||||
if (!team) return NextResponse.json({ error: "ابتدا تیم بساز" }, { status: 400 });
|
||||
|
||||
const player = await db.player.findUnique({ where: { id: playerId } });
|
||||
if (!player) return NextResponse.json({ error: "بازیکن پیدا نشد" }, { status: 404 });
|
||||
|
||||
// چک بودجه
|
||||
const spent = team.players.reduce((s, tp) => s + tp.player.price, 0);
|
||||
if (spent + player.price > team.budget)
|
||||
return NextResponse.json({ error: "بودجه کافی نیست" }, { status: 400 });
|
||||
|
||||
// چک تعداد (۱۵ نفر: ۱۱ اصلی + ۴ ذخیره)
|
||||
if (team.players.length >= 15)
|
||||
return NextResponse.json({ error: "تیم پر است (حداکثر ۱۵ بازیکن)" }, { status: 400 });
|
||||
|
||||
// چک تکراری
|
||||
const exists = team.players.find((tp) => tp.playerId === playerId);
|
||||
if (exists) return NextResponse.json({ error: "این بازیکن قبلاً انتخاب شده" }, { status: 400 });
|
||||
|
||||
// چک حداکثر ۳ بازیکن از یک تیم ملی
|
||||
const sameCountry = team.players.filter((tp) => tp.player.countryId === player.countryId).length;
|
||||
if (sameCountry >= 3)
|
||||
return NextResponse.json({ error: "حداکثر ۳ بازیکن از یک تیم ملی" }, { status: 400 });
|
||||
|
||||
const tp = await db.teamPlayer.create({
|
||||
data: { teamId: team.id, playerId, isBench: isBench ?? false },
|
||||
});
|
||||
|
||||
return NextResponse.json(tp, { status: 201 });
|
||||
}
|
||||
|
||||
// حذف بازیکن از تیم
|
||||
export async function DELETE(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { playerId } = await req.json();
|
||||
const userId = (session.user as any).id;
|
||||
|
||||
const team = await db.team.findUnique({ where: { userId } });
|
||||
if (!team) return NextResponse.json({ error: "تیم پیدا نشد" }, { status: 404 });
|
||||
|
||||
await db.teamPlayer.delete({
|
||||
where: { teamId_playerId: { teamId: team.id, playerId } },
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
34
app/api/team/route.ts
Normal file
34
app/api/team/route.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function GET() {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const team = await db.team.findUnique({
|
||||
where: { userId: (session.user as any).id },
|
||||
include: {
|
||||
players: {
|
||||
include: { player: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(team);
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { name } = await req.json();
|
||||
const userId = (session.user as any).id;
|
||||
|
||||
const existing = await db.team.findUnique({ where: { userId } });
|
||||
if (existing) return NextResponse.json({ error: "Team already exists" }, { status: 400 });
|
||||
|
||||
const team = await db.team.create({ data: { name, userId } });
|
||||
return NextResponse.json(team, { status: 201 });
|
||||
}
|
||||
33
app/api/team/submit/route.ts
Normal file
33
app/api/team/submit/route.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import { validateTeamComposition } from "@/lib/teamValidation";
|
||||
|
||||
export async function POST() {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const team = await db.team.findUnique({
|
||||
where: { userId: (session.user as any).id },
|
||||
include: { players: { include: { player: true } } },
|
||||
});
|
||||
|
||||
if (!team) return NextResponse.json({ error: "تیم پیدا نشد" }, { status: 404 });
|
||||
|
||||
const playerList = team.players.map((tp) => ({
|
||||
position: tp.player.position,
|
||||
isBench: tp.isBench,
|
||||
}));
|
||||
|
||||
const { valid, errors } = validateTeamComposition(playerList, team.formation);
|
||||
if (!valid) return NextResponse.json({ error: errors.join(" | ") }, { status: 400 });
|
||||
|
||||
// مستقیم ACTIVE میشه - نیازی به تایید ادمین نیست
|
||||
const updated = await db.team.update({
|
||||
where: { id: team.id },
|
||||
data: { status: "ACTIVE" },
|
||||
});
|
||||
|
||||
return NextResponse.json(updated);
|
||||
}
|
||||
16
app/api/user/profile/route.ts
Normal file
16
app/api/user/profile/route.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
|
||||
export async function PUT(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const { name } = await req.json();
|
||||
const user = await db.user.update({
|
||||
where: { id: (session.user as any).id },
|
||||
data: { name },
|
||||
});
|
||||
return NextResponse.json({ name: user.name });
|
||||
}
|
||||
Reference in New Issue
Block a user