Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Folder sharing #39

Merged
merged 2 commits into from
Jan 10, 2024
Merged
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
32 changes: 22 additions & 10 deletions functions/add-deck-access.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ import { envSchema } from "./env/env-schema.ts";
import { createForbiddenRequestResponse } from "./lib/json-response/create-forbidden-request-response.ts";
import { createJsonResponse } from "./lib/json-response/create-json-response.ts";
import { createDeckAccessDb } from "./db/deck-access/create-deck-access-db.ts";
import { getFolderByIdAndAuthorId } from "./db/folder/get-folder-by-id-and-author-id.ts";

const requestSchema = z.object({
deckId: z.number(),
deckId: z.number().nullable(),
folderId: z.number().nullable(),
durationDays: z.number().nullable(),
type: z.enum(["deck", "folder"]),
});

const responseSchema = z.object({
Expand All @@ -30,20 +33,29 @@ export const onRequestPost = handleError(async ({ request, env }) => {
}

const envSafe = envSchema.parse(env);
const canEdit = await getDeckByIdAndAuthorId(
envSafe,
input.data.deckId,
user,
);
if (!canEdit) {
return createForbiddenRequestResponse();
if (input.data.deckId) {
if (!(await getDeckByIdAndAuthorId(envSafe, input.data.deckId, user))) {
return createForbiddenRequestResponse();
}
}
if (input.data.folderId) {
if (!(await getFolderByIdAndAuthorId(envSafe, input.data.folderId, user))) {
return createForbiddenRequestResponse();
}
}

// Only 1 option from deckId or folderId should be provided
if (
(input.data.folderId && input.data.deckId) ||
(!input.data.folderId && !input.data.deckId)
) {
return createBadRequestResponse();
}

const createDeckAccessResult = await createDeckAccessDb(
envSafe,
user.id,
input.data.deckId,
input.data.durationDays,
input.data,
);

return createJsonResponse<AddDeckAccessResponse>(
Expand Down
3 changes: 3 additions & 0 deletions functions/db/custom-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Database } from "./databaseTypes.ts";

export type DeckAccessType = Database["public"]["Enums"]["deck_access_type"];
24 changes: 20 additions & 4 deletions functions/db/databaseTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,33 +108,39 @@ export interface Database {
Row: {
author_id: number
created_at: string
deck_id: number
deck_id: number | null
duration_days: number | null
folder_id: number | null
id: number
processed_at: string | null
share_id: string
type: Database["public"]["Enums"]["deck_access_type"]
usage_started_at: string | null
used_by: number | null
}
Insert: {
author_id: number
created_at?: string
deck_id: number
deck_id?: number | null
duration_days?: number | null
folder_id?: number | null
id?: number
processed_at?: string | null
share_id: string
type?: Database["public"]["Enums"]["deck_access_type"]
usage_started_at?: string | null
used_by?: number | null
}
Update: {
author_id?: number
created_at?: string
deck_id?: number
deck_id?: number | null
duration_days?: number | null
folder_id?: number | null
id?: number
processed_at?: string | null
share_id?: string
type?: Database["public"]["Enums"]["deck_access_type"]
usage_started_at?: string | null
used_by?: number | null
}
Expand All @@ -151,6 +157,12 @@ export interface Database {
referencedRelation: "deck"
referencedColumns: ["id"]
},
{
foreignKeyName: "deck_access_folder_id_fkey"
columns: ["folder_id"]
referencedRelation: "folder"
referencedColumns: ["id"]
},
{
foreignKeyName: "deck_access_used_by_fkey"
columns: ["used_by"]
Expand Down Expand Up @@ -254,20 +266,23 @@ export interface Database {
created_at: string
description: string | null
id: number
share_id: string
title: string
}
Insert: {
author_id: number
created_at?: string
description?: string | null
id?: number
share_id: string
title: string
}
Update: {
author_id?: number
created_at?: string
description?: string | null
id?: number
share_id?: string
title?: string
}
Relationships: [
Expand Down Expand Up @@ -476,6 +491,7 @@ export interface Database {
folder_id: number
folder_title: string
folder_description: string
folder_share_id: string
folder_author_id: number
deck_id: number
}[]
Expand Down Expand Up @@ -547,7 +563,7 @@ export interface Database {
}
}
Enums: {
[_ in never]: never
deck_access_type: "deck" | "folder"
}
CompositeTypes: {
[_ in never]: never
Expand Down
15 changes: 11 additions & 4 deletions functions/db/deck-access/create-deck-access-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,29 @@ import { EnvSafe } from "../../env/env-schema.ts";
import { shortUniqueId } from "../../lib/short-unique-id/short-unique-id.ts";
import { DatabaseException } from "../database-exception.ts";
import { getDatabase } from "../get-database.ts";
import { DeckAccessType } from "../custom-types.ts";

export const createDeckAccessDb = async (
envSafe: EnvSafe,
userId: number,
deckId: number,
durationDays: number | null,
body: {
deckId: number | null;
folderId: number | null;
durationDays: number | null;
type: DeckAccessType;
},
) => {
const db = getDatabase(envSafe);

const createDeckAccessResult = await db
.from("deck_access")
.insert({
deck_id: deckId,
deck_id: body.deckId,
folder_id: body.folderId,
author_id: userId,
share_id: shortUniqueId(),
duration_days: durationDays,
duration_days: body.durationDays,
type: body.type,
})
.select()
.single();
Expand Down
6 changes: 4 additions & 2 deletions functions/db/deck-access/get-deck-access-by-share-id-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { EnvSafe } from "../../env/env-schema.ts";
import { z } from "zod";

const resultSchema = z.object({
deck_id: z.number(),
deck_id: z.number().nullable(),
folder_id: z.number().nullable(),
author_id: z.number(),
used_by: z.number().nullable(),
processed_at: z.string().nullable(),
type: z.enum(["folder", "deck"]),
});

type GetDeckAccessByShareIdDbResultType = z.infer<typeof resultSchema>;
Expand All @@ -20,7 +22,7 @@ export const getDeckAccessByShareIdDb = async (

const oneTimeShareLinkResult = await db
.from("deck_access")
.select("deck_id, author_id, used_by, processed_at")
.select("deck_id, author_id, used_by, processed_at, folder_id, type")
.eq("share_id", shareId)
.maybeSingle();

Expand Down
13 changes: 10 additions & 3 deletions functions/db/deck-access/get-last-deck-accesses-for-deck-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,26 @@ export type DeckAccessesForDeckTypeDb = z.infer<typeof responseSchema>;

export const getLastDeckAccessesForDeckDb = async (
envSafe: EnvSafe,
deckId: number,
filters: { deckId: number } | { folderId: number },
): Promise<DeckAccessesForDeckTypeDb> => {
const db = getDatabase(envSafe);

const { data, error } = await db
const query = db
.from("deck_access")
.select(
"deck_id, author_id, used_by, share_id, id, created_at, duration_days, user:used_by (id, username, first_name, last_name)",
)
.eq("deck_id", deckId)
.order("created_at", { ascending: false })
.limit(100);

if ("deckId" in filters) {
query.eq("deck_id", filters.deckId);
}
if ("folderId" in filters) {
query.eq("folder_id", filters.folderId);
}

const { data, error } = await query;
if (error) {
throw new DatabaseException(error);
}
Expand Down
2 changes: 1 addition & 1 deletion functions/db/deck/get-deck-by-id-and-author-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const getDeckByIdAndAuthorId = async (
query = query.eq("author_id", user.id);
}

const canEditDeckResult = await query.single();
const canEditDeckResult = await query.maybeSingle();
if (canEditDeckResult.error) {
throw new DatabaseException(canEditDeckResult.error);
}
Expand Down
11 changes: 7 additions & 4 deletions functions/db/deck/get-deck-with-cards-by-share-id-db.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import { DatabaseException } from "../database-exception.ts";
import { deckWithCardsSchema } from "./decks-with-cards-schema.ts";
import {
DeckWithCardsDbType,
deckWithCardsSchema,
} from "./decks-with-cards-schema.ts";
import { EnvSafe } from "../../env/env-schema.ts";
import { getDatabase } from "../get-database.ts";

export const getDeckWithCardsByShareIdDb = async (
env: EnvSafe,
shareId: string,
) => {
): Promise<DeckWithCardsDbType | null> => {
const db = getDatabase(env);

const { data, error } = await db
.from("deck")
.select("*, deck_card!deck_card_deck_id_fkey(*)")
.eq("share_id", shareId)
.limit(1)
.single();
.maybeSingle();

if (error) {
throw new DatabaseException(error);
}

return deckWithCardsSchema.parse(data);
return data ? deckWithCardsSchema.parse(data) : null;
};
26 changes: 26 additions & 0 deletions functions/db/deck/get-many-decks-with-cards-db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { DatabaseException } from "../database-exception.ts";
import {
decksWithCardsSchema,
DeckWithCardsDbType,
} from "./decks-with-cards-schema.ts";
import { getDatabase } from "../get-database.ts";
import { EnvSafe } from "../../env/env-schema.ts";

export const getManyDecksWithCardsDb = async (
env: EnvSafe,
deckIds: number[],
): Promise<DeckWithCardsDbType[]> => {
const db = getDatabase(env);

const { data, error } = await db
.from("deck")
.select("*, deck_card!deck_card_deck_id_fkey(*)")
.in("id", deckIds)
.order("id", { ascending: false });

if (error) {
throw new DatabaseException(error);
}

return decksWithCardsSchema.parse(data);
};
24 changes: 4 additions & 20 deletions functions/db/deck/get-my-decks-with-cards-db.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { EnvSafe } from "../../env/env-schema.ts";
import { getDatabase } from "../get-database.ts";
import { DatabaseException } from "../database-exception.ts";
import {
decksWithCardsSchema,
DeckWithCardsDbType,
} from "./decks-with-cards-schema.ts";
import { DeckWithCardsDbType } from "./decks-with-cards-schema.ts";
import { z } from "zod";
import { getManyDecksWithCardsDb } from "./get-many-decks-with-cards-db.ts";

export const getMyDecksWithCardsDb = async (
env: EnvSafe,
Expand All @@ -22,23 +20,9 @@ export const getMyDecksWithCardsDb = async (
}

const deckIds = z
.array(
z.object({
id: z.number(),
}),
)
.array(z.object({ id: z.number() }))
.transform((list) => list.map((item) => item.id))
.parse(getUserDeckIdsResult.data);

const { data, error } = await db
.from("deck")
.select("*, deck_card!deck_card_deck_id_fkey(*)")
.in("id", deckIds)
.order("id", { ascending: false });

if (error) {
throw new DatabaseException(error);
}

return decksWithCardsSchema.parse(data);
return getManyDecksWithCardsDb(env, deckIds);
};
8 changes: 6 additions & 2 deletions functions/db/deck/is-user-deck-exists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ export const isUserDeckExists = async (
) => {
const db = getDatabase(envSafe);

const userDeck = await db.from("user_deck").select().match(body);
const userDeck = await db
.from("user_deck")
.select()
.match(body)
.maybeSingle();

if (userDeck.error) {
throw new DatabaseException(userDeck.error);
}

return userDeck.data.length ? userDeck.data[0] : null;
return userDeck.data ? userDeck.data : null;
};
Loading