feat: private forum groups - Group/GroupMember models, group CRUD API, invite codes, private threads, groups UI pages
This commit is contained in:
@@ -14,8 +14,28 @@ export async function GET(request: NextRequest) {
|
||||
where.categoryId = categoryId;
|
||||
}
|
||||
|
||||
// For group-scoped visibility: if user is authenticated, find which group IDs
|
||||
// they are a member of, so we can include public threads (groupId: null) plus
|
||||
// private threads where they are a member.
|
||||
const auth = await requireAuth(request);
|
||||
let userGroupIds: string[] = [];
|
||||
|
||||
if (auth) {
|
||||
const memberships = await prisma.groupMember.findMany({
|
||||
where: { userId: auth.userId },
|
||||
select: { groupId: true },
|
||||
});
|
||||
userGroupIds = memberships.map((m) => m.groupId);
|
||||
}
|
||||
|
||||
const threads = await prisma.forumThread.findMany({
|
||||
where,
|
||||
where: {
|
||||
...where,
|
||||
OR: [
|
||||
{ groupId: null },
|
||||
{ groupId: { in: userGroupIds } },
|
||||
],
|
||||
},
|
||||
include: {
|
||||
author: {
|
||||
select: { id: true, name: true, isPremium: true, isPro: true },
|
||||
@@ -23,6 +43,9 @@ export async function GET(request: NextRequest) {
|
||||
category: {
|
||||
select: { id: true, name: true, icon: true },
|
||||
},
|
||||
group: {
|
||||
select: { id: true, name: true },
|
||||
},
|
||||
_count: {
|
||||
select: { posts: true },
|
||||
},
|
||||
@@ -65,7 +88,7 @@ export async function POST(request: NextRequest) {
|
||||
);
|
||||
}
|
||||
|
||||
const { title, content, categoryId } = await request.json();
|
||||
const { title, content, categoryId, groupId } = await request.json();
|
||||
|
||||
if (!title || !content || !categoryId) {
|
||||
return NextResponse.json(
|
||||
@@ -86,13 +109,30 @@ export async function POST(request: NextRequest) {
|
||||
);
|
||||
}
|
||||
|
||||
// If groupId is provided, verify user is a member of that group
|
||||
if (groupId) {
|
||||
const membership = await prisma.groupMember.findUnique({
|
||||
where: {
|
||||
groupId_userId: { groupId, userId: user.id },
|
||||
},
|
||||
});
|
||||
|
||||
if (!membership) {
|
||||
return NextResponse.json(
|
||||
{ error: "You are not a member of this group" },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const thread = await prisma.forumThread.create({
|
||||
data: {
|
||||
title,
|
||||
content,
|
||||
categoryId,
|
||||
authorId: user.id,
|
||||
shariahStatus: "pending",
|
||||
groupId: groupId || null,
|
||||
shariahStatus: groupId ? "private" : "pending",
|
||||
},
|
||||
include: {
|
||||
author: {
|
||||
@@ -101,6 +141,9 @@ export async function POST(request: NextRequest) {
|
||||
category: {
|
||||
select: { id: true, name: true, icon: true },
|
||||
},
|
||||
group: {
|
||||
select: { id: true, name: true },
|
||||
},
|
||||
_count: {
|
||||
select: { posts: true },
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user