Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/app/api/admin/invitations/route.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { NextResponse } from "next/server";
import { supabaseAdmin } from "@/lib/supabase/server";
import { checkAdminAuth } from "@/lib/auth/adminAuth";

export async function GET() {
try {
const auth = await checkAdminAuth();
if (!auth.authorized) return auth.error;

const { data, error } = await supabaseAdmin
.from("project_invitation_new")
.select(`
Expand Down Expand Up @@ -61,16 +65,18 @@ const formatted = data.map((row) => ({

export async function POST(req: Request) {
try {
const auth = await checkAdminAuth();
if (!auth.authorized) return auth.error;

const body = await req.json();


const {
invitation_type, // "service_only" | "project"
email,
project_id, //프로젝트 초대일때만사용
project_role, //프로젝트 초대일때만사용
invited_by, // 관리자 user_id
project_id, // 프로젝트 초대일 때만 사용
project_role, // 프로젝트 초대일 때만 사용
} = body;
const invited_by = auth.userId;

//email, 초대타입 필수!
if (!email || !invitation_type) {
Expand Down
6 changes: 4 additions & 2 deletions src/app/api/admin/projects/route.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// src/app/api/admin/projects/route.ts

import { NextResponse } from "next/server";
import { supabaseAdmin } from "@/lib/supabase/server";
import { checkAdminAuth } from "@/lib/auth/adminAuth";

export async function GET() {
try {
const auth = await checkAdminAuth();
if (!auth.authorized) return auth.error;

const { data, error } = await supabaseAdmin
.from("projects")
.select("project_id, project_name")
Expand Down
6 changes: 5 additions & 1 deletion src/app/api/admin/users/role/route.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { NextResponse } from "next/server";
import { supabaseAdmin } from "@/lib/supabase/server"; // service role
import { supabaseAdmin } from "@/lib/supabase/server";
import { checkAdminAuth } from "@/lib/auth/adminAuth";

export async function PATCH(req: Request) {
try {
const auth = await checkAdminAuth();
if (!auth.authorized) return auth.error;

const { user_id, newRole } = await req.json();

if (!user_id || !newRole) {
Expand Down
25 changes: 12 additions & 13 deletions src/app/api/admin/users/route.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
import { supabaseAdmin } from "@/lib/supabase/server";
import { NextResponse } from "next/server";
import { checkAdminAuth } from "@/lib/auth/adminAuth";


//user 정보 조회
export async function GET() {

try {
const {data, error} = await supabaseAdmin
.from("users")
.select(`user_name,email,global_role,user_id`)
const auth = await checkAdminAuth();
if (!auth.authorized) return auth.error;

if (error) {
console.error("Supabase error:", error);
return NextResponse.json({ error: "DB error" }, { status: 500 });
}

return NextResponse.json(data)
const { data, error } = await supabaseAdmin
.from("users")
.select(`user_name,email,global_role,user_id`);

if (error) {
console.error("Supabase error:", error);
return NextResponse.json({ error: "DB error" }, { status: 500 });
}

return NextResponse.json(data);
} catch (error) {
console.error(error);
return NextResponse.json({ error: "Server error" }, { status: 500 });
}
}
}


Expand Down
55 changes: 8 additions & 47 deletions src/app/api/announcements/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NextResponse } from "next/server";
import { getUnifiedAuthUser } from "@/lib/auth/unifiedAuth";
import { supabaseAdmin } from "@/lib/supabase/server";
import { checkAdminAuth } from "@/lib/auth/adminAuth";

// ------------------------------------------------------
// 공통 에러 핸들러
Expand All @@ -25,39 +25,6 @@ async function handleRequest(fn: () => Promise<NextResponse | undefined>) {
}
}

// ------------------------------------------------------
// 권한 체크
// ------------------------------------------------------

export async function checkAdminFnc() {
const authUser = await getUnifiedAuthUser();

if (!authUser.isAuthenticated || !authUser.userId) {
return {
authorized: false,
error: NextResponse.json(
{ error: "로그인이 필요합니다." },
{ status: 401 }
),
};
}

const isAdmin = authUser.role === "admin";
if (!isAdmin) {
return {
authorized: false,
error: NextResponse.json(
{ error: "관리자 권한이 필요합니다." },
{ status: 403 }
),
};
}

const user_id = authUser.userId;

return { authorized: true, user_id };
}

// ------------------------------------------------------
// 공지사항 유효성 검사

Expand Down Expand Up @@ -164,22 +131,17 @@ export async function GET(request: Request) {
export async function POST(request: Request) {
return handleRequest(async () => {
// 로그인, 관리자 여부 확인한 다음
const permission = await checkAdminFnc();
// 둘 중 하나라도 아니라면 false 또는 에러 즉시 반환
if (!permission.authorized) return permission.error;
const auth = await checkAdminAuth();
if (!auth.authorized) return auth.error;

// title, content, is_important를 가져온다
const body = await request.json();
// 입력값 검증
// 제목, 내용 없거나 제목 255자 초과 시 -> 에러
validateNoticeInput(body);

const { data, error } = await supabaseAdmin
.from("notices")
// insert()는 기본적으로 배열 형태의 rows를 받는다고 한다
.insert([
{
user_id: permission.user_id,
user_id: auth.userId,
title: body.title.trim(),
content: body.content.trim(),
is_important: body.is_important || false,
Expand All @@ -201,9 +163,8 @@ export async function POST(request: Request) {
export async function PUT(request: Request) {
return handleRequest(async () => {
// 로그인, 관리자 여부 확인한 다음
const permission = await checkAdminFnc();
// 둘 중 하나라도 아니라면 false 또는 에러 즉시 반환
if (!permission.authorized) return permission.error;
const auth = await checkAdminAuth();
if (!auth.authorized) return auth.error;

// /api/notices/:id 방식으로 추출하거나 쿼리스트링에서 가져와서
// 이 id 기준으로 update가 진행
Expand Down Expand Up @@ -243,8 +204,8 @@ export async function PUT(request: Request) {

export async function DELETE(request: Request) {
return handleRequest(async () => {
const permission = await checkAdminFnc();
if (!permission.authorized) return permission.error;
const auth = await checkAdminAuth();
if (!auth.authorized) return auth.error;

const announcement_id = getAnnouncementId(request);

Expand Down
26 changes: 26 additions & 0 deletions src/lib/auth/adminAuth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { NextResponse } from "next/server";
import { getUnifiedAuthUser } from "@/lib/auth/unifiedAuth";

type AdminAuthResult =
| { authorized: true; userId: string }
| { authorized: false; error: NextResponse };

export async function checkAdminAuth(): Promise<AdminAuthResult> {
const authUser = await getUnifiedAuthUser();

if (!authUser.isAuthenticated || !authUser.userId) {
return {
authorized: false,
error: NextResponse.json({ error: "로그인이 필요합니다." }, { status: 401 }),
};
}

if (authUser.role !== "admin") {
return {
authorized: false,
error: NextResponse.json({ error: "관리자 권한이 필요합니다." }, { status: 403 }),
};
}

return { authorized: true, userId: authUser.userId };
}
Loading