From ed317feae7475995fef320807e200897eb7ea365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Kr=C4=8Dek?= Date: Tue, 8 Jul 2025 12:07:43 +0200 Subject: [PATCH] Restructure progress --- .github/copilot-instructions.md | 5 + src/lib/gmail.ts | 80 ---------------- src/lib/google-server.ts | 38 -------- src/lib/google.ts | 95 ------------------- src/lib/google/auth/server.ts | 1 + src/lib/google/client.ts | 13 ++- src/lib/google/client/index.ts | 5 - src/lib/google/client/types.ts | 14 --- src/lib/google/gmail/index.ts | 90 ------------------ src/lib/google/gmail/server.ts | 88 +++++++++++++++++ src/lib/google/index.ts | 9 -- src/lib/google/server.ts | 17 ++-- src/lib/google/sheets/client.ts | 23 +++++ src/lib/google/sheets/index.ts | 77 --------------- src/lib/google/sheets/server.ts | 89 +++++++++++++++++ src/lib/index.ts | 1 - src/lib/sheets.ts | 58 ----------- src/lib/{ => types}/types.ts | 0 src/routes/api/auth/refresh/+server.ts | 4 +- src/routes/api/events/+server.ts | 21 ---- src/routes/auth/google/+server.ts | 4 +- src/routes/auth/google/callback/+server.ts | 4 +- .../api/google/auth/refresh/+server.ts | 4 +- .../api/google/auth/userinfo/+server.ts | 4 +- .../google/sheets/[sheetId]/data/+server.ts | 4 +- .../api/google/sheets/recent/+server.ts | 4 +- src/routes/private/events/+page.server.ts | 0 src/routes/private/events/+page.svelte | 85 +++-------------- .../private/events/event/new/+page.svelte | 4 +- .../new/components/GoogleSheetsStep.svelte | 2 +- src/routes/private/scanner/+page.svelte | 4 +- .../private/scanner/TicketDisplay.svelte | 4 +- 32 files changed, 257 insertions(+), 594 deletions(-) delete mode 100644 src/lib/gmail.ts delete mode 100644 src/lib/google-server.ts delete mode 100644 src/lib/google.ts delete mode 100644 src/lib/google/client/index.ts delete mode 100644 src/lib/google/client/types.ts delete mode 100644 src/lib/google/gmail/index.ts create mode 100644 src/lib/google/gmail/server.ts delete mode 100644 src/lib/google/index.ts create mode 100644 src/lib/google/sheets/client.ts delete mode 100644 src/lib/google/sheets/index.ts create mode 100644 src/lib/google/sheets/server.ts delete mode 100644 src/lib/index.ts delete mode 100644 src/lib/sheets.ts rename src/lib/{ => types}/types.ts (100%) create mode 100644 src/routes/private/events/+page.server.ts diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index a67c7e3..303229d 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -92,6 +92,11 @@ onsubmit|preventDefault={handleSubmit} is depracated, do not use it! Loading session using page.server.ts is not needed as the session is already available in the locals object. +IMPORTANT: Always make sure that the client-side module are not importing secrets +or are running any sensritive code that could expose secrets to the client. +If any requests are needed to check sensitive infomration, create an api route and +fetch data from there instead of directly in the client-side module. + The database schema in supabase is as follows: -- WARNING: This schema is for context only and is not meant to be run. -- Table order and constraints may not be valid for execution. diff --git a/src/lib/gmail.ts b/src/lib/gmail.ts deleted file mode 100644 index c46488d..0000000 --- a/src/lib/gmail.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { google } from 'googleapis'; -import quotedPrintable from 'quoted-printable'; -import { getAuthenticatedClient } from './google-server.js'; - -export function createEmailTemplate(text: string): string { - return ` - - - - - -
-

${text}

- QR Code -
-
-
-
-
-
-
-
-

This email has been generated with the help of ScanWave

-
-
- -`; -} - -export async function sendGmail( - refreshToken: string, - { to, subject, text, qr_code }: { to: string; subject: string; text: string; qr_code: string } -) { - const oauth = getAuthenticatedClient(refreshToken); - const gmail = google.gmail({ version: 'v1', auth: oauth }); - - const message_html = createEmailTemplate(text); - const boundary = 'BOUNDARY'; - const nl = '\r\n'; - - // Convert HTML to a Buffer, then to latin1 string for quotedPrintable.encode - const htmlBuffer = Buffer.from(message_html, 'utf8'); - const htmlLatin1 = htmlBuffer.toString('latin1'); - const htmlQP = quotedPrintable.encode(htmlLatin1); - const qrLines = qr_code.replace(/.{1,76}/g, '$&' + nl); - - const rawParts = [ - 'MIME-Version: 1.0', - `To: ${to}`, - `Subject: ${subject}`, - `Content-Type: multipart/related; boundary="${boundary}"`, - '', - `--${boundary}`, - 'Content-Type: text/html; charset="UTF-8"', - 'Content-Transfer-Encoding: quoted-printable', - '', - htmlQP, - '', - `--${boundary}`, - 'Content-Type: image/png', - 'Content-Transfer-Encoding: base64', - 'Content-ID: ', - 'Content-Disposition: inline; filename="qr.png"', - '', - qrLines, - '', - `--${boundary}--`, - '' - ]; - - const rawMessage = rawParts.join(nl); - const raw = Buffer.from(rawMessage).toString('base64url'); - - await gmail.users.messages.send({ - userId: 'me', - requestBody: { raw } - }); -} diff --git a/src/lib/google-server.ts b/src/lib/google-server.ts deleted file mode 100644 index 7d98157..0000000 --- a/src/lib/google-server.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { google } from 'googleapis'; -import { env } from '$env/dynamic/private'; - -export const scopes = [ - 'https://www.googleapis.com/auth/gmail.send', - 'https://www.googleapis.com/auth/userinfo.email', - 'https://www.googleapis.com/auth/drive.readonly', - 'https://www.googleapis.com/auth/spreadsheets.readonly' -]; - -export function getOAuthClient() { - return new google.auth.OAuth2( - env.GOOGLE_CLIENT_ID, - env.GOOGLE_CLIENT_SECRET, - env.GOOGLE_REDIRECT_URI - ); -} - -export function createAuthUrl() { - return getOAuthClient().generateAuthUrl({ - access_type: 'offline', - prompt: 'consent', - scope: scopes, - redirect_uri: env.GOOGLE_REDIRECT_URI - }); -} - -export async function exchangeCodeForTokens(code: string) { - const { tokens } = await getOAuthClient().getToken(code); - if (!tokens.refresh_token) throw new Error('No refresh_token returned'); - return tokens.refresh_token; -} - -export function getAuthenticatedClient(refreshToken: string) { - const oauth = getOAuthClient(); - oauth.setCredentials({ refresh_token: refreshToken }); - return oauth; -} diff --git a/src/lib/google.ts b/src/lib/google.ts deleted file mode 100644 index 4977884..0000000 --- a/src/lib/google.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { browser } from '$app/environment'; - -// Client-side only functions -export const scopes = [ - 'https://www.googleapis.com/auth/gmail.send', - 'https://www.googleapis.com/auth/userinfo.email', - 'https://www.googleapis.com/auth/drive.readonly', - 'https://www.googleapis.com/auth/spreadsheets.readonly' -]; - -// Client-side functions for browser environment -export async function initGoogleAuth(): Promise { - if (!browser) return; - // Google Auth initialization is handled by the OAuth flow - // No initialization needed for our server-side approach -} - -export function getAuthUrl(): string { - if (!browser) return ''; - // This should be obtained from the server - return '/auth/google'; -} - -export async function isTokenValid(accessToken: string): Promise { - if (!browser) return false; - - try { - const response = await fetch(`https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=${accessToken}`); - const data = await response.json(); - - if (response.ok && data.expires_in && data.expires_in > 0) { - return true; - } - return false; - } catch (error) { - console.error('Error validating token:', error); - return false; - } -} - -export async function refreshAccessToken(refreshToken: string): Promise { - try { - const response = await fetch('/private/api/google/auth/refresh', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ refreshToken }) - }); - - if (response.ok) { - const data = await response.json(); - return data.accessToken; - } - return null; - } catch (error) { - console.error('Error refreshing token:', error); - return null; - } -} - -export async function getUserInfo(accessToken: string): Promise<{ email: string; name: string; picture: string } | null> { - try { - const response = await fetch('/private/api/google/auth/userinfo', { - headers: { - 'Authorization': `Bearer ${accessToken}` - } - }); - - if (response.ok) { - return await response.json(); - } - return null; - } catch (error) { - console.error('Error fetching user info:', error); - return null; - } -} - -export async function revokeToken(accessToken: string): Promise { - try { - const response = await fetch('/private/api/google/auth/revoke', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ accessToken }) - }); - - return response.ok; - } catch (error) { - console.error('Error revoking token:', error); - return false; - } -} diff --git a/src/lib/google/auth/server.ts b/src/lib/google/auth/server.ts index 6e937ae..5b4e373 100644 --- a/src/lib/google/auth/server.ts +++ b/src/lib/google/auth/server.ts @@ -26,6 +26,7 @@ export function getOAuthClient() { * @returns Auth URL for Google OAuth */ export function createAuthUrl() { + console.warn("CREATE AUTH URL"); return getOAuthClient().generateAuthUrl({ access_type: 'offline', prompt: 'consent', diff --git a/src/lib/google/client.ts b/src/lib/google/client.ts index dcce5f2..74da0a6 100644 --- a/src/lib/google/client.ts +++ b/src/lib/google/client.ts @@ -1,8 +1,13 @@ /** - * Client-side Google API integration module + * Google API integration module * - * This module provides utilities for interacting with Google APIs from the client-side. + * This module provides utilities for interacting with Google APIs: + * - Authentication (server and client-side) + * - Sheets API */ -// Re-export auth utilities -export * from './auth/client.js'; +// Google service modules +export * as googleAuthClient from './auth/client.ts'; + +export * as googleSheetsClient from './sheets/client.ts'; + diff --git a/src/lib/google/client/index.ts b/src/lib/google/client/index.ts deleted file mode 100644 index 589398b..0000000 --- a/src/lib/google/client/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Re-export client-side auth utilities -export * from '../auth/client.js'; - -// Re-export types -export * from './types.js'; diff --git a/src/lib/google/client/types.ts b/src/lib/google/client/types.ts deleted file mode 100644 index d6f5986..0000000 --- a/src/lib/google/client/types.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Client-side type definitions for Google API integration - */ - -export interface GoogleSheet { - id: string; - name: string; - modifiedTime: string; - webViewLink: string; -} - -export interface SheetData { - values: string[][]; -} diff --git a/src/lib/google/gmail/index.ts b/src/lib/google/gmail/index.ts deleted file mode 100644 index d281afc..0000000 --- a/src/lib/google/gmail/index.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { google } from 'googleapis'; -import quotedPrintable from 'quoted-printable'; -import { getAuthenticatedClient } from '../auth/server.js'; - -/** - * Create an HTML email template - * @param text - Email body text - * @returns HTML email template - */ -export function createEmailTemplate(text: string): string { - return ` - - - - - -
-

${text}

- QR Code -
-
-
-
-
-
-
-
-

This email has been generated with the help of ScanWave

-
-
- -`; -} - -/** - * Send an email through Gmail - * @param refreshToken - Google refresh token - * @param params - Email parameters (to, subject, text, qr_code) - */ -export async function sendGmail( - refreshToken: string, - { to, subject, text, qr_code }: { to: string; subject: string; text: string; qr_code: string } -) { - const oauth = getAuthenticatedClient(refreshToken); - const gmail = google.gmail({ version: 'v1', auth: oauth }); - - const message_html = createEmailTemplate(text); - const boundary = 'BOUNDARY'; - const nl = '\r\n'; - - // Convert HTML to a Buffer, then to latin1 string for quotedPrintable.encode - const htmlBuffer = Buffer.from(message_html, 'utf8'); - const htmlLatin1 = htmlBuffer.toString('latin1'); - const htmlQP = quotedPrintable.encode(htmlLatin1); - const qrLines = qr_code.replace(/.{1,76}/g, '$&' + nl); - - const rawParts = [ - 'MIME-Version: 1.0', - `To: ${to}`, - `Subject: ${subject}`, - `Content-Type: multipart/related; boundary="${boundary}"`, - '', - `--${boundary}`, - 'Content-Type: text/html; charset="UTF-8"', - 'Content-Transfer-Encoding: quoted-printable', - '', - htmlQP, - '', - `--${boundary}`, - 'Content-Type: image/png', - 'Content-Transfer-Encoding: base64', - 'Content-ID: ', - 'Content-Disposition: inline; filename="qr.png"', - '', - qrLines, - '', - `--${boundary}--`, - '' - ]; - - const rawMessage = rawParts.join(nl); - const raw = Buffer.from(rawMessage).toString('base64url'); - - await gmail.users.messages.send({ - userId: 'me', - requestBody: { raw } - }); -} diff --git a/src/lib/google/gmail/server.ts b/src/lib/google/gmail/server.ts new file mode 100644 index 0000000..c6838ca --- /dev/null +++ b/src/lib/google/gmail/server.ts @@ -0,0 +1,88 @@ +import { google } from 'googleapis'; +import quotedPrintable from 'quoted-printable'; +import { getAuthenticatedClient } from '../auth/server.js'; + +/** + * Create an HTML email template + * @param text - Email body text + * @returns HTML email template + */ +export function createEmailTemplate(text: string): string { + return ` + + + + + +
+

${text}

+ QR Code +
+ +`; +} + +/** + * Send an email through Gmail + * @param refreshToken - Google refresh token + * @param params - Email parameters (to, subject, text, qr_code) + */ +export async function sendGmail( + refreshToken: string, + { + to, + subject, + text, + qr_code + }: { + to: string; + subject: string; + text: string; + qr_code: string; + } +) { + const oauth = getAuthenticatedClient(refreshToken); + const gmail = google.gmail({ version: 'v1', auth: oauth }); + + const message_html = createEmailTemplate(text); + const boundary = 'BOUNDARY'; + const nl = '\r\n'; + + const htmlBuffer = Buffer.from(message_html, 'utf8'); + const htmlLatin1 = htmlBuffer.toString('latin1'); + const htmlQP = quotedPrintable.encode(htmlLatin1); + const qrLines = qr_code.replace(/.{1,76}/g, '$&' + nl); + + const rawParts = [ + 'MIME-Version: 1.0', + `To: ${to}`, + `Subject: ${subject}`, + `Content-Type: multipart/related; boundary="${boundary}"`, + '--' + boundary, + 'Content-Type: text/html; charset="UTF-8"', + 'Content-Transfer-Encoding: quoted-printable', + '', + htmlQP, + '', + '--' + boundary, + 'Content-Type: image/png', + 'Content-Transfer-Encoding: base64', + 'Content-ID: ', + 'Content-Disposition: inline; filename="qr.png"', + '', + qrLines, + '', + '--' + boundary + '--', + '' + ]; + + const rawMessage = rawParts.join(nl); + const raw = Buffer.from(rawMessage).toString('base64url'); + + await gmail.users.messages.send({ + userId: 'me', + requestBody: { raw } + }); +} diff --git a/src/lib/google/index.ts b/src/lib/google/index.ts deleted file mode 100644 index eb972b5..0000000 --- a/src/lib/google/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Google API integration module - * - * This module provides utilities for interacting with Google APIs. - * NOTE: This is a client-side module. For server-side code, import from '$lib/google/server.js' - */ - -// Re-export client-side auth utilities -export * from './auth/client.js'; diff --git a/src/lib/google/server.ts b/src/lib/google/server.ts index 2ed029e..55e1b66 100644 --- a/src/lib/google/server.ts +++ b/src/lib/google/server.ts @@ -1,14 +1,15 @@ /** - * Server-side Google API integration module + * Google API integration module * - * This module provides utilities for interacting with Google APIs from the server-side. + * This module provides utilities for interacting with Google APIs: + * - Authentication (server and client-side) + * - Sheets API + * - Gmail API */ -// Re-export server-side auth utilities -export * from './auth/server.js'; +// Google service modules +export * as googleAuthServer from './auth/server.ts'; -// Re-export sheets utilities -export * from './sheets/index.js'; +export * as googleSheetsServer from './sheets/server.ts'; -// Re-export Gmail utilities -export * from './gmail/index.js'; +export * as googleGmailServer from './gmail/server.ts'; diff --git a/src/lib/google/sheets/client.ts b/src/lib/google/sheets/client.ts new file mode 100644 index 0000000..21c74b5 --- /dev/null +++ b/src/lib/google/sheets/client.ts @@ -0,0 +1,23 @@ +// Client-side Sheets functions (use fetch to call protected API endpoints) + +/** + * Fetch recent spreadsheets via protected endpoint + */ +export async function getRecentSpreadsheetsClient(refreshToken: string, limit: number = 10) { + const response = await fetch(`/private/api/google/sheets/recent?limit=${limit}`, { + headers: { Authorization: `Bearer ${refreshToken}` } + }); + if (!response.ok) throw new Error('Failed to fetch recent sheets'); + return await response.json(); +} + +/** + * Fetch spreadsheet data via protected endpoint + */ +export async function getSpreadsheetDataClient(refreshToken: string, sheetId: string, range: string = 'A1:Z10') { + const response = await fetch(`/private/api/google/sheets/${sheetId}/data?range=${encodeURIComponent(range)}`, { + headers: { Authorization: `Bearer ${refreshToken}` } + }); + if (!response.ok) throw new Error('Failed to fetch spreadsheet data'); + return await response.json(); +} diff --git a/src/lib/google/sheets/index.ts b/src/lib/google/sheets/index.ts deleted file mode 100644 index 8eaf173..0000000 --- a/src/lib/google/sheets/index.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { google } from 'googleapis'; -import { getAuthenticatedClient } from '../auth/server.js'; - -export interface GoogleSheet { - id: string; - name: string; - modifiedTime: string; - webViewLink: string; -} - -export interface SheetData { - values: string[][]; -} - -/** - * Get a list of recent Google Sheets - * @param refreshToken - Google refresh token - * @param limit - Maximum number of sheets to return - * @returns List of Google Sheets - */ -export async function getRecentSpreadsheets(refreshToken: string, limit: number = 10): Promise { - const oauth = getAuthenticatedClient(refreshToken); - const drive = google.drive({ version: 'v3', auth: oauth }); - - const response = await drive.files.list({ - q: "mimeType='application/vnd.google-apps.spreadsheet'", - orderBy: 'modifiedTime desc', - pageSize: limit, - fields: 'files(id,name,modifiedTime,webViewLink)' - }); - - return response.data.files?.map(file => ({ - id: file.id!, - name: file.name!, - modifiedTime: file.modifiedTime!, - webViewLink: file.webViewLink! - })) || []; -} - -/** - * Get data from a Google Sheet - * @param refreshToken - Google refresh token - * @param spreadsheetId - ID of the spreadsheet - * @param range - Cell range to retrieve (default: A1:Z10) - * @returns Sheet data as a 2D array - */ -export async function getSpreadsheetData(refreshToken: string, spreadsheetId: string, range: string = 'A1:Z10'): Promise { - const oauth = getAuthenticatedClient(refreshToken); - const sheets = google.sheets({ version: 'v4', auth: oauth }); - - const response = await sheets.spreadsheets.values.get({ - spreadsheetId, - range - }); - - return { - values: response.data.values || [] - }; -} - -/** - * Get metadata about a Google Sheet - * @param refreshToken - Google refresh token - * @param spreadsheetId - ID of the spreadsheet - * @returns Spreadsheet metadata - */ -export async function getSpreadsheetInfo(refreshToken: string, spreadsheetId: string) { - const oauth = getAuthenticatedClient(refreshToken); - const sheets = google.sheets({ version: 'v4', auth: oauth }); - - const response = await sheets.spreadsheets.get({ - spreadsheetId, - fields: 'properties.title,sheets.properties(title,sheetId)' - }); - - return response.data; -} diff --git a/src/lib/google/sheets/server.ts b/src/lib/google/sheets/server.ts new file mode 100644 index 0000000..57a7268 --- /dev/null +++ b/src/lib/google/sheets/server.ts @@ -0,0 +1,89 @@ +import { google } from 'googleapis'; +import { getAuthenticatedClient } from '../auth/server.js'; + +export interface GoogleSheet { + id: string; + name: string; + modifiedTime: string; + webViewLink: string; +} + +export interface SheetData { + values: string[][]; +} + +/** + * Get a list of recent Google Sheets + * @param refreshToken - Google refresh token + * @param limit - Maximum number of sheets to return + * @returns List of Google Sheets + */ +export async function getRecentSpreadsheets( + refreshToken: string, + limit: number = 10 +): Promise { + const oauth = getAuthenticatedClient(refreshToken); + const drive = google.drive({ version: 'v3', auth: oauth }); + + const response = await drive.files.list({ + q: "mimeType='application/vnd.google-apps.spreadsheet'", + orderBy: 'modifiedTime desc', + pageSize: limit, + fields: 'files(id,name,modifiedTime,webViewLink)' + }); + + return ( + response.data.files?.map(file => ({ + id: file.id!, // eslint-disable-line @typescript-eslint/no-non-null-assertion + name: file.name!, + modifiedTime: file.modifiedTime!, + webViewLink: file.webViewLink! + })) || [] + ); +} + +/** + * Get data from a Google Sheet + * @param refreshToken - Google refresh token + * @param spreadsheetId - ID of the spreadsheet + * @param range - Cell range to retrieve (default: A1:Z10) + * @returns Sheet data as a 2D array + */ +export async function getSpreadsheetData( + refreshToken: string, + spreadsheetId: string, + range: string = 'A1:Z10' +): Promise { + const oauth = getAuthenticatedClient(refreshToken); + const sheets = google.sheets({ version: 'v4', auth: oauth }); + + const response = await sheets.spreadsheets.values.get({ + spreadsheetId, + range + }); + + return { + values: response.data.values || [] + }; +} + +/** + * Get metadata about a Google Sheet + * @param refreshToken - Google refresh token + * @param spreadsheetId - ID of the spreadsheet + * @returns Spreadsheet metadata + */ +export async function getSpreadsheetInfo( + refreshToken: string, + spreadsheetId: string +) { + const oauth = getAuthenticatedClient(refreshToken); + const sheets = google.sheets({ version: 'v4', auth: oauth }); + + const response = await sheets.spreadsheets.get({ + spreadsheetId, + fields: 'properties.title,sheets.properties(title,sheetId)' + }); + + return response.data; +} diff --git a/src/lib/index.ts b/src/lib/index.ts deleted file mode 100644 index 856f2b6..0000000 --- a/src/lib/index.ts +++ /dev/null @@ -1 +0,0 @@ -// place files you want to import through the `$lib` alias in this folder. diff --git a/src/lib/sheets.ts b/src/lib/sheets.ts deleted file mode 100644 index b8dcc4c..0000000 --- a/src/lib/sheets.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { google } from 'googleapis'; -import { getAuthenticatedClient } from './google-server.js'; - -export interface GoogleSheet { - id: string; - name: string; - modifiedTime: string; - webViewLink: string; -} - -export interface SheetData { - values: string[][]; -} - -export async function getRecentSpreadsheets(refreshToken: string, limit: number = 10): Promise { - const oauth = getAuthenticatedClient(refreshToken); - const drive = google.drive({ version: 'v3', auth: oauth }); - - const response = await drive.files.list({ - q: "mimeType='application/vnd.google-apps.spreadsheet'", - orderBy: 'modifiedTime desc', - pageSize: limit, - fields: 'files(id,name,modifiedTime,webViewLink)' - }); - - return response.data.files?.map(file => ({ - id: file.id!, - name: file.name!, - modifiedTime: file.modifiedTime!, - webViewLink: file.webViewLink! - })) || []; -} - -export async function getSpreadsheetData(refreshToken: string, spreadsheetId: string, range: string = 'A1:Z10'): Promise { - const oauth = getAuthenticatedClient(refreshToken); - const sheets = google.sheets({ version: 'v4', auth: oauth }); - - const response = await sheets.spreadsheets.values.get({ - spreadsheetId, - range - }); - - return { - values: response.data.values || [] - }; -} - -export async function getSpreadsheetInfo(refreshToken: string, spreadsheetId: string) { - const oauth = getAuthenticatedClient(refreshToken); - const sheets = google.sheets({ version: 'v4', auth: oauth }); - - const response = await sheets.spreadsheets.get({ - spreadsheetId, - fields: 'properties.title,sheets.properties(title,sheetId)' - }); - - return response.data; -} diff --git a/src/lib/types.ts b/src/lib/types/types.ts similarity index 100% rename from src/lib/types.ts rename to src/lib/types/types.ts diff --git a/src/routes/api/auth/refresh/+server.ts b/src/routes/api/auth/refresh/+server.ts index 83eecbb..cfbd733 100644 --- a/src/routes/api/auth/refresh/+server.ts +++ b/src/routes/api/auth/refresh/+server.ts @@ -1,6 +1,6 @@ import { json } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; -import { authServer } from '$lib/google/index.js'; +import { getOAuthClient } from '$lib/google/auth/server.js'; export const POST: RequestHandler = async ({ request }) => { try { @@ -10,7 +10,7 @@ export const POST: RequestHandler = async ({ request }) => { return json({ error: 'Refresh token is required' }, { status: 400 }); } - const oauth = authServer.getOAuthClient(); + const oauth = getOAuthClient(); oauth.setCredentials({ refresh_token: refreshToken }); const { credentials } = await oauth.refreshAccessToken(); diff --git a/src/routes/api/events/+server.ts b/src/routes/api/events/+server.ts index a352d1f..e69de29 100644 --- a/src/routes/api/events/+server.ts +++ b/src/routes/api/events/+server.ts @@ -1,21 +0,0 @@ -import { json } from '@sveltejs/kit'; -import type { RequestHandler } from './$types'; - -export const GET: RequestHandler = async ({ locals }) => { - try { - const { data: events, error } = await locals.supabase - .from('events') - .select('*') - .order('date', { ascending: false }); - - if (error) { - console.error('Error fetching events:', error); - return json({ error: error.message }, { status: 500 }); - } - - return json({ events }); - } catch (err) { - console.error('Error in events API:', err); - return json({ error: 'Internal server error' }, { status: 500 }); - } -}; diff --git a/src/routes/auth/google/+server.ts b/src/routes/auth/google/+server.ts index 49205f7..71ea732 100644 --- a/src/routes/auth/google/+server.ts +++ b/src/routes/auth/google/+server.ts @@ -1,8 +1,8 @@ import { redirect } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; -import { authServer } from '$lib/google/index.js'; +import { createAuthUrl } from '$lib/google/auth/server.js'; export const GET: RequestHandler = () => { - const authUrl = authServer.createAuthUrl(); + const authUrl = createAuthUrl(); throw redirect(302, authUrl); }; diff --git a/src/routes/auth/google/callback/+server.ts b/src/routes/auth/google/callback/+server.ts index d369a58..584aa48 100644 --- a/src/routes/auth/google/callback/+server.ts +++ b/src/routes/auth/google/callback/+server.ts @@ -1,6 +1,6 @@ import { redirect } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; -import { authServer } from '$lib/google/index.js'; +import { googleAuthServer } from '$lib/google/server.ts'; export const GET: RequestHandler = async ({ url }) => { try { @@ -17,7 +17,7 @@ export const GET: RequestHandler = async ({ url }) => { } // Exchange code for tokens - const oauth = authServer.getOAuthClient(); + const oauth = googleAuthServer.getOAuthClient(); const { tokens } = await oauth.getToken(code); if (!tokens.refresh_token || !tokens.access_token) { diff --git a/src/routes/private/api/google/auth/refresh/+server.ts b/src/routes/private/api/google/auth/refresh/+server.ts index 5190a36..ca057c8 100644 --- a/src/routes/private/api/google/auth/refresh/+server.ts +++ b/src/routes/private/api/google/auth/refresh/+server.ts @@ -1,6 +1,6 @@ import { json } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; -import { getOAuthClient } from '$lib/google/server.js'; +import { googleAuthServer } from '$lib/google/server.ts'; export const POST: RequestHandler = async ({ request }) => { try { @@ -10,7 +10,7 @@ export const POST: RequestHandler = async ({ request }) => { return json({ error: 'Refresh token is required' }, { status: 400 }); } - const oauth = getOAuthClient(); + const oauth = googleAuthServer.getOAuthClient(); oauth.setCredentials({ refresh_token: refreshToken }); const { credentials } = await oauth.refreshAccessToken(); diff --git a/src/routes/private/api/google/auth/userinfo/+server.ts b/src/routes/private/api/google/auth/userinfo/+server.ts index 3c978d7..2e44e75 100644 --- a/src/routes/private/api/google/auth/userinfo/+server.ts +++ b/src/routes/private/api/google/auth/userinfo/+server.ts @@ -1,6 +1,6 @@ import { json } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; -import { getOAuthClient } from '$lib/google/server.js'; +import { googleAuthServer } from '$lib/google/server.ts'; import { google } from 'googleapis'; export const GET: RequestHandler = async ({ request }) => { @@ -14,7 +14,7 @@ export const GET: RequestHandler = async ({ request }) => { const accessToken = authHeader.slice(7); // Create OAuth client with the token - const oauth = getOAuthClient(); + const oauth = googleAuthServer.getOAuthClient(); oauth.setCredentials({ access_token: accessToken }); // Call the userinfo endpoint to get user details diff --git a/src/routes/private/api/google/sheets/[sheetId]/data/+server.ts b/src/routes/private/api/google/sheets/[sheetId]/data/+server.ts index 3126261..e87c1ff 100644 --- a/src/routes/private/api/google/sheets/[sheetId]/data/+server.ts +++ b/src/routes/private/api/google/sheets/[sheetId]/data/+server.ts @@ -1,6 +1,6 @@ import { json } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; -import { getSpreadsheetData } from '$lib/google/server.js'; +import { sheets } from '$lib/google/index.js'; export const GET: RequestHandler = async ({ params, request }) => { try { @@ -12,7 +12,7 @@ export const GET: RequestHandler = async ({ params, request }) => { } const refreshToken = authHeader.slice(7); - const sheetData = await getSpreadsheetData(refreshToken, sheetId, 'A1:Z10'); + const sheetData = await sheets.getSpreadsheetData(refreshToken, sheetId, 'A1:Z10'); return json(sheetData); } catch (error) { diff --git a/src/routes/private/api/google/sheets/recent/+server.ts b/src/routes/private/api/google/sheets/recent/+server.ts index d39f4e8..ed01813 100644 --- a/src/routes/private/api/google/sheets/recent/+server.ts +++ b/src/routes/private/api/google/sheets/recent/+server.ts @@ -1,6 +1,6 @@ import { json } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; -import { getRecentSpreadsheets } from '$lib/google/server.js'; +import { sheets } from '$lib/google/index.js'; export const GET: RequestHandler = async ({ request }) => { try { @@ -10,7 +10,7 @@ export const GET: RequestHandler = async ({ request }) => { } const refreshToken = authHeader.slice(7); - const spreadsheets = await getRecentSpreadsheets(refreshToken, 20); + const spreadsheets = await sheets.getRecentSpreadsheets(refreshToken, 20); return json(spreadsheets); } catch (error) { diff --git a/src/routes/private/events/+page.server.ts b/src/routes/private/events/+page.server.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/private/events/+page.svelte b/src/routes/private/events/+page.svelte index ad261e2..1664850 100644 --- a/src/routes/private/events/+page.svelte +++ b/src/routes/private/events/+page.svelte @@ -1,85 +1,24 @@

All Events

- {#if loading} - - {#each Array(4) as _} - New Event diff --git a/src/routes/private/events/event/new/+page.svelte b/src/routes/private/events/event/new/+page.svelte index b130cf8..e2177ff 100644 --- a/src/routes/private/events/event/new/+page.svelte +++ b/src/routes/private/events/event/new/+page.svelte @@ -1,7 +1,7 @@