kramp HF Staff commited on
Commit
9f870c5
·
unverified ·
1 Parent(s): 1a14bea

allow guest on home and shared convo (#1960)

Browse files

* allow guest on home and shared convo

* lint

* more interactions

* add also to mobile nav menu

src/hooks.server.ts CHANGED
@@ -138,16 +138,37 @@ export const handle: Handle = async ({ event, resolve }) => {
138
 
139
  event.locals.sessionId = auth.sessionId;
140
 
141
- if (
142
- loginEnabled &&
143
- !auth.user &&
144
- config.AUTOMATIC_LOGIN === "true" &&
145
- !event.url.pathname.startsWith(`${base}/login`) &&
146
- !event.url.pathname.startsWith(`${base}/healthcheck`)
147
- ) {
148
- // To get the same CSRF token after callback
149
- refreshSessionCookie(event.cookies, auth.secretSessionId);
150
- return await triggerOauthFlow({ request: event.request, url: event.url, locals: event.locals });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  }
152
 
153
  event.locals.user = auth.user || undefined;
 
138
 
139
  event.locals.sessionId = auth.sessionId;
140
 
141
+ if (loginEnabled && !auth.user) {
142
+ if (config.AUTOMATIC_LOGIN === "true") {
143
+ // AUTOMATIC_LOGIN: always redirect to OAuth flow (unless already on login or healthcheck pages)
144
+ if (
145
+ !event.url.pathname.startsWith(`${base}/login`) &&
146
+ !event.url.pathname.startsWith(`${base}/healthcheck`)
147
+ ) {
148
+ // To get the same CSRF token after callback
149
+ refreshSessionCookie(event.cookies, auth.secretSessionId);
150
+ return await triggerOauthFlow({
151
+ request: event.request,
152
+ url: event.url,
153
+ locals: event.locals,
154
+ });
155
+ }
156
+ } else {
157
+ // Redirect to OAuth flow unless on the authorized pages (home, shared conversation, login, healthcheck)
158
+ if (
159
+ event.url.pathname !== `${base}/` &&
160
+ event.url.pathname !== `${base}` &&
161
+ !event.url.pathname.startsWith(`${base}/login`) &&
162
+ !event.url.pathname.startsWith(`${base}/login/callback`) &&
163
+ !event.url.pathname.startsWith(`${base}/healthcheck`) &&
164
+ !event.url.pathname.startsWith(`${base}/r/`) &&
165
+ !event.url.pathname.startsWith(`${base}/conversation/`) &&
166
+ !event.url.pathname.startsWith(`${base}/api`)
167
+ ) {
168
+ refreshSessionCookie(event.cookies, auth.secretSessionId);
169
+ return triggerOauthFlow({ request: event.request, url: event.url, locals: event.locals });
170
+ }
171
+ }
172
  }
173
 
174
  event.locals.user = auth.user || undefined;
src/lib/components/MobileNav.svelte CHANGED
@@ -17,6 +17,7 @@
17
  import { Spring } from "svelte/motion";
18
  import { shareModal } from "$lib/stores/shareModal";
19
  import { loading } from "$lib/stores/loading";
 
20
  interface Props {
21
  title: string | undefined;
22
  children?: import("svelte").Snippet;
@@ -105,7 +106,15 @@
105
  <IconShare classNames={!canShare ? "opacity-40" : ""} />
106
  </button>
107
  {/if}
108
- <a href="{base}/" class="flex size-8 shrink-0 items-center justify-center text-lg">
 
 
 
 
 
 
 
 
109
  <IconNew />
110
  </a>
111
  </div>
 
17
  import { Spring } from "svelte/motion";
18
  import { shareModal } from "$lib/stores/shareModal";
19
  import { loading } from "$lib/stores/loading";
20
+ import { requireAuthUser } from "$lib/utils/auth";
21
  interface Props {
22
  title: string | undefined;
23
  children?: import("svelte").Snippet;
 
106
  <IconShare classNames={!canShare ? "opacity-40" : ""} />
107
  </button>
108
  {/if}
109
+ <a
110
+ href="{base}/"
111
+ class="flex size-8 shrink-0 items-center justify-center text-lg"
112
+ onclick={(e) => {
113
+ if (requireAuthUser()) {
114
+ e.preventDefault();
115
+ }
116
+ }}
117
+ >
118
  <IconNew />
119
  </a>
120
  </div>
src/lib/components/NavConversationItem.svelte CHANGED
@@ -9,6 +9,7 @@
9
  import type { ConvSidebar } from "$lib/types/ConvSidebar";
10
 
11
  import EditConversationModal from "$lib/components/EditConversationModal.svelte";
 
12
 
13
  interface Props {
14
  conv: ConvSidebar;
@@ -49,6 +50,7 @@
49
  title="Cancel delete action"
50
  onclick={(e) => {
51
  e.preventDefault();
 
52
  confirmDelete = false;
53
  }}
54
  >
@@ -60,6 +62,7 @@
60
  title="Confirm delete action"
61
  onclick={(e) => {
62
  e.preventDefault();
 
63
  confirmDelete = false;
64
  ondeleteConversation?.(conv.id.toString());
65
  }}
@@ -75,6 +78,7 @@
75
  title="Edit conversation title"
76
  onclick={(e) => {
77
  e.preventDefault();
 
78
  renameOpen = true;
79
  }}
80
  >
@@ -87,6 +91,7 @@
87
  title="Delete conversation"
88
  onclick={(event) => {
89
  event.preventDefault();
 
90
  if (event.shiftKey) {
91
  ondeleteConversation?.(conv.id.toString());
92
  } else {
 
9
  import type { ConvSidebar } from "$lib/types/ConvSidebar";
10
 
11
  import EditConversationModal from "$lib/components/EditConversationModal.svelte";
12
+ import { requireAuthUser } from "$lib/utils/auth";
13
 
14
  interface Props {
15
  conv: ConvSidebar;
 
50
  title="Cancel delete action"
51
  onclick={(e) => {
52
  e.preventDefault();
53
+ if (requireAuthUser()) return;
54
  confirmDelete = false;
55
  }}
56
  >
 
62
  title="Confirm delete action"
63
  onclick={(e) => {
64
  e.preventDefault();
65
+ if (requireAuthUser()) return;
66
  confirmDelete = false;
67
  ondeleteConversation?.(conv.id.toString());
68
  }}
 
78
  title="Edit conversation title"
79
  onclick={(e) => {
80
  e.preventDefault();
81
+ if (requireAuthUser()) return;
82
  renameOpen = true;
83
  }}
84
  >
 
91
  title="Delete conversation"
92
  onclick={(event) => {
93
  event.preventDefault();
94
+ if (requireAuthUser()) return;
95
  if (event.shiftKey) {
96
  ondeleteConversation?.(conv.id.toString());
97
  } else {
src/lib/components/NavMenu.svelte CHANGED
@@ -27,6 +27,7 @@
27
  import { browser } from "$app/environment";
28
  import { usePublicConfig } from "$lib/utils/PublicConfig.svelte";
29
  import { useAPIClient, handleResponse } from "$lib/APIClient";
 
30
 
31
  const publicConfig = usePublicConfig();
32
  const client = useAPIClient();
@@ -49,8 +50,18 @@
49
 
50
  let hasMore = $state(true);
51
 
52
- function handleNewChatClick() {
53
  isAborted.set(true);
 
 
 
 
 
 
 
 
 
 
54
  }
55
 
56
  const dateRanges = [
@@ -174,6 +185,7 @@
174
  <a
175
  href="{base}/models"
176
  class="flex h-9 flex-none items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
 
177
  >
178
  Models
179
  <span
@@ -186,6 +198,7 @@
186
  <a
187
  href="{base}/settings/application"
188
  class="flex h-9 flex-none flex-grow items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
 
189
  >
190
  Settings
191
  </a>
 
27
  import { browser } from "$app/environment";
28
  import { usePublicConfig } from "$lib/utils/PublicConfig.svelte";
29
  import { useAPIClient, handleResponse } from "$lib/APIClient";
30
+ import { requireAuthUser } from "$lib/utils/auth";
31
 
32
  const publicConfig = usePublicConfig();
33
  const client = useAPIClient();
 
50
 
51
  let hasMore = $state(true);
52
 
53
+ function handleNewChatClick(e: MouseEvent) {
54
  isAborted.set(true);
55
+
56
+ if (requireAuthUser()) {
57
+ e.preventDefault();
58
+ }
59
+ }
60
+
61
+ function handleNavItemClick(e: MouseEvent) {
62
+ if (requireAuthUser()) {
63
+ e.preventDefault();
64
+ }
65
  }
66
 
67
  const dateRanges = [
 
185
  <a
186
  href="{base}/models"
187
  class="flex h-9 flex-none items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
188
+ onclick={handleNavItemClick}
189
  >
190
  Models
191
  <span
 
198
  <a
199
  href="{base}/settings/application"
200
  class="flex h-9 flex-none flex-grow items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
201
+ onclick={handleNavItemClick}
202
  >
203
  Settings
204
  </a>
src/lib/components/chat/ChatInput.svelte CHANGED
@@ -7,6 +7,8 @@
7
  import IconPaperclip from "$lib/components/icons/IconPaperclip.svelte";
8
 
9
  import { isVirtualKeyboard } from "$lib/utils/isVirtualKeyboard";
 
 
10
  interface Props {
11
  files?: File[];
12
  mimeTypes?: string[];
@@ -160,6 +162,7 @@
160
  {disabled}
161
  onfocus={handleFocus}
162
  onblur={handleBlur}
 
163
  ></textarea>
164
 
165
  {#if !showNoTools}
@@ -194,6 +197,11 @@
194
  aria-label="Upload file"
195
  type="file"
196
  onchange={onFileChange}
 
 
 
 
 
197
  accept={mimeTypes.join(",")}
198
  />
199
  <IconPaperclip classNames="text-xl" />
 
7
  import IconPaperclip from "$lib/components/icons/IconPaperclip.svelte";
8
 
9
  import { isVirtualKeyboard } from "$lib/utils/isVirtualKeyboard";
10
+ import { requireAuthUser } from "$lib/utils/auth";
11
+
12
  interface Props {
13
  files?: File[];
14
  mimeTypes?: string[];
 
162
  {disabled}
163
  onfocus={handleFocus}
164
  onblur={handleBlur}
165
+ onbeforeinput={requireAuthUser}
166
  ></textarea>
167
 
168
  {#if !showNoTools}
 
197
  aria-label="Upload file"
198
  type="file"
199
  onchange={onFileChange}
200
+ onclick={(e) => {
201
+ if (requireAuthUser()) {
202
+ e.preventDefault();
203
+ }
204
+ }}
205
  accept={mimeTypes.join(",")}
206
  />
207
  <IconPaperclip classNames="text-xl" />
src/lib/components/chat/ChatMessage.svelte CHANGED
@@ -17,6 +17,7 @@
17
  import Alternatives from "./Alternatives.svelte";
18
  import MessageAvatar from "./MessageAvatar.svelte";
19
  import { PROVIDERS_HUB_ORGS } from "@huggingface/inference";
 
20
 
21
  interface Props {
22
  message: Message;
@@ -329,7 +330,10 @@
329
  class="hidden cursor-pointer items-center gap-1 rounded-md border border-gray-200 px-1.5 py-0.5 text-xs text-gray-400 group-hover:flex hover:flex hover:text-gray-500 dark:border-gray-700 dark:text-gray-400 dark:hover:text-gray-300 lg:-right-2"
330
  title="Edit"
331
  type="button"
332
- onclick={() => (editMsdgId = message.id)}
 
 
 
333
  >
334
  <CarbonPen />
335
  Edit
 
17
  import Alternatives from "./Alternatives.svelte";
18
  import MessageAvatar from "./MessageAvatar.svelte";
19
  import { PROVIDERS_HUB_ORGS } from "@huggingface/inference";
20
+ import { requireAuthUser } from "$lib/utils/auth";
21
 
22
  interface Props {
23
  message: Message;
 
330
  class="hidden cursor-pointer items-center gap-1 rounded-md border border-gray-200 px-1.5 py-0.5 text-xs text-gray-400 group-hover:flex hover:flex hover:text-gray-500 dark:border-gray-700 dark:text-gray-400 dark:hover:text-gray-300 lg:-right-2"
331
  title="Edit"
332
  type="button"
333
+ onclick={() => {
334
+ if (requireAuthUser()) return;
335
+ editMsdgId = message.id;
336
+ }}
337
  >
338
  <CarbonPen />
339
  Edit
src/lib/components/chat/ChatWindow.svelte CHANGED
@@ -32,6 +32,7 @@
32
  import { cubicInOut } from "svelte/easing";
33
 
34
  import { isVirtualKeyboard } from "$lib/utils/isVirtualKeyboard";
 
35
 
36
  interface Props {
37
  messages?: Message[];
@@ -74,7 +75,7 @@
74
  let pastedLongContent = $state(false);
75
 
76
  const handleSubmit = () => {
77
- if (loading || !draft) return;
78
  onmessage?.(draft);
79
  draft = "";
80
  };
@@ -273,12 +274,13 @@
273
  });
274
 
275
  function triggerPrompt(prompt: string) {
276
- if (loading) return;
277
  draft = prompt;
278
  handleSubmit();
279
  }
280
 
281
  async function startExample(example: RouterExample) {
 
282
  activeRouterExamplePrompt = example.prompt;
283
 
284
  if (browser && example.attachments?.length) {
@@ -533,6 +535,11 @@
533
  {#if !currentModel.isRouter || !loading}
534
  <a
535
  href="{base}/settings/{currentModel.id}"
 
 
 
 
 
536
  class="inline-flex items-center gap-1 hover:underline"
537
  >
538
  {#if currentModel.isRouter}
 
32
  import { cubicInOut } from "svelte/easing";
33
 
34
  import { isVirtualKeyboard } from "$lib/utils/isVirtualKeyboard";
35
+ import { requireAuthUser } from "$lib/utils/auth";
36
 
37
  interface Props {
38
  messages?: Message[];
 
75
  let pastedLongContent = $state(false);
76
 
77
  const handleSubmit = () => {
78
+ if (requireAuthUser() || loading || !draft) return;
79
  onmessage?.(draft);
80
  draft = "";
81
  };
 
274
  });
275
 
276
  function triggerPrompt(prompt: string) {
277
+ if (requireAuthUser() || loading) return;
278
  draft = prompt;
279
  handleSubmit();
280
  }
281
 
282
  async function startExample(example: RouterExample) {
283
+ if (requireAuthUser()) return;
284
  activeRouterExamplePrompt = example.prompt;
285
 
286
  if (browser && example.attachments?.length) {
 
535
  {#if !currentModel.isRouter || !loading}
536
  <a
537
  href="{base}/settings/{currentModel.id}"
538
+ onclick={(e) => {
539
+ if (requireAuthUser()) {
540
+ e.preventDefault();
541
+ }
542
+ }}
543
  class="inline-flex items-center gap-1 hover:underline"
544
  >
545
  {#if currentModel.isRouter}
src/lib/components/chat/FileDropzone.svelte CHANGED
@@ -1,4 +1,5 @@
1
  <script lang="ts">
 
2
  import CarbonImage from "~icons/carbon/image";
3
 
4
  interface Props {
@@ -18,7 +19,7 @@
18
 
19
  async function dropHandle(event: DragEvent) {
20
  event.preventDefault();
21
- if (event.dataTransfer && event.dataTransfer.items) {
22
  // Use DataTransferItemList interface to access the file(s)
23
  if (files.length > 0) {
24
  files = [];
 
1
  <script lang="ts">
2
+ import { requireAuthUser } from "$lib/utils/auth";
3
  import CarbonImage from "~icons/carbon/image";
4
 
5
  interface Props {
 
19
 
20
  async function dropHandle(event: DragEvent) {
21
  event.preventDefault();
22
+ if (!requireAuthUser() && event.dataTransfer && event.dataTransfer.items) {
23
  // Use DataTransferItemList interface to access the file(s)
24
  if (files.length > 0) {
25
  files = [];
src/lib/utils/auth.ts ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { goto } from "$app/navigation";
2
+ import { base } from "$app/paths";
3
+ import { page } from "$app/state";
4
+
5
+ /**
6
+ * Redirects to the login page if the user is not authenticated
7
+ * and the login feature is enabled.
8
+ */
9
+ export function requireAuthUser(): boolean {
10
+ if (page.data.loginEnabled && !page.data.user) {
11
+ goto(`${base}/login`, { invalidateAll: true });
12
+ return true;
13
+ }
14
+ return false;
15
+ }
src/routes/+layout.svelte CHANGED
@@ -22,6 +22,7 @@
22
  import IconShare from "$lib/components/icons/IconShare.svelte";
23
  import { shareModal } from "$lib/stores/shareModal";
24
  import BackgroundGenerationPoller from "$lib/components/BackgroundGenerationPoller.svelte";
 
25
 
26
  let { data = $bindable(), children } = $props();
27
 
@@ -95,11 +96,8 @@
95
  }
96
 
97
  function closeWelcomeModal() {
 
98
  settings.set({ welcomeModalSeen: true });
99
-
100
- if (!data.user && data.loginEnabled) {
101
- goto(`${base}/login`, { invalidateAll: true });
102
- }
103
  }
104
 
105
  onDestroy(() => {
@@ -161,6 +159,7 @@
161
  if (oPressed && e.shiftKey && metaOrCtrl) {
162
  e.preventDefault();
163
  isAborted.set(true);
 
164
  goto(`${base}/`, { invalidateAll: true });
165
  }
166
  };
@@ -176,7 +175,10 @@
176
  );
177
 
178
  // Show the welcome modal once on first app load
179
- let showWelcome = $derived(!$settings.welcomeModalSeen && !(page.data.shared === true));
 
 
 
180
  </script>
181
 
182
  <svelte:head>
@@ -223,7 +225,7 @@
223
  {/if}
224
  </svelte:head>
225
 
226
- {#if showWelcome || (!data.user && data.loginEnabled)}
227
  <WelcomeModal close={closeWelcomeModal} />
228
  {/if}
229
 
 
22
  import IconShare from "$lib/components/icons/IconShare.svelte";
23
  import { shareModal } from "$lib/stores/shareModal";
24
  import BackgroundGenerationPoller from "$lib/components/BackgroundGenerationPoller.svelte";
25
+ import { requireAuthUser } from "$lib/utils/auth";
26
 
27
  let { data = $bindable(), children } = $props();
28
 
 
96
  }
97
 
98
  function closeWelcomeModal() {
99
+ if (requireAuthUser()) return;
100
  settings.set({ welcomeModalSeen: true });
 
 
 
 
101
  }
102
 
103
  onDestroy(() => {
 
159
  if (oPressed && e.shiftKey && metaOrCtrl) {
160
  e.preventDefault();
161
  isAborted.set(true);
162
+ if (requireAuthUser()) return;
163
  goto(`${base}/`, { invalidateAll: true });
164
  }
165
  };
 
175
  );
176
 
177
  // Show the welcome modal once on first app load
178
+ let showWelcome = $derived(
179
+ !$settings.welcomeModalSeen &&
180
+ !(page.data.shared === true && page.route.id?.startsWith("/conversation/"))
181
+ );
182
  </script>
183
 
184
  <svelte:head>
 
225
  {/if}
226
  </svelte:head>
227
 
228
+ {#if showWelcome}
229
  <WelcomeModal close={closeWelcomeModal} />
230
  {/if}
231
 
src/routes/conversation/[id]/+page.svelte CHANGED
@@ -27,6 +27,7 @@
27
  import { updateDebouncer } from "$lib/utils/updates.js";
28
  import SubscribeModal from "$lib/components/SubscribeModal.svelte";
29
  import { loading } from "$lib/stores/loading.js";
 
30
 
31
  let { data = $bindable() } = $props();
32
 
@@ -393,6 +394,8 @@
393
  }
394
 
395
  async function onRetry(payload: { id: Message["id"]; content?: string }) {
 
 
396
  const lastMsgId = payload.id;
397
  messagesPath = createMessagesPath(messages, lastMsgId);
398
 
 
27
  import { updateDebouncer } from "$lib/utils/updates.js";
28
  import SubscribeModal from "$lib/components/SubscribeModal.svelte";
29
  import { loading } from "$lib/stores/loading.js";
30
+ import { requireAuthUser } from "$lib/utils/auth.js";
31
 
32
  let { data = $bindable() } = $props();
33
 
 
394
  }
395
 
396
  async function onRetry(payload: { id: Message["id"]; content?: string }) {
397
+ if (requireAuthUser()) return;
398
+
399
  const lastMsgId = payload.id;
400
  messagesPath = createMessagesPath(messages, lastMsgId);
401