Skip to content

Commit

Permalink
Deck one time access
Browse files Browse the repository at this point in the history
  • Loading branch information
kubk committed Jan 3, 2024
1 parent 52c95fe commit f2eca25
Show file tree
Hide file tree
Showing 9 changed files with 329 additions and 18 deletions.
159 changes: 159 additions & 0 deletions functions/db/databaseTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,55 @@ export interface Database {
}
]
}
deck_access: {
Row: {
author_id: number
created_at: string
deck_id: number
id: number
is_used: boolean
share_id: string
used_by: number | null
}
Insert: {
author_id: number
created_at?: string
deck_id: number
id?: number
is_used?: boolean
share_id: string
used_by?: number | null
}
Update: {
author_id?: number
created_at?: string
deck_id?: number
id?: number
is_used?: boolean
share_id?: string
used_by?: number | null
}
Relationships: [
{
foreignKeyName: "deck_access_author_id_fkey"
columns: ["author_id"]
referencedRelation: "user"
referencedColumns: ["id"]
},
{
foreignKeyName: "deck_access_deck_id_fkey"
columns: ["deck_id"]
referencedRelation: "deck"
referencedColumns: ["id"]
},
{
foreignKeyName: "deck_access_used_by_fkey"
columns: ["used_by"]
referencedRelation: "user"
referencedColumns: ["id"]
}
]
}
deck_card: {
Row: {
back: string
Expand Down Expand Up @@ -162,6 +211,65 @@ export interface Database {
}
Relationships: []
}
deck_folder: {
Row: {
created_at: string
deck_id: number
folder_id: number
}
Insert: {
created_at?: string
deck_id: number
folder_id: number
}
Update: {
created_at?: string
deck_id?: number
folder_id?: number
}
Relationships: [
{
foreignKeyName: "deck_folder_deck_id_fkey"
columns: ["deck_id"]
referencedRelation: "deck"
referencedColumns: ["id"]
},
{
foreignKeyName: "deck_folder_folder_id_fkey"
columns: ["folder_id"]
referencedRelation: "folder"
referencedColumns: ["id"]
}
]
}
folder: {
Row: {
author_id: number
created_at: string
id: number
title: string
}
Insert: {
author_id: number
created_at?: string
id?: number
title: string
}
Update: {
author_id?: number
created_at?: string
id?: number
title?: string
}
Relationships: [
{
foreignKeyName: "folder_author_id_fkey"
columns: ["author_id"]
referencedRelation: "user"
referencedColumns: ["id"]
}
]
}
notification: {
Row: {
created_at: string
Expand Down Expand Up @@ -259,6 +367,37 @@ export interface Database {
}
]
}
user_folder: {
Row: {
created_at: string
folder_id: number
user_id: number
}
Insert: {
created_at?: string
folder_id: number
user_id: number
}
Update: {
created_at?: string
folder_id?: number
user_id?: number
}
Relationships: [
{
foreignKeyName: "user_folder_folder_id_fkey"
columns: ["folder_id"]
referencedRelation: "folder"
referencedColumns: ["id"]
},
{
foreignKeyName: "user_folder_user_id_fkey"
columns: ["user_id"]
referencedRelation: "user"
referencedColumns: ["id"]
}
]
}
}
Views: {
[_ in never]: never
Expand Down Expand Up @@ -292,6 +431,16 @@ export interface Database {
type: string
}[]
}
get_folder_with_decks: {
Args: {
usr_id: number
}
Returns: {
folder_id: number
folder_title: string
deck_id: number
}[]
}
get_unadded_public_decks: {
Args: {
user_id: number
Expand Down Expand Up @@ -347,6 +496,16 @@ export interface Database {
is_admin: boolean
}[]
}
get_users_with_review_to_notify2: {
Args: Record<PropertyKey, never>
Returns: {
user_id: number
review_count: number
last_reminded_date: string
is_admin: boolean
language_code: string
}[]
}
}
Enums: {
[_ in never]: never
Expand Down
43 changes: 43 additions & 0 deletions functions/deck-accesses.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { createJsonResponse } from "./lib/json-response/create-json-response.ts";
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";

export type DeckAccessesOfDeckResponse = {
accesses: Array<{
used_by: number | null;
share_id: string;
}>;
};

export const onRequest = handleError(async ({ request, env }) => {
const user = await getUser(request, env);
if (!user) return createAuthFailedResponse();

const url = new URL(request.url);
const deckId = url.searchParams.get("deck_id");
if (!deckId) {
return createBadRequestResponse();
}

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);
}

return createJsonResponse<DeckAccessesOfDeckResponse>({
accesses: data,
});
});
81 changes: 67 additions & 14 deletions functions/get-shared-deck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import { createAuthFailedResponse } from "./lib/json-response/create-auth-failed
export type GetSharedDeckResponse = { deck: DeckWithCardsDbType };

export const onRequest = handleError(async ({ env, request }) => {
const user = getUser(request, env);
if (!user) createAuthFailedResponse();
const user = await getUser(request, env);
if (!user) {
return createAuthFailedResponse();
}
const url = new URL(request.url);
const shareId = url.searchParams.get("share_id");
if (!shareId) {
Expand All @@ -26,20 +28,71 @@ export const onRequest = handleError(async ({ env, request }) => {
const envSafe = envSchema.parse(env);
const db = getDatabase(envSafe);

const result = await db
.from("deck")
.select("*, deck_card!deck_card_deck_id_fkey(*)")
.eq("share_id", shareId);
const oneTimeShareLinkResult = await db
.from("deck_access")
.select("deck_id, author_id, used_by")
.eq("share_id", shareId)
.single();

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

if (result.data.length === 0) {
return createNotFoundResponse();
}
let deckId: number;
if (oneTimeShareLinkResult.data) {
deckId = oneTimeShareLinkResult.data.deck_id;
if (oneTimeShareLinkResult.data.author_id !== user.id) {
if (oneTimeShareLinkResult.data.used_by) {
if (oneTimeShareLinkResult.data.used_by !== user.id) {
return createBadRequestResponse("The link has already been used");
}
} else {
const updateResult = await db
.from("deck_access")
.update({ used_by: user.id })
.eq("share_id", shareId)
.single();
if (updateResult.error) {
throw new DatabaseException(updateResult.error);
}
}
}

const stableShareLinkResult = await db
.from("deck")
.select("*, deck_card!deck_card_deck_id_fkey(*)")
.eq("id", deckId)
.single();

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

if (!stableShareLinkResult.data) {
return createNotFoundResponse();
}

return createJsonResponse<GetSharedDeckResponse>({
deck: deckWithCardsSchema.parse(result.data[0]),
});
return createJsonResponse<GetSharedDeckResponse>({
deck: deckWithCardsSchema.parse(stableShareLinkResult.data),
});

} else {
const stableShareLinkResult = await db
.from("deck")
.select("*, deck_card!deck_card_deck_id_fkey(*)")
.eq("share_id", shareId)
.single();

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

if (!stableShareLinkResult.data) {
return createNotFoundResponse();
}

return createJsonResponse<GetSharedDeckResponse>({
deck: deckWithCardsSchema.parse(stableShareLinkResult.data),
});
}
});
9 changes: 9 additions & 0 deletions src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import { DeckCatalogResponse } from "../../functions/catalog-decks.ts";
import { DeckWithCardsResponse } from "../../functions/deck-with-cards.ts";
import { CopyDeckResponse } from "../../functions/duplicate-deck.ts";
import { DeckCategoryResponse } from "../../functions/deck-categories.ts";
import {
DeckAccessesOfDeckResponse
} from "../../functions/deck-accesses.ts";

export const healthRequest = () => {
return request<HealthResponse>("/health");
Expand All @@ -48,6 +51,12 @@ export const addDeckToMineRequest = (body: AddDeckToMineRequest) => {
);
};

export const getDeckAccessesOfDeckRequest = (deckId: number) => {
return request<DeckAccessesOfDeckResponse>(
`/deck-accesses?deck_id=${deckId}`,
);
}

export const apiDuplicateDeckRequest = (deckId: number) => {
return request<CopyDeckResponse>(`/duplicate-deck?deck_id=${deckId}`, "POST");
};
Expand Down
7 changes: 7 additions & 0 deletions src/screens/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { RepeatAllScreen } from "./deck-review/repeat-all-screen.tsx";
import { DeckCatalog } from "./deck-catalog/deck-catalog.tsx";
import { DeckCatalogStoreContextProvider } from "../store/deck-catalog-store-context.tsx";
import { ShareDeck } from "./share-deck/share-deck.tsx";

export const App = observer(() => {
useRestoreFullScreenExpand();
Expand Down Expand Up @@ -60,6 +61,12 @@ export const App = observer(() => {
</DeckFormStoreProvider>
</PreventTelegramSwipeDownClosingIos>
)}
{screenStore.screen.type === "shareDeck" && (
<PreventTelegramSwipeDownClosingIos>
<ShareDeck />
</PreventTelegramSwipeDownClosingIos>
)}

{screenStore.screen.type === "cardQuickAddForm" && (
<PreventTelegramSwipeDownClosingIos>
<QuickAddCardForm />
Expand Down
Loading

0 comments on commit f2eca25

Please sign in to comment.