Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
kubk committed Jan 4, 2024
1 parent 69b375d commit 89d8e32
Show file tree
Hide file tree
Showing 31 changed files with 564 additions and 139 deletions.
3 changes: 1 addition & 2 deletions functions/add-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ export const onRequestPost = handleError(async ({ request, env }) => {
const canEdit = await getDeckByIdAndAuthorId(
envSafe,
input.data.deckId,
user.id,
user.is_admin,
user,
);
if (!canEdit) {
return createForbiddenRequestResponse();
Expand Down
53 changes: 53 additions & 0 deletions functions/add-deck-access.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { handleError } from "./lib/handle-error/handle-error.ts";
import { getUser } from "./services/get-user.ts";
import { createAuthFailedResponse } from "./lib/json-response/create-auth-failed-response.ts";
import { createBadRequestResponse } from "./lib/json-response/create-bad-request-response.ts";
import { z } from "zod";
import { getDeckByIdAndAuthorId } from "./db/deck/get-deck-by-id-and-author-id.ts";
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";

const requestSchema = z.object({
deckId: z.number(),
durationDays: z.number().nullable(),
});

const responseSchema = z.object({
share_id: z.string(),
});

export type AddDeckAccessRequest = z.infer<typeof requestSchema>;
export type AddDeckAccessResponse = z.infer<typeof responseSchema>;

export const onRequestPost = handleError(async ({ request, env }) => {
const user = await getUser(request, env);
if (!user) return createAuthFailedResponse();
const input = requestSchema.safeParse(await request.json());
if (!input.success) {
return createBadRequestResponse();
}

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

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

return createJsonResponse<AddDeckAccessResponse>(
responseSchema.parse(createDeckAccessResult),
200,
);
});
9 changes: 6 additions & 3 deletions functions/db/databaseTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,27 +109,30 @@ export interface Database {
author_id: number
created_at: string
deck_id: number
duration_days: number | null
id: number
is_used: boolean
share_id: string
usage_started_at: string | null
used_by: number | null
}
Insert: {
author_id: number
created_at?: string
deck_id: number
duration_days?: number | null
id?: number
is_used?: boolean
share_id: string
usage_started_at?: string | null
used_by?: number | null
}
Update: {
author_id?: number
created_at?: string
deck_id?: number
duration_days?: number | null
id?: number
is_used?: boolean
share_id?: string
usage_started_at?: string | null
used_by?: number | null
}
Relationships: [
Expand Down
30 changes: 30 additions & 0 deletions functions/db/deck-access/create-deck-access-db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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";

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

const createDeckAccessResult = await db
.from("deck_access")
.insert({
deck_id: deckId,
author_id: userId,
share_id: shortUniqueId(),
duration_days: durationDays,
})
.select()
.single();

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

return createDeckAccessResult.data;
};
29 changes: 29 additions & 0 deletions functions/db/deck-access/get-deck-access-by-share-id-db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { DatabaseException } from "../database-exception.ts";
import { getDatabase } from "../get-database.ts";
import { EnvSafe } from "../../env/env-schema.ts";
import { z } from "zod";

const resultSchema = z.object({
deck_id: z.number(),
author_id: z.number(),
used_by: z.number().nullable(),
});

export const getDeckAccessByShareIdDb = async (
envSafe: EnvSafe,
shareId: string,
) => {
const db = getDatabase(envSafe);

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

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

return resultSchema.parse(oneTimeShareLinkResult.data);
};
25 changes: 25 additions & 0 deletions functions/db/deck-access/get-last-deck-accesses-for-deck-db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { DatabaseException } from "../database-exception.ts";
import { getDatabase } from "../get-database.ts";
import { EnvSafe } from "../../env/env-schema.ts";

export const getLastDeckAccessesForDeckDb = async (
envSafe: EnvSafe,
deckId: number,
) => {
const db = getDatabase(envSafe);

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

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

return data;
};
24 changes: 24 additions & 0 deletions functions/db/deck-access/start-using-deck-access-db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { getDatabase } from "../get-database.ts";
import { EnvSafe } from "../../env/env-schema.ts";
import { DatabaseException } from "../database-exception.ts";

export const startUsingDeckAccessDb = async (
envSafe: EnvSafe,
userId: number,
shareId: string,
) => {
const db = getDatabase(envSafe);

const updateResult = await db
.from("deck_access")
.update({
used_by: userId,
usage_started_at: new Date().toISOString(),
})
.eq("share_id", shareId)
.single();

if (updateResult.error) {
throw new DatabaseException(updateResult.error);
}
};
2 changes: 1 addition & 1 deletion functions/db/deck/decks-with-cards-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const deckSchema = z.object({
name: z.string(),
author_id: z.number().nullable(),
description: z.string().nullable(),
share_id: z.string().nullable(),
share_id: z.string(),
is_public: z.boolean(),
speak_locale: z.string().nullable(),
speak_field: deckSpeakField.nullable(),
Expand Down
9 changes: 3 additions & 6 deletions functions/db/deck/get-deck-by-id-and-author-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,16 @@ import { DatabaseException } from "../database-exception.ts";
export const getDeckByIdAndAuthorId = async (
envSafe: EnvSafe,
deckId: number,
userId: number,
isAdmin: boolean,
user: { id: number; is_admin: boolean },
) => {
const db = getDatabase(envSafe);

let query = db.from("deck").select().eq("id", deckId);

if (!isAdmin) {
query = query.eq("author_id", userId);
if (!user.is_admin) {
query = query.eq("author_id", user.id);
}

const canEditDeckResult = await query.single();

if (canEditDeckResult.error) {
throw new DatabaseException(canEditDeckResult.error);
}
Expand Down
8 changes: 4 additions & 4 deletions functions/db/deck/get-deck-with-cards-by-id-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import { getDatabase } from "../get-database.ts";
export const getDeckWithCardsById = async (env: EnvSafe, deckId: number) => {
const db = getDatabase(env);

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

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

return deckWithCardsSchema.parse(data);
return deckWithCardsSchema.parse(stableShareLinkResult.data);
};
24 changes: 24 additions & 0 deletions functions/db/deck/get-deck-with-cards-by-share-id-db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { DatabaseException } from "../database-exception.ts";
import { 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,
) => {
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();

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

return deckWithCardsSchema.parse(data);
};
36 changes: 17 additions & 19 deletions functions/deck-accesses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,23 @@ import { getUser } from "./services/get-user.ts";
import { createAuthFailedResponse } from "./lib/json-response/create-auth-failed-response.ts";
import { handleError } from "./lib/handle-error/handle-error.ts";
import { envSchema } from "./env/env-schema.ts";
import { getDatabase } from "./db/get-database.ts";
import { DatabaseException } from "./db/database-exception.ts";
import { createBadRequestResponse } from "./lib/json-response/create-bad-request-response.ts";
import { getLastDeckAccessesForDeckDb } from "./db/deck-access/get-last-deck-accesses-for-deck-db.ts";
import { z } from "zod";

export type DeckAccessesOfDeckResponse = {
accesses: Array<{
used_by: number | null;
share_id: string;
}>;
};
const responseSchema = z.object({
accesses: z.array(
z.object({
used_by: z.number().nullable(),
share_id: z.string(),
id: z.number(),
created_at: z.string(),
duration_days: z.number().nullable(),
}),
),
});

export type DeckAccessesForDeckTypeDb = z.infer<typeof responseSchema>;

export const onRequest = handleError(async ({ request, env }) => {
const user = await getUser(request, env);
Expand All @@ -25,19 +32,10 @@ export const onRequest = handleError(async ({ request, env }) => {
}

const envSafe = envSchema.parse(env);
const db = getDatabase(envSafe);

const { data, error } = await db
.from("deck_access")
.select("deck_id, author_id, used_by, share_id")
.eq("deck_id", deckId)
.limit(100);

if (error) {
throw new DatabaseException(error);
}
const data = await getLastDeckAccessesForDeckDb(envSafe, Number(deckId));

return createJsonResponse<DeckAccessesOfDeckResponse>({
return createJsonResponse<DeckAccessesForDeckTypeDb>({
accesses: data,
});
});
Loading

0 comments on commit 89d8e32

Please sign in to comment.