From ad2aaea8b0ac6a0973b7e77727f54da34a420cb9 Mon Sep 17 00:00:00 2001 From: George Petrakis Date: Fri, 13 Jun 2025 14:47:47 +0300 Subject: [PATCH 01/16] Feat: reintroduce API module with enhanced error handling and documentation --- ui/src/api.js | 79 ------------------------------- ui/src/pages/Create.vue | 2 +- ui/src/pages/View.vue | 2 +- ui/src/services/api.js | 100 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 81 deletions(-) delete mode 100644 ui/src/api.js create mode 100644 ui/src/services/api.js diff --git a/ui/src/api.js b/ui/src/api.js deleted file mode 100644 index 57cb620..0000000 --- a/ui/src/api.js +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Provides functions to interact with the backend API. - * Uses fetch for HTTP requests. - */ -const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8080' -console.log('API_URL:', API_URL); - -export async function createSend(formData) { - const res = await fetch(`${API_URL}/send`, { - method: 'POST', - body: formData - }) - if (!res.ok) { - if (res.status === 413) { - throw new Error('File too large') - } else if (res.status === 422) { - throw new Error('Invalid form data') - } else if (res.status === 429) { - throw new Error('Too many requests – please try again later') - } else { - throw new Error('Failed to create send') - } - } - return res.json() -} - -export async function getSend(hash, password = '') { - const API_BASE_URL = `${window.location.origin}/api` - const url = new URL(`${API_BASE_URL}/send/${hash}`) - - if (password) url.searchParams.set('password', password) - - const res = await fetch(url) - - - if (res.status === 404) { - console.log('Secret not found.') - return { notFound: true } - } - - if (!res.ok) { - console.error('Failed to retrieve send:', res.statusText) - throw new Error('Failed to retrieve send') - } - - const contentDisposition = res.headers.get('Content-Disposition') - let filename = `download-${hash}` - - if (contentDisposition) { - const matches = contentDisposition.match(/filename="(.+?)"/) - if (matches && matches[1]) { - filename = matches[1] - } - } - - const contentType = res.headers.get('content-type') - - if (contentType.includes('application/octet-stream')) { - const blob = await res.blob() - return { file: blob, filename } - } - - const text = await res.text() - return { text } -} - -export async function checkPasswordProtection(hash) { - const res = await fetch(`${API_URL}/send/${hash}/check`) - - if (res.status === 404) { - return { notFound: true } - } - - if (!res.ok) { - throw new Error('Failed to check password protection') - } - - return await res.json() -} \ No newline at end of file diff --git a/ui/src/pages/Create.vue b/ui/src/pages/Create.vue index 06d10bd..074bd8e 100644 --- a/ui/src/pages/Create.vue +++ b/ui/src/pages/Create.vue @@ -99,7 +99,7 @@ \ No newline at end of file diff --git a/ui/src/pages/Create.vue b/ui/src/pages/Create.vue deleted file mode 100644 index 074bd8e..0000000 --- a/ui/src/pages/Create.vue +++ /dev/null @@ -1,215 +0,0 @@ - - - - - diff --git a/ui/src/pages/Error404.vue b/ui/src/pages/Error404.vue deleted file mode 100644 index d06123c..0000000 --- a/ui/src/pages/Error404.vue +++ /dev/null @@ -1,32 +0,0 @@ - - - - - diff --git a/ui/src/pages/ErrorGeneral.vue b/ui/src/pages/ErrorGeneral.vue deleted file mode 100644 index 89545c9..0000000 --- a/ui/src/pages/ErrorGeneral.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/ui/src/pages/View.vue b/ui/src/pages/View.vue deleted file mode 100644 index b1c7dff..0000000 --- a/ui/src/pages/View.vue +++ /dev/null @@ -1,138 +0,0 @@ - - - - - From 55191149d39b9d7a67f6390b2c65432c5b82fef1 Mon Sep 17 00:00:00 2001 From: George Petrakis Date: Fri, 13 Jun 2025 14:49:15 +0300 Subject: [PATCH 05/16] Feat: add SecretDisplay component for displaying and copying secrets with file download functionality --- ui/src/components/SecretDisplay.vue | 47 +++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 ui/src/components/SecretDisplay.vue diff --git a/ui/src/components/SecretDisplay.vue b/ui/src/components/SecretDisplay.vue new file mode 100644 index 0000000..7f0f5d7 --- /dev/null +++ b/ui/src/components/SecretDisplay.vue @@ -0,0 +1,47 @@ + + + \ No newline at end of file From 62736d855381c924d1e64e07de5d3c29717b9f27 Mon Sep 17 00:00:00 2001 From: George Petrakis Date: Fri, 13 Jun 2025 14:49:37 +0300 Subject: [PATCH 06/16] Feat: implement Create component for creating secrets with text and file options --- ui/src/pages/Create.vue | 164 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 ui/src/pages/Create.vue diff --git a/ui/src/pages/Create.vue b/ui/src/pages/Create.vue new file mode 100644 index 0000000..409e62a --- /dev/null +++ b/ui/src/pages/Create.vue @@ -0,0 +1,164 @@ + + + + + \ No newline at end of file From 296ad003685068580e3b8bebc15121cb899e4579 Mon Sep 17 00:00:00 2001 From: George Petrakis Date: Fri, 13 Jun 2025 14:49:53 +0300 Subject: [PATCH 07/16] Feat: implement View component for displaying secrets with password protection and file download options --- ui/src/pages/View.vue | 103 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 ui/src/pages/View.vue diff --git a/ui/src/pages/View.vue b/ui/src/pages/View.vue new file mode 100644 index 0000000..d6809e7 --- /dev/null +++ b/ui/src/pages/View.vue @@ -0,0 +1,103 @@ + + + + + \ No newline at end of file From a3f434906fb553eed032b94869c484678128db1d Mon Sep 17 00:00:00 2001 From: George Petrakis Date: Fri, 13 Jun 2025 14:51:33 +0300 Subject: [PATCH 08/16] Refactor: clean up comments and formatting in main application entry point --- ui/src/main.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/ui/src/main.js b/ui/src/main.js index 3b76e01..0a08408 100644 --- a/ui/src/main.js +++ b/ui/src/main.js @@ -1,18 +1,24 @@ +/** + * Main application entry point. + * Initializes Vue, Vuetify, and the Router. + */ import { createApp } from 'vue' import App from './App.vue' -import router from './router' +import router from './router' // This now imports from the /router directory // Import Vuetify and styles -import 'vuetify/styles' +import 'vuetify/styles' import { createVuetify } from 'vuetify' -import '@mdi/font/css/materialdesignicons.css' +import '@mdi/font/css/materialdesignicons.css' +// Create Vuetify instance const vuetify = createVuetify({ icons: { - defaultSet: 'mdi', + defaultSet: 'mdi', }, }) +// Create and mount the Vue application const app = createApp(App) app.use(router) app.use(vuetify) From c808cc8da808c67b2c8c2750819d0353f28812a7 Mon Sep 17 00:00:00 2001 From: George Petrakis Date: Fri, 13 Jun 2025 14:54:40 +0300 Subject: [PATCH 09/16] Feat: reintroduce Vue Router setup with corrected import paths and route definitions --- ui/src/router.js | 22 ---------------------- ui/src/router/index.js | 23 +++++++++++++++++++++++ 2 files changed, 23 insertions(+), 22 deletions(-) delete mode 100644 ui/src/router.js create mode 100644 ui/src/router/index.js diff --git a/ui/src/router.js b/ui/src/router.js deleted file mode 100644 index 281eaa6..0000000 --- a/ui/src/router.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Sets up the Vue Router with basic routes for create, view, and error pages. - */ -import { createRouter, createWebHistory } from 'vue-router' -import Create from './pages/Create.vue' -import View from './pages/View.vue' -import Error404 from './pages/Error404.vue' -import ErrorGeneral from './pages/ErrorGeneral.vue' - -const routes = [ - { path: '/', component: Create }, - { path: '/view/:hash', component: View }, - { path: '/error', component: ErrorGeneral }, - { path: '/:pathMatch(.*)*', component: Error404 } -] - -const router = createRouter({ - history: createWebHistory(), - routes -}) - -export default router diff --git a/ui/src/router/index.js b/ui/src/router/index.js new file mode 100644 index 0000000..b5f42be --- /dev/null +++ b/ui/src/router/index.js @@ -0,0 +1,23 @@ +/** + * Sets up the Vue Router. + * The import paths are now relative to the `src/router/` directory. + */ +import { createRouter, createWebHistory } from 'vue-router'; +import Create from '../pages/Create.vue'; // Corrected Path +import View from '../pages/View.vue'; // Corrected Path +import Error404 from '../pages/Error404.vue'; // Corrected Path +import ErrorGeneral from '../pages/ErrorGeneral.vue'; // Corrected Path + +const routes = [ + { path: '/', component: Create, name: 'create' }, + { path: '/view/:hash', component: View, name: 'view' }, + { path: '/error', component: ErrorGeneral, name: 'error' }, + { path: '/:pathMatch(.*)*', component: Error404, name: 'not-found' } +]; + +const router = createRouter({ + history: createWebHistory(), + routes +}); + +export default router; From 52f859dbe4ae371bf25778a2f5fd4b0ff188a333 Mon Sep 17 00:00:00 2001 From: George Petrakis Date: Fri, 13 Jun 2025 14:54:46 +0300 Subject: [PATCH 10/16] Feat: add 404 and general error components for improved user feedback --- ui/src/pages/Error404.vue | 28 ++++++++++++++++++++++++++++ ui/src/pages/ErrorGeneral.vue | 27 +++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 ui/src/pages/Error404.vue create mode 100644 ui/src/pages/ErrorGeneral.vue diff --git a/ui/src/pages/Error404.vue b/ui/src/pages/Error404.vue new file mode 100644 index 0000000..a16cf7c --- /dev/null +++ b/ui/src/pages/Error404.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/ui/src/pages/ErrorGeneral.vue b/ui/src/pages/ErrorGeneral.vue new file mode 100644 index 0000000..cd3d08e --- /dev/null +++ b/ui/src/pages/ErrorGeneral.vue @@ -0,0 +1,27 @@ + + + + + \ No newline at end of file From f056b9a414c265e40cac81b75d33c5d50eeeef8f Mon Sep 17 00:00:00 2001 From: George Petrakis Date: Fri, 13 Jun 2025 14:58:26 +0300 Subject: [PATCH 11/16] Fix: update getSend function to correctly append password as a query parameter --- ui/src/services/api.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ui/src/services/api.js b/ui/src/services/api.js index 6762eca..11ea582 100644 --- a/ui/src/services/api.js +++ b/ui/src/services/api.js @@ -43,12 +43,18 @@ export async function createSend(formData) { * @throws {Error} If the retrieval fails. */ export async function getSend(hash, password = '') { - const url = new URL(`${API_URL}/send/${hash}`); + // --- Start of Fix --- + // Construct the base URL string. + let url = `${API_URL}/send/${hash}`; + + // Manually append the password as a query parameter if it exists. if (password) { - url.searchParams.set('password', password); + const params = new URLSearchParams({ password }); + url += `?${params.toString()}`; } + // --- End of Fix --- - const res = await fetch(url); + const res = await fetch(url); // Use the resilient URL string. if (res.status === 404) { console.log('Secret not found.'); From 161b7ed497d0b3fd6836db938405d224ec9278e7 Mon Sep 17 00:00:00 2001 From: George Petrakis Date: Fri, 13 Jun 2025 15:03:36 +0300 Subject: [PATCH 12/16] Fix: update handleFile function to correctly handle both single files and arrays of files --- ui/src/pages/Create.vue | 8 ++++++-- ui/src/services/api.js | 3 --- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ui/src/pages/Create.vue b/ui/src/pages/Create.vue index 409e62a..aa6e567 100644 --- a/ui/src/pages/Create.vue +++ b/ui/src/pages/Create.vue @@ -100,8 +100,12 @@ const expirationOptions = [ { title: '1 Week', value: '168h' } ]; -function handleFile(files) { - fileBlob.value = files[0] || null; +function handleFile(fileOrFiles) { + if (Array.isArray(fileOrFiles)) { + fileBlob.value = fileOrFiles[0] || null; + } else { + fileBlob.value = fileOrFiles || null; + } } async function handleSubmit() { diff --git a/ui/src/services/api.js b/ui/src/services/api.js index 11ea582..ebe0005 100644 --- a/ui/src/services/api.js +++ b/ui/src/services/api.js @@ -43,8 +43,6 @@ export async function createSend(formData) { * @throws {Error} If the retrieval fails. */ export async function getSend(hash, password = '') { - // --- Start of Fix --- - // Construct the base URL string. let url = `${API_URL}/send/${hash}`; // Manually append the password as a query parameter if it exists. @@ -52,7 +50,6 @@ export async function getSend(hash, password = '') { const params = new URLSearchParams({ password }); url += `?${params.toString()}`; } - // --- End of Fix --- const res = await fetch(url); // Use the resilient URL string. From a7e57ce3892b78da85bb40c69e6fd8d531e75a52 Mon Sep 17 00:00:00 2001 From: George Petrakis Date: Fri, 13 Jun 2025 15:07:39 +0300 Subject: [PATCH 13/16] Feat: implement form reset functionality and update file handling in Create.vue --- ui/src/App.vue | 18 ++++++++++++------ ui/src/pages/Create.vue | 35 ++++++++++++++++++++++++++++------- ui/src/stores/formStore.js | 15 +++++++++++++++ 3 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 ui/src/stores/formStore.js diff --git a/ui/src/App.vue b/ui/src/App.vue index de55bac..5544cd5 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -2,26 +2,23 @@ - - + Logo - + mdi-plus Create - - © {{ new Date().getFullYear() }} GopherDrop | @@ -44,6 +41,15 @@ * The root component of the application. * Provides a header, navigation, and footer. */ +import { formStore } from './stores/formStore.js'; + +/** + * Triggers the form reset via the store. + * This will be picked up by a watcher in Create.vue. + */ +function requestFormReset() { + formStore.triggerReset(); +} + \ No newline at end of file diff --git a/ui/src/pages/Create.vue b/ui/src/pages/Create.vue index aa6e567..7df55d4 100644 --- a/ui/src/pages/Create.vue +++ b/ui/src/pages/Create.vue @@ -22,7 +22,7 @@ v-if="type === 'file'" label="Select File" prepend-icon="mdi-upload" - @update:modelValue="handleFile" + v-model="files" show-size required > @@ -75,13 +75,15 @@ + \ No newline at end of file diff --git a/ui/src/pages/ErrorGeneral.vue b/ui/src/pages/ErrorGeneral.vue index cd3d08e..0586404 100644 --- a/ui/src/pages/ErrorGeneral.vue +++ b/ui/src/pages/ErrorGeneral.vue @@ -1,12 +1,12 @@