From aada965ff40f5f6cf2ddf3aa7e142fef475791ea Mon Sep 17 00:00:00 2001 From: beo3000 Date: Fri, 27 Feb 2026 18:17:59 +0100 Subject: [PATCH] upd calender impotz --- ka-note/.env.example | 2 + ka-note/VERSION | 2 +- .../src/lib/components/JournalView.svelte | 72 +- ka-note/server/drizzle/0014_api_key_email.sql | 1 + .../server/drizzle/0014_classy_power_pack.sql | 1 + .../server/drizzle/meta/0014_snapshot.json | 1153 +++++++++++++++++ ka-note/server/drizzle/meta/_journal.json | 7 + ka-note/server/ka-note.db-shm | Bin 32768 -> 32768 bytes ka-note/server/ka-note.db-wal | Bin 700432 -> 815792 bytes ka-note/server/src/db/schema.ts | 1 + ka-note/server/src/middleware/auth.ts | 2 +- ka-note/server/src/routes/api-keys.ts | 3 +- ka-note/server/src/routes/calendar.ts | 2 +- 13 files changed, 1234 insertions(+), 12 deletions(-) create mode 100644 ka-note/server/drizzle/0014_api_key_email.sql create mode 100644 ka-note/server/drizzle/0014_classy_power_pack.sql create mode 100644 ka-note/server/drizzle/meta/0014_snapshot.json diff --git a/ka-note/.env.example b/ka-note/.env.example index 7c52c8f..1592e2f 100644 --- a/ka-note/.env.example +++ b/ka-note/.env.example @@ -12,6 +12,8 @@ AZURE_TENANT_ID= # App Registration → Certificates & secrets → New client secret AZURE_GRAPH_CLIENT_ID= AZURE_GRAPH_CLIENT_SECRET= +# Fallback email when auth provides no email (e.g. API key login) +CALENDAR_USER_EMAIL= # ── CLIENT (Vite — copy relevant lines to client/.env) ─────────────────────── # VITE_AZURE_CLIENT_ID= diff --git a/ka-note/VERSION b/ka-note/VERSION index 5961097..27e2dba 100644 --- a/ka-note/VERSION +++ b/ka-note/VERSION @@ -1 +1 @@ -1.1.81 \ No newline at end of file +1.1.84 \ No newline at end of file diff --git a/ka-note/client/src/lib/components/JournalView.svelte b/ka-note/client/src/lib/components/JournalView.svelte index caae225..e311923 100644 --- a/ka-note/client/src/lib/components/JournalView.svelte +++ b/ka-note/client/src/lib/components/JournalView.svelte @@ -16,7 +16,7 @@ import { useUnsavedGuard } from '$lib/utils/unsavedGuard.svelte'; import EventCard from './EventCard.svelte'; import { eventsForDate } from '$lib/stores/agenda'; - import { createEvent, updateEventNotes } from '$lib/db/repositories'; + import { createEvent, updateEventNotes, upsertContext } from '$lib/db/repositories'; import { fetchCalendarEvents, type CalendarEvent } from '$lib/utils/calendarApi'; import { extractMentionName, quoteMention } from '$lib/actions/mentionCore'; import type { PersonMeta } from '@ka-note/shared'; @@ -222,6 +222,11 @@ let calendarError = $state(null); let calendarEvents = $state([]); + // Unknown-persons dialog (shown after calendar import) + interface UnknownAttendee { name: string; email: string; selected: boolean; } + let unknownDialogOpen = $state(false); + let unknownAttendees = $state([]); + async function openCalendarPicker() { if (!showNewEventForm) openNewEventForm(); calendarLoading = true; @@ -241,23 +246,48 @@ newEventTitle = ev.subject; newEventTime = ev.start; pendingBodyPreview = ev.bodyPreview; + calendarPickerOpen = false; const persons = await db.contexts .filter(c => !c.deletedAt && c.type === 'person') .toArray(); - const mentions = ev.attendees.map(att => { + + const mentions: string[] = []; + const unknowns: UnknownAttendee[] = []; + + for (const att of ev.attendees) { const match = persons.find( p => (p.meta as PersonMeta | null)?.email?.toLowerCase() === att.email.toLowerCase() ); if (match) { - return quoteMention('@', extractMentionName(match)); + mentions.push(quoteMention('@', extractMentionName(match))); + } else { + const cleaned = att.name.replace(/\s*\(.*?\)\s*$/, '').trim(); + mentions.push(quoteMention('@', cleaned)); + if (att.email) unknowns.push({ name: cleaned, email: att.email, selected: true }); } - // Strip company suffix e.g. "Lars Leifer (KRAH)" → "Lars Leifer" - const cleaned = att.name.replace(/\s*\(.*?\)\s*$/, '').trim(); - return quoteMention('@', cleaned); - }); + } + newEventParticipants = mentions.join(' '); - calendarPickerOpen = false; + + if (unknowns.length > 0) { + unknownAttendees = unknowns; + unknownDialogOpen = true; + } + } + + async function confirmUnknownPersons() { + for (const u of unknownAttendees.filter(u => u.selected)) { + const slug = u.name.toLowerCase().replace(/\s+/g, '-'); + await upsertContext({ + id: `u-${slug}`, + name: `Person ${u.name}`, + type: 'person', + sortOrder: 99, + meta: { fullName: u.name, email: u.email, phone: '', duSince: '' } satisfies PersonMeta, + }); + } + unknownDialogOpen = false; } const dateEvents = $derived(eventsForDate(selectedDate)); @@ -468,6 +498,32 @@ {/if} {/if} + + {#if unknownDialogOpen} +
+

Unbekannte Teilnehmer anlegen?

+
+ {#each unknownAttendees as u} + + {/each} +
+
+ + +
+
+ {/if} + {#each $dateEvents ?? [] as event (event.id)}
diff --git a/ka-note/server/drizzle/0014_api_key_email.sql b/ka-note/server/drizzle/0014_api_key_email.sql new file mode 100644 index 0000000..ce6e942 --- /dev/null +++ b/ka-note/server/drizzle/0014_api_key_email.sql @@ -0,0 +1 @@ +ALTER TABLE `api_keys` ADD `email` text NOT NULL DEFAULT ''; diff --git a/ka-note/server/drizzle/0014_classy_power_pack.sql b/ka-note/server/drizzle/0014_classy_power_pack.sql new file mode 100644 index 0000000..60d6646 --- /dev/null +++ b/ka-note/server/drizzle/0014_classy_power_pack.sql @@ -0,0 +1 @@ +ALTER TABLE `api_keys` ADD `email` text DEFAULT '' NOT NULL; \ No newline at end of file diff --git a/ka-note/server/drizzle/meta/0014_snapshot.json b/ka-note/server/drizzle/meta/0014_snapshot.json new file mode 100644 index 0000000..208a79f --- /dev/null +++ b/ka-note/server/drizzle/meta/0014_snapshot.json @@ -0,0 +1,1153 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "690dfff1-a52a-4c26-968c-c540deaf5871", + "prevId": "d8154271-c91d-4ad4-b288-7c09662cd1dc", + "tables": { + "ai_locks": { + "name": "ai_locks", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "locked_at": { + "name": "locked_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "api_keys": { + "name": "api_keys", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "key_hash": { + "name": "key_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_used_at": { + "name": "last_used_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "api_keys_key_hash_unique": { + "name": "api_keys_key_hash_unique", + "columns": [ + "key_hash" + ], + "isUnique": true + }, + "api_keys_user_id_idx": { + "name": "api_keys_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "api_keys_key_hash_idx": { + "name": "api_keys_key_hash_idx", + "columns": [ + "key_hash" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "contexts": { + "name": "contexts", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "meta": { + "name": "meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "archived_at": { + "name": "archived_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_favorite": { + "name": "is_favorite", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "purged_at": { + "name": "purged_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + } + }, + "indexes": { + "contexts_updated_at_idx": { + "name": "contexts_updated_at_idx", + "columns": [ + "updated_at" + ], + "isUnique": false + }, + "contexts_user_id_idx": { + "name": "contexts_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "contexts_id_user_id_pk": { + "columns": [ + "id", + "user_id" + ], + "name": "contexts_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "history_entries": { + "name": "history_entries", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "topic_id": { + "name": "topic_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "date": { + "name": "date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "text": { + "name": "text", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "linked_context_id": { + "name": "linked_context_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "done_at": { + "name": "done_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "wiedervorlage_date": { + "name": "wiedervorlage_date", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "wiedervorlage_resolved_at": { + "name": "wiedervorlage_resolved_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_private": { + "name": "is_private", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "purged_at": { + "name": "purged_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + } + }, + "indexes": { + "history_entries_updated_at_idx": { + "name": "history_entries_updated_at_idx", + "columns": [ + "updated_at" + ], + "isUnique": false + }, + "history_entries_topic_id_idx": { + "name": "history_entries_topic_id_idx", + "columns": [ + "topic_id" + ], + "isUnique": false + }, + "history_entries_user_id_idx": { + "name": "history_entries_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "history_entries_topic_id_user_id_topics_id_user_id_fk": { + "name": "history_entries_topic_id_user_id_topics_id_user_id_fk", + "tableFrom": "history_entries", + "tableTo": "topics", + "columnsFrom": [ + "topic_id", + "user_id" + ], + "columnsTo": [ + "id", + "user_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "history_entries_id_user_id_pk": { + "columns": [ + "id", + "user_id" + ], + "name": "history_entries_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "image_blobs": { + "name": "image_blobs", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "data": { + "name": "data", + "type": "blob", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + } + }, + "indexes": { + "image_blobs_user_id_idx": { + "name": "image_blobs_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "image_blobs_content_hash_idx": { + "name": "image_blobs_content_hash_idx", + "columns": [ + "content_hash" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "image_blobs_id_user_id_pk": { + "columns": [ + "id", + "user_id" + ], + "name": "image_blobs_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "notebooks": { + "name": "notebooks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "context_id": { + "name": "context_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_private": { + "name": "is_private", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "is_favorite": { + "name": "is_favorite", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "purged_at": { + "name": "purged_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + } + }, + "indexes": { + "notebooks_updated_at_idx": { + "name": "notebooks_updated_at_idx", + "columns": [ + "updated_at" + ], + "isUnique": false + }, + "notebooks_user_id_idx": { + "name": "notebooks_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "notebooks_id_user_id_pk": { + "columns": [ + "id", + "user_id" + ], + "name": "notebooks_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "page_notebooks": { + "name": "page_notebooks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "page_id": { + "name": "page_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "notebook_id": { + "name": "notebook_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "purged_at": { + "name": "purged_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + } + }, + "indexes": { + "page_notebooks_updated_at_idx": { + "name": "page_notebooks_updated_at_idx", + "columns": [ + "updated_at" + ], + "isUnique": false + }, + "page_notebooks_page_id_idx": { + "name": "page_notebooks_page_id_idx", + "columns": [ + "page_id" + ], + "isUnique": false + }, + "page_notebooks_notebook_id_idx": { + "name": "page_notebooks_notebook_id_idx", + "columns": [ + "notebook_id" + ], + "isUnique": false + }, + "page_notebooks_user_id_idx": { + "name": "page_notebooks_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "page_notebooks_id_user_id_pk": { + "columns": [ + "id", + "user_id" + ], + "name": "page_notebooks_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "pages": { + "name": "pages", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "is_private": { + "name": "is_private", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "is_favorite": { + "name": "is_favorite", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "purged_at": { + "name": "purged_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + } + }, + "indexes": { + "pages_updated_at_idx": { + "name": "pages_updated_at_idx", + "columns": [ + "updated_at" + ], + "isUnique": false + }, + "pages_user_id_idx": { + "name": "pages_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "pages_id_user_id_pk": { + "columns": [ + "id", + "user_id" + ], + "name": "pages_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "ratings": { + "name": "ratings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "topic_id": { + "name": "topic_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "history_entry_id": { + "name": "history_entry_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "person_name": { + "name": "person_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "comment": { + "name": "comment", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "purged_at": { + "name": "purged_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + } + }, + "indexes": { + "ratings_updated_at_idx": { + "name": "ratings_updated_at_idx", + "columns": [ + "updated_at" + ], + "isUnique": false + }, + "ratings_topic_id_idx": { + "name": "ratings_topic_id_idx", + "columns": [ + "topic_id" + ], + "isUnique": false + }, + "ratings_user_id_idx": { + "name": "ratings_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "ratings_topic_id_user_id_topics_id_user_id_fk": { + "name": "ratings_topic_id_user_id_topics_id_user_id_fk", + "tableFrom": "ratings", + "tableTo": "topics", + "columnsFrom": [ + "topic_id", + "user_id" + ], + "columnsTo": [ + "id", + "user_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "ratings_history_entry_id_user_id_history_entries_id_user_id_fk": { + "name": "ratings_history_entry_id_user_id_history_entries_id_user_id_fk", + "tableFrom": "ratings", + "tableTo": "history_entries", + "columnsFrom": [ + "history_entry_id", + "user_id" + ], + "columnsTo": [ + "id", + "user_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "ratings_id_user_id_pk": { + "columns": [ + "id", + "user_id" + ], + "name": "ratings_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "topics": { + "name": "topics", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "context_id": { + "name": "context_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'active'" + }, + "snooze_until": { + "name": "snooze_until", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_new": { + "name": "is_new", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "purged_at": { + "name": "purged_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + } + }, + "indexes": { + "topics_updated_at_idx": { + "name": "topics_updated_at_idx", + "columns": [ + "updated_at" + ], + "isUnique": false + }, + "topics_context_id_idx": { + "name": "topics_context_id_idx", + "columns": [ + "context_id" + ], + "isUnique": false + }, + "topics_user_id_idx": { + "name": "topics_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "topics_context_id_user_id_contexts_id_user_id_fk": { + "name": "topics_context_id_user_id_contexts_id_user_id_fk", + "tableFrom": "topics", + "tableTo": "contexts", + "columnsFrom": [ + "context_id", + "user_id" + ], + "columnsTo": [ + "id", + "user_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "topics_id_user_id_pk": { + "columns": [ + "id", + "user_id" + ], + "name": "topics_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/ka-note/server/drizzle/meta/_journal.json b/ka-note/server/drizzle/meta/_journal.json index 67475c4..f4f51a0 100644 --- a/ka-note/server/drizzle/meta/_journal.json +++ b/ka-note/server/drizzle/meta/_journal.json @@ -99,6 +99,13 @@ "when": 1772100000000, "tag": "0013_fts_search", "breakpoints": true + }, + { + "idx": 14, + "version": "6", + "when": 1772212044510, + "tag": "0014_classy_power_pack", + "breakpoints": true } ] } \ No newline at end of file diff --git a/ka-note/server/ka-note.db-shm b/ka-note/server/ka-note.db-shm index 8fd4a43c90775e6a624d0c3256006ed036a7994b..146d21dc8bb775e39f764f8e4f589dd5d28c72fc 100644 GIT binary patch delta 416 zcmb7+&nv@m7{{OI`Ruzg)QXmAlG9GgeJ}7w{F=z=c%1cBp+k{y)SkbdcXeYcTZqM{9%%7nsANXM% zF4%pj=tL9Z;ZM*H!w`TCFbYArfHJ6rE|`TCI94uEgX(t5OqgQMpbE{jAf7R&Ne1Vw Pc*0M1dBc?ErJcS3_!y2+ delta 355 zcmZo@U}|V!s+V}A%K!q>K+MR%Ag~HZuLR=13=2=Ze-))L=S^lskm3xd%;$0&&a{;2 zld2wQ6c~Wa{f`8o!b}V*8ynX%ZC=70WjA>PbIIg?j$D%$F@M|q&*>eDAXE{Q5@U$p zypZ`f)8-#uGK`xSF+XCO{LN1W$k@g_`9zQaknxUb^RZA1Rv_yT^X3C_Ol*@EG5^}U zCzXo{$oR5(SB4P_ka24Awp=No8Ud!s5As2_onrTANM&ebSU7nh^Uuv&3QZWnf&mO^ z3{4D+K!V)N3_J`X3@!{+46}f4kZ0U{r<9EeXvP`F&FdP3(M*QMRNLJ>CZthk zuG2p{)0?@O-#*Xtdwwt9&pyu%ohuuA&-P#vBw-Ry5=k;iCFvxSM8{aum~48MG70CW zGBeFX>z-vX49n*l!?!ymY#$n?Iqt}?tPxB}F5q>~1xygHYSvUtvK)&p4BukY2yVz!!{o1nFwYR4n z2Xsfa6*CO*gNAEtt3nO2^{hOUjmSc$WDQCINfHB+TN0f%Tcy|;40eh^r!5$A1_Hs5 zwLzyXJ2Ci7m>#bC;OH@~TWx2=UZnv268gQ$9 zXN9o1Pe1?egzH$jz9rv$gAjbPCWUQQ3X3kqzbR7G(e%QOs`mL-eFv8KOcCQ>_{H3} z4Mp4~V>U}D8AI#^l+q{Q@AL;l4x8u?`h%j=X?2L6ihxxN*n+N#&Pqx0J3P8RWtKIB z&j-?O?~QuqmHe`=Zj_R{H9Z+R{slehxZ1g|(-nif<#UQ+2unM~FDSZvuKoWrN*q3FEiEg{8&=BeUk5qz-$Eqs z)lZ~ZT>f9)6>Ar166!npulq46so~Z}t&pchbP!T2R2d#2KfAlMSHWp(Z&Ow~(HP3u z`GeQ`Pc+Xwr~5E3VW?KV_hpz%W}->vC1q(X`aV-yg8M)^WVI=m8c`u_rt7ae-J=Z= zeNXmN%--hDds=IRcz`yY)f5-!FA|mLfHCb(?soy`!;Aq<-m93 zN2cHshB!+&@E!1-qesAg=u8y1@qV8#HwObcOX;K~|7e6PD@<$Uo{P}TrT9p-NjdIE z+d1Lk-#i`M_2UMkR?!mLE#K8mi;#9JTY3?sOYbK9=`~2tglJRO%O5nNB3YP3l>E#H zS*R3mL^j6UJcYuagbvSWVaCb57!{)$DKmM6e1+V5q;4lE|9OHe1>^DwGf}F1HHk7< z`F$JUGmdP`9lrZ3O(mLNC%zve$l+LCA;kA96MIn{cP_*IFrE6v-sphTkBw{VC-9p~kR zt$<(ri@K+Ocl=HFl;$Z?mod7I{*`cActQvZmDFX${8#cVs`O6va)beo-R5w*LZT<& zv58KP$11vQs#R$VRs>wZK+x&3$^I<-%V1nt{UP~VX0h+!&OIkSUUXgm#G%SCVHy80 z_q-ts_0gxPG8O&XD9=NAiRyVipFcl|GZ>~FLF)CHUMTguDlKvpRmvQ|&UHZ9eG=6( zOxZeOE#0;5ZN-hKt3vtEgX#~c;lHQ;u_rHuH?`(JRzFjGcGq~qyOR|LFh*E|30H-W zgiFGEk8UT5l=AI_R{;0Ru}6u>aLeUP`QisCOW3z^({9K5j_+z^KgY<5FpZ)BGO}85 zE{&K(HI8Lr*h1weGbl!zzZ0r&-V^`zKX}7djA9WcyvrivCf;Cpf-RAUJXE&wQxA0( zZC%9TSe=#`Bo|-=0007j1E5+Mm0Xt!JI4cv?6o6lX(3P@s0PeCm z^+7Yh-7dRsE(Flut6TFSjKy@z2w^;=TQo3qO8v3Etx}*X-g{r7ngNiQ&w+k@b^%}l z(MT*lAoc0b2;e~}qMHm3)G>86#{!}&JiEXIU^uAHXG4&RY5;V1PdLymr5@)26bT3V zqW#g(fW8nyD%u(D=$W180o5yYMP{E!KtzMHd$R!V4@F7M2#)7Pc1l7LFFqEnET{0Ia(TFaQ7m diff --git a/ka-note/server/src/db/schema.ts b/ka-note/server/src/db/schema.ts index 74b7c8b..5d13ba0 100644 --- a/ka-note/server/src/db/schema.ts +++ b/ka-note/server/src/db/schema.ts @@ -144,6 +144,7 @@ export const apiKeys = sqliteTable('api_keys', { id: text('id').primaryKey(), userId: text('user_id').notNull(), label: text('label').notNull(), + email: text('email').notNull().default(''), keyHash: text('key_hash').notNull().unique(), createdAt: integer('created_at', { mode: 'timestamp' }).notNull(), lastUsedAt: integer('last_used_at', { mode: 'timestamp' }), diff --git a/ka-note/server/src/middleware/auth.ts b/ka-note/server/src/middleware/auth.ts index 2eb9af5..eb91a11 100644 --- a/ka-note/server/src/middleware/auth.ts +++ b/ka-note/server/src/middleware/auth.ts @@ -51,7 +51,7 @@ export const authMiddleware = createMiddleware(async (c, next) => { if (!key) { return c.json({ error: 'Invalid or revoked API key' }, 401); } - c.set('auth', { userId: key.userId, name: key.label, email: '' }); + c.set('auth', { userId: key.userId, name: key.label, email: key.email ?? '' }); // fire-and-forget lastUsedAt update db.update(apiKeys).set({ lastUsedAt: new Date() }).where(eq(apiKeys.id, key.id)).catch(() => {}); await next(); diff --git a/ka-note/server/src/routes/api-keys.ts b/ka-note/server/src/routes/api-keys.ts index c1e4449..d80a151 100644 --- a/ka-note/server/src/routes/api-keys.ts +++ b/ka-note/server/src/routes/api-keys.ts @@ -23,7 +23,7 @@ router.get('/', handle('api-keys/list', async (c) => { })); router.post('/', handle('api-keys/create', async (c) => { - const { userId } = c.get('auth'); + const { userId, email } = c.get('auth'); const body = await c.req.json<{ label: string }>(); if (!body.label?.trim()) { return c.json({ error: 'label required' }, 400); @@ -37,6 +37,7 @@ router.post('/', handle('api-keys/create', async (c) => { await db.insert(apiKeys).values({ id, userId, + email, label: body.label.trim(), keyHash, createdAt: now, diff --git a/ka-note/server/src/routes/calendar.ts b/ka-note/server/src/routes/calendar.ts index a0d1f76..bed15bf 100644 --- a/ka-note/server/src/routes/calendar.ts +++ b/ka-note/server/src/routes/calendar.ts @@ -15,7 +15,7 @@ calendar.get('/events', async (c) => { const auth = c.get('auth'); if (!auth.email) { - return c.json({ error: 'graph_unavailable', detail: 'No email in auth context (API key or dev-bypass)' }, 502); + return c.json({ error: 'graph_unavailable', detail: 'No email in auth context' }, 502); } try {