Refactor Study Desk application structure
This commit is contained in:
parent
faaccf8a7e
commit
089439ed90
145 changed files with 8087 additions and 3412 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import { prisma } from "@/lib/db";
|
||||
|
||||
export async function getShareLink(token: string) {
|
||||
return prisma.shareLink.findUnique({
|
||||
const link = await prisma.shareLink.findUnique({
|
||||
where: { id: token },
|
||||
include: {
|
||||
deck: {
|
||||
|
|
@ -47,6 +47,30 @@ export async function getShareLink(token: string) {
|
|||
}
|
||||
},
|
||||
});
|
||||
if (!link) return null;
|
||||
const targets = [link.deck, link.quizSet, link.group].filter(Boolean);
|
||||
const agrees =
|
||||
(link.targetType === "DECK" && Boolean(link.deck)) ||
|
||||
(link.targetType === "QUIZ" && Boolean(link.quizSet)) ||
|
||||
(link.targetType === "GROUP" && Boolean(link.group));
|
||||
if (targets.length !== 1 || !agrees) return null;
|
||||
if (!link.group) return link;
|
||||
return {
|
||||
...link,
|
||||
group: {
|
||||
...link.group,
|
||||
decks: link.group.decks.filter(
|
||||
(deck) =>
|
||||
link.group?.type === "DECK" &&
|
||||
deck.class.slug === link.group.class.slug
|
||||
),
|
||||
quizSets: link.group.quizSets.filter(
|
||||
(quiz) =>
|
||||
link.group?.type === "QUIZ" &&
|
||||
quiz.class.slug === link.group.class.slug
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -54,9 +78,10 @@ export async function getShareLink(token: string) {
|
|||
* metadata without loading every card, question and option.
|
||||
*/
|
||||
export async function getShareLinkMeta(token: string) {
|
||||
return prisma.shareLink.findUnique({
|
||||
const link = await prisma.shareLink.findUnique({
|
||||
where: { id: token },
|
||||
select: {
|
||||
targetType: true,
|
||||
deck: {
|
||||
select: {
|
||||
name: true,
|
||||
|
|
@ -79,17 +104,53 @@ export async function getShareLinkMeta(token: string) {
|
|||
type: true,
|
||||
class: { select: { slug: true, name: true } },
|
||||
decks: {
|
||||
select: { id: true, name: true, description: true, _count: { select: { cards: true } } },
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
description: true,
|
||||
class: { select: { slug: true, name: true } },
|
||||
_count: { select: { cards: true } },
|
||||
},
|
||||
orderBy: { sortOrder: "asc" },
|
||||
},
|
||||
quizSets: {
|
||||
select: { id: true, name: true, description: true, _count: { select: { questions: true } } },
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
description: true,
|
||||
class: { select: { slug: true, name: true } },
|
||||
_count: { select: { questions: true } },
|
||||
},
|
||||
orderBy: { sortOrder: "asc" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!link) return null;
|
||||
const targets = [link.deck, link.quizSet, link.group].filter(Boolean);
|
||||
const agrees =
|
||||
(link.targetType === "DECK" && Boolean(link.deck)) ||
|
||||
(link.targetType === "QUIZ" && Boolean(link.quizSet)) ||
|
||||
(link.targetType === "GROUP" && Boolean(link.group));
|
||||
if (targets.length !== 1 || !agrees) return null;
|
||||
if (!link.group) return link;
|
||||
return {
|
||||
...link,
|
||||
group: {
|
||||
...link.group,
|
||||
decks: link.group.decks.filter(
|
||||
(deck) =>
|
||||
link.group?.type === "DECK" &&
|
||||
deck.class.slug === link.group.class.slug
|
||||
),
|
||||
quizSets: link.group.quizSets.filter(
|
||||
(quiz) =>
|
||||
link.group?.type === "QUIZ" &&
|
||||
quiz.class.slug === link.group.class.slug
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function getShareLinkForContent(targetType: "DECK" | "QUIZ" | "GROUP", contentId: string) {
|
||||
|
|
@ -103,25 +164,47 @@ export async function getShareLinkForContent(targetType: "DECK" | "QUIZ" | "GROU
|
|||
}
|
||||
|
||||
export async function toggleShareLink(targetType: "DECK" | "QUIZ" | "GROUP", contentId: string) {
|
||||
const existing = await getShareLinkForContent(targetType, contentId);
|
||||
|
||||
if (existing) {
|
||||
// Disable sharing
|
||||
await prisma.shareLink.delete({ where: { id: existing.id } });
|
||||
return null;
|
||||
}
|
||||
|
||||
// Enable sharing
|
||||
return prisma.shareLink.create({
|
||||
data: {
|
||||
targetType,
|
||||
deckId: targetType === "DECK" ? contentId : null,
|
||||
quizSetId: targetType === "QUIZ" ? contentId : null,
|
||||
groupId: targetType === "GROUP" ? contentId : null,
|
||||
},
|
||||
return prisma.$transaction(async (transaction) => {
|
||||
const target =
|
||||
targetType === "DECK"
|
||||
? await transaction.deck.findUnique({
|
||||
where: { id: contentId },
|
||||
select: { id: true },
|
||||
})
|
||||
: targetType === "QUIZ"
|
||||
? await transaction.quizSet.findUnique({
|
||||
where: { id: contentId },
|
||||
select: { id: true },
|
||||
})
|
||||
: await transaction.materialGroup.findUnique({
|
||||
where: { id: contentId },
|
||||
select: { id: true },
|
||||
});
|
||||
if (!target) throw new ShareTargetNotFoundError("Share target not found");
|
||||
|
||||
const existing =
|
||||
targetType === "DECK"
|
||||
? await transaction.shareLink.findUnique({ where: { deckId: contentId } })
|
||||
: targetType === "QUIZ"
|
||||
? await transaction.shareLink.findUnique({ where: { quizSetId: contentId } })
|
||||
: await transaction.shareLink.findUnique({ where: { groupId: contentId } });
|
||||
if (existing) {
|
||||
await transaction.shareLink.delete({ where: { id: existing.id } });
|
||||
return null;
|
||||
}
|
||||
return transaction.shareLink.create({
|
||||
data: {
|
||||
targetType,
|
||||
deckId: targetType === "DECK" ? contentId : null,
|
||||
quizSetId: targetType === "QUIZ" ? contentId : null,
|
||||
groupId: targetType === "GROUP" ? contentId : null,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export class ShareTargetNotFoundError extends Error {}
|
||||
|
||||
export async function isContentSharedViaGroup(targetType: "DECK" | "QUIZ", contentId: string) {
|
||||
let groupId: string | null = null;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue