diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 78bf4cb..8cde018 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -3,10 +3,16 @@ import { randomUUID } from "crypto" import { performance } from "perf_hooks" import { pool } from "$lib/server/sql" import { DEVELOPMENT_USER } from "$lib/server/environment" -import type { User } from "$lib/databaseTypes" +import type { User } from "$lib/types" import type { RequestEvent } from "@sveltejs/kit" -const ADMIN_ENDPOINTS = ["/api/templates/.*?"] +type Endpoint = { + path: string + method: "GET" | "PATCH" | "POST" | "PUT" | "DELETE" +} + +const ADMIN_ENDPOINT_PATHS = ["/api/templates/.*?", "/api/dsm/.*?"] +const ADMIN_SPECIFIC_ENDPOINTS: Endpoint[] = [{ path: "/api/dsm", method: "POST" }] export async function handle({ event, resolve }) { const requestId = randomUUID() @@ -87,8 +93,14 @@ export async function getOrInsertUser(email: string) { } function isUserAuthorized(event: RequestEvent>, string | null>, user: User) { - if (!user.is_admin && ADMIN_ENDPOINTS.some(endpoint => event.request.url.match(endpoint))) { + if (!user.is_admin && ADMIN_ENDPOINT_PATHS.some(path => event.request.url.match(path))) { return false } + + for (const endpoint of ADMIN_SPECIFIC_ENDPOINTS) { + if (!user.is_admin && event.request.url.match(endpoint.path) && event.request.method === endpoint.method) { + return false + } + } return true } diff --git a/src/lib/components/Navigation.svelte b/src/lib/components/Navigation.svelte index 5eebcc5..8f960e9 100644 --- a/src/lib/components/Navigation.svelte +++ b/src/lib/components/Navigation.svelte @@ -4,6 +4,7 @@ const drawerStore = getDrawerStore() const pages = [ + { name: "DSM Codes", href: "/dsm" }, { name: "Intake", href: "/intake" }, { name: "Summarization", href: "/summarization" }, { name: "Templates", href: "/templates" } diff --git a/src/lib/icons/XIcon.svelte b/src/lib/icons/XIcon.svelte new file mode 100644 index 0000000..0e63f03 --- /dev/null +++ b/src/lib/icons/XIcon.svelte @@ -0,0 +1 @@ + diff --git a/src/lib/markdownRenderers/OrderedListItem.svelte b/src/lib/markdownRenderers/OrderedListItem.svelte deleted file mode 100644 index 73e8356..0000000 --- a/src/lib/markdownRenderers/OrderedListItem.svelte +++ /dev/null @@ -1,15 +0,0 @@ -
-
  • - -
  • -
    - - diff --git a/src/lib/markdownRenderers/UnorderedListItem.svelte b/src/lib/markdownRenderers/UnorderedListItem.svelte deleted file mode 100644 index 4daaad0..0000000 --- a/src/lib/markdownRenderers/UnorderedListItem.svelte +++ /dev/null @@ -1,15 +0,0 @@ -
    -
  • - -
  • -
    - - diff --git a/src/lib/server/sql.ts b/src/lib/server/sql.ts index 88fb528..bab967f 100644 --- a/src/lib/server/sql.ts +++ b/src/lib/server/sql.ts @@ -13,16 +13,14 @@ const config = { export const pool = new Pool(config) -export interface SqlTemplateModel { +export type SqlTemplateSchema = { id: number text: string parent_id: number | null - time_created: string - time_updated: string } -export interface SqlTemplateSchema { +export type SqlDsmCodeSchema = { id: number - text: string - parent_id: number | null + code: string + label: string } diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 814f067..edfbba6 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -18,10 +18,12 @@ } from "@skeletonlabs/skeleton" import "../app.postcss" import ModalSearchDecisionTree from "./templates/TemplatesDirectory/ModalSearchDecisionTree.svelte" + import ModalDsmForm from "./dsm/ModalDsmForm.svelte" initializeStores() storePopup.set({ computePosition, autoUpdate, flip, shift, offset, arrow }) const modalRegistry: Record = { + dsmForm: { ref: ModalDsmForm }, markdown: { ref: ModalMarkdown }, searchDecisionTree: { ref: ModalSearchDecisionTree } } diff --git a/src/routes/api/dsm/+server.ts b/src/routes/api/dsm/+server.ts new file mode 100644 index 0000000..87611e7 --- /dev/null +++ b/src/routes/api/dsm/+server.ts @@ -0,0 +1,42 @@ +import { logger } from "$lib/server/logging" +import { pool, type SqlDsmCodeSchema } from "$lib/server/sql" + +export async function GET() { + logger.info("Getting all DSM codes") + return await pool + .connect() + .then(async client => { + const result = await client.query("SELECT * FROM dsm_codes") + client.release() + return result.rows as SqlDsmCodeSchema[] + }) + .then(rows => { + return new Response(JSON.stringify(rows), { headers: { "Content-Type": "application/json" } }) + }) + .catch(error => { + logger.error("Error getting all templates:", error) + return new Response(null, { status: 500 }) + }) +} + +export async function POST({ request }) { + logger.info("Posting a new DSM code") + const { code, label } = await request.json() + return await pool + .connect() + .then(async client => { + const result = await client.query({ + text: "INSERT INTO dsm_codes (code, label) VALUES ($1, $2) RETURNING id, code, label", + values: [code, label] + }) + client.release() + return result.rows as SqlDsmCodeSchema[] + }) + .then(rows => { + return new Response(JSON.stringify(rows[0]), { headers: { "Content-Type": "application/json" } }) + }) + .catch(error => { + logger.error("Error getting all templates:", error) + return new Response(null, { status: 500 }) + }) +} diff --git a/src/routes/api/dsm/[id]/+server.ts b/src/routes/api/dsm/[id]/+server.ts new file mode 100644 index 0000000..25efec9 --- /dev/null +++ b/src/routes/api/dsm/[id]/+server.ts @@ -0,0 +1,40 @@ +import { logger } from "$lib/server/logging" +import { pool, type SqlDsmCodeSchema } from "$lib/server/sql" + +export async function PUT({ params, request }) { + const id = params.id + const { code, label } = await request.json() + logger.info("Editting DSM Code") + return await pool + .connect() + .then(async client => { + const result = await client.query({ + text: "UPDATE dsm_codes SET code = $1, label = $2 WHERE id = $3", + values: [code, label, id] + }) + client.release() + return result.rows as SqlDsmCodeSchema[] + }) + .then(rows => { + return new Response(JSON.stringify(rows), { headers: { "Content-Type": "application/json" } }) + }) + .catch(error => { + logger.error("Error getting all dsm codes:", error) + return new Response(null, { status: 500 }) + }) +} + +export async function DELETE({ params }) { + return await pool + .connect() + .then(async client => { + await client.query({ text: "DELETE FROM dsm_codes WHERE id = $1", values: [params.id] }) + }) + .then(() => { + return new Response(null) + }) + .catch(error => { + logger.error("Error deleting all dsm code:", error) + return new Response(null, { status: 500 }) + }) +} diff --git a/src/routes/dsm/+page.svelte b/src/routes/dsm/+page.svelte new file mode 100644 index 0000000..1e06072 --- /dev/null +++ b/src/routes/dsm/+page.svelte @@ -0,0 +1,136 @@ + + + + {#if isAdmin} + + {/if} + + +
    + + + +
    + + + {#each selected as selection} + + {/each} + + +
    +
      + {#each autoCompeleteOptions as option} +
    • + {#if isAdmin} + + + + + {/if} + +
    • + {/each} +
    +
    diff --git a/src/routes/dsm/CreateButton.svelte b/src/routes/dsm/CreateButton.svelte new file mode 100644 index 0000000..f81eff2 --- /dev/null +++ b/src/routes/dsm/CreateButton.svelte @@ -0,0 +1,47 @@ + + + diff --git a/src/routes/dsm/DeleteButton.svelte b/src/routes/dsm/DeleteButton.svelte new file mode 100644 index 0000000..a43ff28 --- /dev/null +++ b/src/routes/dsm/DeleteButton.svelte @@ -0,0 +1,46 @@ + + + diff --git a/src/routes/dsm/EditButton.svelte b/src/routes/dsm/EditButton.svelte new file mode 100644 index 0000000..88c79f2 --- /dev/null +++ b/src/routes/dsm/EditButton.svelte @@ -0,0 +1,46 @@ + + + diff --git a/src/routes/dsm/ModalDsmForm.svelte b/src/routes/dsm/ModalDsmForm.svelte new file mode 100644 index 0000000..db656a5 --- /dev/null +++ b/src/routes/dsm/ModalDsmForm.svelte @@ -0,0 +1,32 @@ + + +{#if $modalStore[0]} +
    +
    + + + +
    +
    +{/if} diff --git a/src/routes/dsm/utils.ts b/src/routes/dsm/utils.ts new file mode 100644 index 0000000..ddc75fa --- /dev/null +++ b/src/routes/dsm/utils.ts @@ -0,0 +1,17 @@ +export function indexForNewItemInSortedList(list: string[], item: string) { + let left = 0 + let right = list.length - 1 + + while (left <= right) { + const mid = Math.floor((right + left) / 2) + const direction = list[mid].localeCompare(item) + if (direction === 0) { + return mid + } else if (direction === -1) { + left = mid + 1 + } else { + right = mid - 1 + } + } + return left +} diff --git a/src/routes/templates/+page.svelte b/src/routes/templates/+page.svelte index 9f8af15..77ea0b3 100644 --- a/src/routes/templates/+page.svelte +++ b/src/routes/templates/+page.svelte @@ -1,13 +1,12 @@