diff --git a/backend/src/handlers/posts.rs b/backend/src/handlers/posts.rs index b9755b1..a30df0e 100644 --- a/backend/src/handlers/posts.rs +++ b/backend/src/handlers/posts.rs @@ -30,6 +30,29 @@ pub async fn create_post( .join("posts") .join(format!("{}.md", payload.slug)); + // Handle renaming + if let Some(ref old_slug) = payload.old_slug { + if old_slug != &payload.slug { + let old_file_path = state.data_dir.join("posts").join(format!("{}.md", old_slug)); + if old_file_path.exists() { + // If new path already exists and it's different from old path, error out + if file_path.exists() { + return Err(AppError::BadRequest( + "A post with this new title already exists".to_string(), + )); + } + if let Err(e) = fs::rename(&old_file_path, &file_path) { + error!("Rename error from {} to {}: {}", old_slug, payload.slug, e); + return Err(AppError::Internal( + "Rename error".to_string(), + Some(e.to_string()), + )); + } + info!("Renamed post from {} to {}", old_slug, payload.slug); + } + } + } + let mut file_content = String::new(); if let Some(ref summary) = payload.summary { if !summary.trim().is_empty() { diff --git a/backend/src/models.rs b/backend/src/models.rs index be67440..e1ee832 100644 --- a/backend/src/models.rs +++ b/backend/src/models.rs @@ -44,6 +44,7 @@ pub struct PostDetail { #[derive(Deserialize)] pub struct CreatePostRequest { pub slug: String, + pub old_slug: Option, pub summary: Option, pub content: String, } diff --git a/frontend/src/pages/admin/editor.astro b/frontend/src/pages/admin/editor.astro index 5c78e8d..d99af13 100644 --- a/frontend/src/pages/admin/editor.astro +++ b/frontend/src/pages/admin/editor.astro @@ -21,7 +21,7 @@ import AdminLayout from '../../layouts/AdminLayout.astro'; target="_blank" class="hidden bg-blue text-crust font-bold py-3 px-8 rounded-lg hover:bg-sky transition-all transform hover:scale-105 w-full md:w-auto whitespace-nowrap items-center justify-center gap-2" > - + View Post @@ -30,7 +30,7 @@ import AdminLayout from '../../layouts/AdminLayout.astro';
- + { const payload = { slug: slugInput.value, + old_slug: originalSlug || null, summary: summaryInput.value || null, content: editor.getValue() }; if (!payload.slug || !payload.content) { - showAlert('Slug and content are required.', 'error'); + showAlert('Title and content are required.', 'error'); return; } try { @@ -333,13 +336,15 @@ import AdminLayout from '../../layouts/AdminLayout.astro'; }); if (res.ok) { showAlert('Post saved!', 'success'); + originalSlug = payload.slug; // Update for next save if (viewPostBtn) { viewPostBtn.href = `/posts/${payload.slug}`; viewPostBtn.classList.remove('hidden'); viewPostBtn.classList.add('inline-flex'); } } else { - showAlert('Error saving post.', 'error'); + const err = await res.json(); + showAlert(`Error: ${err.error}`, 'error'); } } catch (err) { showAlert('Failed to connect to server.', 'error'); @@ -347,15 +352,16 @@ import AdminLayout from '../../layouts/AdminLayout.astro'; }); delBtn?.addEventListener('click', async () => { - if (confirm(`Delete post "${slugInput.value}" permanently?`)) { + const slugToDelete = originalSlug || slugInput.value; + if (confirm(`Delete post "${slugToDelete}" permanently?`)) { try { - const res = await fetch(`/api/posts/${encodeURIComponent(slugInput.value)}`, { + const res = await fetch(`/api/posts/${encodeURIComponent(slugToDelete)}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }); if (res.ok) window.location.href = '/admin'; else showAlert('Error deleting post.', 'error'); - } catch (err) { + } catch (e) { showAlert('Connection error.', 'error'); } } @@ -365,7 +371,7 @@ import AdminLayout from '../../layouts/AdminLayout.astro'; const editSlug = urlParams.get('edit'); if (editSlug) { slugInput.value = editSlug; - slugInput.disabled = true; // Protect slug on edit + originalSlug = editSlug; delBtn?.classList.remove('hidden'); if (viewPostBtn) { diff --git a/frontend/src/pages/admin/index.astro b/frontend/src/pages/admin/index.astro index 8f02e6c..57f354c 100644 --- a/frontend/src/pages/admin/index.astro +++ b/frontend/src/pages/admin/index.astro @@ -76,9 +76,8 @@ import AdminLayout from '../../layouts/AdminLayout.astro'; div.innerHTML = `

${post.slug}

-

/posts/${post.slug}

-
-
+

/posts/${post.slug}

+