feat: POST /auth/workspaces — create an additional collective from an existing account
Until now collectives only existed at registration; an account with a personal workspace had no path to start one. The creator becomes Owner and gets a session scoped to the new workspace.
This commit is contained in:
parent
177ca6eb2b
commit
cbdb8c0f81
18 changed files with 2584 additions and 8 deletions
100
apps/web/src/lib/submissions-types.ts
Normal file
100
apps/web/src/lib/submissions-types.ts
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* Wire shapes for the anonymous submission boxes (apps/api/src/submissions).
|
||||
*
|
||||
* Kept local to the web app so it does not collide with the shared
|
||||
* api-types.ts other builders may be editing in parallel — the same standing
|
||||
* as components/files/types.ts. Hand-synced with submissions.controller.ts
|
||||
* and submissions.service.ts (commit 599a68c).
|
||||
*
|
||||
* JSON note: the API returns `createdAt: Date`, which serialises to an ISO
|
||||
* string on the wire, so every date in here is typed as string.
|
||||
*/
|
||||
|
||||
export type SubmissionKind = "video" | "photo";
|
||||
|
||||
export type SubmissionState = "pending" | "approved" | "rejected";
|
||||
|
||||
/** Moderation queue filter the API accepts (GET ?state=). */
|
||||
export type SubmissionQueueFilter = "pending" | "approved" | "rejected" | "all";
|
||||
|
||||
/** GET /public/submit/:token — public box metadata for the submit page. */
|
||||
export interface SubmissionBoxInfo {
|
||||
id: string;
|
||||
groupId: string;
|
||||
licenseDefault: string;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
/** POST /public/submit/:token → 202 */
|
||||
export interface SubmissionReceiveResult {
|
||||
submissionId: string;
|
||||
state: "pending";
|
||||
}
|
||||
|
||||
/** GET/POST /groups/:groupId/submission-box — token + open switch. */
|
||||
export interface SubmissionBoxConfig {
|
||||
token: string;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
/** GET /groups/:groupId/submissions — contact is licensing-inquiry data that
|
||||
* only this moderation surface ever renders; it is never copied onto assets. */
|
||||
export interface SubmissionRecord {
|
||||
id: string;
|
||||
boxId: string;
|
||||
groupId: string;
|
||||
kind: SubmissionKind;
|
||||
mime: string;
|
||||
sizeBytes: number;
|
||||
sha256: string;
|
||||
license: string;
|
||||
creditName: string | null;
|
||||
contact: string | null;
|
||||
state: SubmissionState;
|
||||
rejectionNote: string | null;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
/** POST /submissions/:id/approve|reject — the decided record plus where it landed. */
|
||||
export type SubmissionDecisionResult = SubmissionRecord & {
|
||||
videoAssetId?: string;
|
||||
groupAssetId?: string;
|
||||
};
|
||||
|
||||
/** The id/name slice of GET /groups/mine the submission surfaces need. */
|
||||
export interface SubmissionGroupSummary {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/* Intake caps, mirroring apps/api/src/submissions/submissions.service.ts. */
|
||||
|
||||
export const SUBMISSION_MAX_VIDEO_BYTES = 200 * 1024 * 1024;
|
||||
export const SUBMISSION_MAX_PHOTO_BYTES = 50 * 1024 * 1024;
|
||||
|
||||
/** The magic-byte window the API reads before deciding a type; shorter files are "unrecognised". */
|
||||
export const SUBMISSION_SNIFF_BYTES = 32;
|
||||
|
||||
/** optionalText() caps in the API's receive path. */
|
||||
export const SUBMISSION_CREDIT_MAX = 100;
|
||||
export const SUBMISSION_CONTACT_MAX = 200;
|
||||
|
||||
/** submissions.rejection_note CHECK constraint (≤ 500). */
|
||||
export const SUBMISSION_NOTE_MAX = 500;
|
||||
|
||||
/** The qualifier every submitter must tick — exact text from the box design. */
|
||||
export const SUBMISSION_LICENSE_TEXT =
|
||||
"I took or own this footage and release it under CC BY-SA 4.0 — it may be shared and remixed with attribution";
|
||||
|
||||
/** Canonical public origin of the web app; overridable for local/dev runs. */
|
||||
export const SUBMIT_APP_ORIGIN = (process.env.NEXT_PUBLIC_APP_ORIGIN ?? "https://app.occupymedia.cc").replace(/\/$/, "");
|
||||
|
||||
/** The link a collective hands out: https://app.occupymedia.cc/submit/<token>. */
|
||||
export function submissionLink(token: string): string {
|
||||
return `${SUBMIT_APP_ORIGIN}/submit/${token}`;
|
||||
}
|
||||
|
||||
/** Size cap per kind — the same rule the API applies after sniffing the bytes. */
|
||||
export function submissionMaxBytes(kind: SubmissionKind): number {
|
||||
return kind === "video" ? SUBMISSION_MAX_VIDEO_BYTES : SUBMISSION_MAX_PHOTO_BYTES;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue