Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 10x 10x 37x 37x 8x 8x 4x 21x 2x 2x 2x 2x 4x 4x 2x 2x 2x | import { z } from "zod";
import type { SortResultShare } from "@/types";
import type { Database } from "@/lib/db";
import { SortResultShareRepository } from "@/server/repositories/implementations/SortResultShareRepository";
export const CreateShareSchema = z.object({
expiresAt: z.string().datetime().optional(),
});
const UpdateShareSchema = z.object({
status: z.enum(["active", "revoked"]).optional(),
expiresAt: z.string().datetime().optional(),
});
export class ShareController {
constructor(private shareRepo: SortResultShareRepository) {}
static fromDb(db: Database): ShareController {
return new ShareController(new SortResultShareRepository(db));
}
async getByIdForResult(shareId: string, resultId: string): Promise<SortResultShare | null> {
const share = await this.shareRepo.findById(shareId);
return share && share.sortResultId === resultId ? share : null;
}
// Raw token lookup (no validation) — the shared-results page applies its own
// status/expiry/finalized gating. viewSharedResult is the validating variant.
async findByToken(token: string): Promise<SortResultShare | null> {
return this.shareRepo.findByToken(token);
}
async listShares(resultId: string): Promise<SortResultShare[]> {
return this.shareRepo.findByResult(resultId);
}
async getShare(shareId: string): Promise<SortResultShare> {
const share = await this.shareRepo.findById(shareId);
if (!share) {
throw new Error("Share not found");
}
return share;
}
async updateShare(shareId: string, data: unknown): Promise<SortResultShare | null> {
const parsed = UpdateShareSchema.parse(data);
const updateData: Partial<SortResultShare> = {
status: parsed.status,
expiresAt: parsed.expiresAt ? new Date(parsed.expiresAt) : undefined,
};
return this.shareRepo.update(shareId, updateData);
}
// false when the share is already gone.
async revokeShare(shareId: string): Promise<boolean> {
return (await this.shareRepo.update(shareId, { status: "revoked" })) !== null;
}
async viewSharedResult(token: string): Promise<SortResultShare> {
const share = await this.shareRepo.findByToken(token);
if (!share || share.status !== "active") {
throw new Error("Share not found");
}
Iif (share.expiresAt && share.expiresAt < new Date()) {
throw new Error("Share expired");
}
return share;
}
}
|