From a8241c6e199173a0e42c807b973b0148f3538310 Mon Sep 17 00:00:00 2001 From: Eclypsed Date: Mon, 12 Feb 2024 00:39:15 -0500 Subject: [PATCH] Every connection now has distince SubmitFunction for adding/removing connections --- src/app.d.ts | 2 +- src/lib/server/users.db | Bin 24576 -> 24576 bytes src/routes/login/+page.svelte | 2 +- .../settings/connections/+page.server.ts | 14 +- src/routes/settings/connections/+page.svelte | 129 +++++++++--------- 5 files changed, 83 insertions(+), 64 deletions(-) diff --git a/src/app.d.ts b/src/app.d.ts index 7bcd9d1..837385b 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -13,7 +13,7 @@ declare global { // General Interface Desing tips: // Use possibly undefined `?:` for when a property is optional, meaning it could be there, or it could be not applicable - // Use possibly null `| nulll` for when the property is expected to be there but could possbily be explicitly empty + // Use possibly null `| null` for when the property is expected to be there but could possbily be explicitly empty interface User { id: string diff --git a/src/lib/server/users.db b/src/lib/server/users.db index ef10ac1b33023fe6c4245a7e67d3ef15302b4bad..df45a2b3d6ac2f9d12c6f35d316b8677d464070a 100644 GIT binary patch delta 894 zcma)*&yJf`6vpk0qEI;*32o7#lo{jW_NEU*IwrFn@+& zqR45KcHJtE(C(|KFOVnbx{JO?x3x#fK4*E(r{B@{>72Kp+HXI#e|_3M`R%(w`{d(~ zf4uy*^`zB$eDwI}<4^xR>i)cX@QrQ1@Bi`;`}~@N#AkR9$P8RVz+egV83|%Y0EB|T zf)D@pp6ys1~l2r!m`YY(_XKx>u!*yK}>K)i>{Y$dY{p~8~!sl!JEU%GcVpXSwYtOc9y3; zjmeaHWtAU>UwBQ)cY`1c%X`#V8#tx`TsA^eE1lQ=W@Qp9ibouKL6T*uW^iTmW9kQ{ zTIyOEHdB1-OLMND8A0aVIQ-e!M829T=8Hm-7;nd1Gak4Fz`rjhNtrzAym{Tho=1w} zGQB1Ta}DO?E(XX~R&F!UVTts-N~Bk57K%{-gmY(>qp_l)wJ=mucT~Fh zmNv4aOKLpVJ-RW6c&TD{8LP$;Xgg)f^-GuGFXJ)sQEhI|XA8JoR6(U&FL<4V1%4%K zMH1E=r_e}roMDq&AglTbdy9?bgyO~Ej?gP}d*_ZCUAe=9z_~z+>lw1fv!QuDT5w~E zB3qCs-WWxQ;8+swQog1pV0R+B4?ib%S0JxMwX2UOYGSg`JOWHJ>4uQaGOuJNrI6rG_=XK(8M&!(mW~2 yQa35t)LhpjB`sMu$;7}!*TgW*Jk87?IVs7|WU`@;?qqxaqnlY2Zt$xRqXPhJaU~Z3 diff --git a/src/routes/login/+page.svelte b/src/routes/login/+page.svelte index a031c36..53f8147 100644 --- a/src/routes/login/+page.svelte +++ b/src/routes/login/+page.svelte @@ -44,7 +44,7 @@ if (data.redirectLocation) formData.append('redirectLocation', data.redirectLocation) - return async ({ result }) => { + return ({ result }) => { if (result.type === 'failure') return ($newestAlert = ['warning', result.data?.message]) if (result.type === 'redirect') return goto(result.location) } diff --git a/src/routes/settings/connections/+page.server.ts b/src/routes/settings/connections/+page.server.ts index 7144db1..1df60d4 100644 --- a/src/routes/settings/connections/+page.server.ts +++ b/src/routes/settings/connections/+page.server.ts @@ -58,6 +58,7 @@ export const actions: Actions = { const tokenData: Jellyfin.JFTokens = { accessToken: authData.AccessToken, } + const newConnectionResponse = await fetch(`/api/users/${locals.user.id}/connections`, { method: 'POST', headers: { apikey: SECRET_INTERNAL_API_KEY }, @@ -69,7 +70,7 @@ export const actions: Actions = { const newConnection: Jellyfin.JFConnection = await newConnectionResponse.json() return { newConnection } }, - youtubeMusicLogin: async ({ request }) => { + youtubeMusicLogin: async ({ request, fetch, locals }) => { const formData = await request.formData() const { code } = Object.fromEntries(formData) const client = new google.auth.OAuth2({ clientId: PUBLIC_YOUTUBE_API_CLIENT_ID, clientSecret: YOUTUBE_API_CLIENT_SECRET, redirectUri: 'http://localhost:5173' }) // DO NOT SHIP THIS. THE CLIENT SECRET SHOULD NOT BE MADE AVAILABLE TO USERS. MAKE A REQUEST TO THE LAZULI WEBSITE INSTEAD. @@ -92,6 +93,17 @@ export const actions: Actions = { username: userChannel.snippet?.title as string, profilePicture: userChannel.snippet?.thumbnails?.default?.url as string | undefined, } + + const newConnectionResponse = await fetch(`/api/users/${locals.user.id}/connections`, { + method: 'POST', + headers: { apikey: SECRET_INTERNAL_API_KEY }, + body: JSON.stringify({ service: serviceData, tokens: tokenData }), + }) + + if (!newConnectionResponse.ok) return fail(500, { message: 'Internal Server Error' }) + + const newConnection: YouTubeMusic.YTConnection = await newConnectionResponse.json() + return { newConnection } }, deleteConnection: async ({ request, fetch, locals }) => { const formData = await request.formData() diff --git a/src/routes/settings/connections/+page.svelte b/src/routes/settings/connections/+page.svelte index 31b0837..fb94def 100644 --- a/src/routes/settings/connections/+page.svelte +++ b/src/routes/settings/connections/+page.svelte @@ -13,78 +13,85 @@ export let data: PageServerData let connections = data.userConnections - const submitCredentials: SubmitFunction = async ({ formData, action, cancel }) => { - switch (action.search) { - case '?/authenticateJellyfin': - const { serverUrl, username, password } = Object.fromEntries(formData) + const authenticateJellyfin: SubmitFunction = ({ formData, cancel }) => { + const { serverUrl, username, password } = Object.fromEntries(formData) - if (!(serverUrl && username && password)) { - $newestAlert = ['caution', 'All fields must be filled out'] - return cancel() - } - try { - formData.set('serverUrl', new URL(serverUrl.toString()).origin) - } catch { - $newestAlert = ['caution', 'Server URL is invalid'] - return cancel() - } - - const deviceId = getDeviceUUID() - formData.append('deviceId', deviceId) - break - case '?/youtubeMusicLogin': - const code = await youtubeAuthenication() - formData.append('code', code) - break - case '?/deleteConnection': - break - default: - console.log(action.search) - cancel() + if (!(serverUrl && username && password)) { + $newestAlert = ['caution', 'All fields must be filled out'] + return cancel() + } + try { + formData.set('serverUrl', new URL(serverUrl.toString()).origin) + } catch { + $newestAlert = ['caution', 'Server URL is invalid'] + return cancel() } - return async ({ result }) => { + const deviceId = getDeviceUUID() + formData.append('deviceId', deviceId) + + return ({ result }) => { if (result.type === 'failure') { return ($newestAlert = ['warning', result.data?.message]) } else if (result.type === 'success') { - if (result.data?.newConnection) { - const newConnection: Connection = result.data.newConnection - connections = [newConnection, ...connections] + const newConnection: Connection = result.data!.newConnection + connections = [...connections, newConnection] - newConnectionModal = null - return ($newestAlert = ['success', `Added ${Services[newConnection.service.type].displayName}`]) - } else if (result.data?.deletedConnectionId) { - const id = result.data.deletedConnectionId - const indexToDelete = connections.findIndex((connection) => connection.id === id) - const serviceType = connections[indexToDelete].service.type + newConnectionModal = null + return ($newestAlert = ['success', `Added ${Services[newConnection.service.type].displayName}`]) + } + } + } - connections.splice(indexToDelete, 1) - connections = connections + const authenticateYouTube: SubmitFunction = async ({ formData, cancel }) => { + const googleLoginProcess = (): Promise => { + return new Promise((resolve) => { + // @ts-ignore (google variable is a global variable imported by html script tag) + const client = google.accounts.oauth2.initCodeClient({ + client_id: PUBLIC_YOUTUBE_API_CLIENT_ID, + scope: 'https://www.googleapis.com/auth/youtube', + ux_mode: 'popup', + callback: (response: any) => { + resolve(response.code) + }, + }) + client.requestCode() + }) + } - return ($newestAlert = ['success', `Deleted ${Services[serviceType].displayName}`]) - } - } else if (result.type === 'redirect') { - window.open(result.location, '_blank') + const code = await googleLoginProcess() + if (!code) cancel() + formData.append('code', code) + + return ({ result }) => { + if (result.type === 'failure') { + return ($newestAlert = ['warning', result.data?.message]) + } else if (result.type === 'success') { + const newConnection: Connection = result.data!.newConnection + connections = [...connections, newConnection] + return ($newestAlert = ['success', 'Added Youtube Music']) + } + } + } + + const deleteConnection: SubmitFunction = () => { + return ({ result }) => { + if (result.type === 'failure') { + return ($newestAlert = ['warning', result.data?.message]) + } else if (result.type === 'success') { + const id = result.data!.deletedConnectionId + const indexToDelete = connections.findIndex((connection) => connection.id === id) + const serviceType = connections[indexToDelete].service.type + + connections.splice(indexToDelete, 1) + connections = connections + + return ($newestAlert = ['success', `Deleted ${Services[serviceType].displayName}`]) } } } let newConnectionModal: ComponentType> | null = null - - const youtubeAuthenication = async (): Promise => { - return new Promise((resolve) => { - // @ts-ignore (google variable is a global variable imported by html script tag) - const client = google.accounts.oauth2.initCodeClient({ - client_id: PUBLIC_YOUTUBE_API_CLIENT_ID, - scope: 'https://www.googleapis.com/auth/youtube', - ux_mode: 'popup', - callback: (response: any) => { - resolve(response.code) - }, - }) - client.requestCode() - }) - }
@@ -94,7 +101,7 @@ -
+ @@ -103,11 +110,11 @@
{#each connections as connection} - + {/each}
{#if newConnectionModal !== null} - (newConnectionModal = null)} /> + (newConnectionModal = null)} /> {/if}