add edit blog feature
This commit is contained in:
parent
e31a7fe09e
commit
7c294a5ecb
@ -223,6 +223,66 @@ pub fn delete(id: []const u8, request: *jetzig.Request) !jetzig.View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// blogs/:id/edit
|
||||||
|
pub fn edit(id: []const u8, request: *jetzig.Request) !jetzig.View {
|
||||||
|
// check "session" cookie for authentication
|
||||||
|
const cookies = try request.cookies();
|
||||||
|
const session = cookies.get("session") orelse {
|
||||||
|
return request.fail(.not_found);
|
||||||
|
};
|
||||||
|
|
||||||
|
const session_query = jetzig.database.Query(.Session)
|
||||||
|
.findBy(.{ .session_id = session.value });
|
||||||
|
|
||||||
|
_ = request.repo.execute(session_query) catch {
|
||||||
|
return request.fail(.not_found);
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (request.method) {
|
||||||
|
.GET => {
|
||||||
|
// get blog
|
||||||
|
const blog_query = jetzig.database.Query(.Blog)
|
||||||
|
.find(try std.fmt.parseInt(i32, id, 10));
|
||||||
|
|
||||||
|
const blog = request.repo.execute(blog_query) catch {
|
||||||
|
return request.fail(.not_found);
|
||||||
|
};
|
||||||
|
|
||||||
|
const root = try request.data(.object);
|
||||||
|
try root.put("allowed", true);
|
||||||
|
try root.put("blog", blog);
|
||||||
|
|
||||||
|
return request.render(.ok);
|
||||||
|
},
|
||||||
|
.POST => {
|
||||||
|
// make two queries for now
|
||||||
|
const params = try request.params();
|
||||||
|
|
||||||
|
const blog_query_original = jetzig.database.Query(.Blog)
|
||||||
|
.find(try std.fmt.parseInt(i32, id, 10));
|
||||||
|
|
||||||
|
if (try request.repo.execute(blog_query_original)) |blog| {
|
||||||
|
const title = params.getT(.string, "title") orelse blog.title;
|
||||||
|
const content = params.getT(.string, "content") orelse blog.content;
|
||||||
|
const preview = params.getT(.string, "preview") orelse blog.blob;
|
||||||
|
|
||||||
|
// query the blogpost first
|
||||||
|
const blog_query = jetzig.database.Query(.Blog)
|
||||||
|
.update(.{ .title = title, .blob = preview, .content = content })
|
||||||
|
.where(.{ .id = try std.fmt.parseInt(i32, id, 10) });
|
||||||
|
|
||||||
|
// update the blogpost
|
||||||
|
try request.repo.execute(blog_query);
|
||||||
|
|
||||||
|
return request.redirect("/blogs", .moved_permanently);
|
||||||
|
} else {
|
||||||
|
return request.fail(.not_found);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => return request.fail(.not_found),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "index" {
|
test "index" {
|
||||||
var app = try jetzig.testing.app(std.testing.allocator, @import("routes"));
|
var app = try jetzig.testing.app(std.testing.allocator, @import("routes"));
|
||||||
defer app.deinit();
|
defer app.deinit();
|
||||||
|
46
src/app/views/blogs/edit.zmpl
Normal file
46
src/app/views/blogs/edit.zmpl
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<div class="max-w-2xl mx-auto mt-10 p-6 bg-white border border-win7-border shadow-md rounded-2xl font-sans text-win7-text">
|
||||||
|
<form action="/blogs/{{.blog.id}}/edit" method="POST" class="space-y-6">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="title" class="block text-sm font-medium mb-1">Title</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="title"
|
||||||
|
id="title"
|
||||||
|
value="{{.blog.title}}"
|
||||||
|
required
|
||||||
|
class="mt-1 w-full px-4 py-2 bg-white border border-win7-border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-win7-hover focus:border-win7-hover transition"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="content" class="block text-sm font-medium mb-1">Content</label>
|
||||||
|
<textarea
|
||||||
|
name="content"
|
||||||
|
id="content"
|
||||||
|
rows="8"
|
||||||
|
required
|
||||||
|
class="mt-1 w-full px-4 py-2 bg-white border border-win7-border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-win7-hover focus:border-win7-hover transition"
|
||||||
|
>{{.blog.content}}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="preview" class="block text-sm font-medium mb-1">Preview</label>
|
||||||
|
<textarea
|
||||||
|
name="preview"
|
||||||
|
id="preview"
|
||||||
|
rows="3"
|
||||||
|
class="mt-1 w-full px-4 py-2 bg-white border border-win7-border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-win7-hover focus:border-win7-hover transition"
|
||||||
|
>{{.blog.blob}}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="submit"
|
||||||
|
value="Save Changes"
|
||||||
|
class="px-4 py-2 bg-win7-link text-white font-semibold rounded-md shadow hover:bg-win7-hover transition"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
@ -3,25 +3,27 @@
|
|||||||
<div class="max-w-3xl mx-auto mt-10 space-y-6 font-sans">
|
<div class="max-w-3xl mx-auto mt-10 space-y-6 font-sans">
|
||||||
@for (.blogs) |blog| {
|
@for (.blogs) |blog| {
|
||||||
<div class="p4 bg-win7-bg border border-win7-border rounded-xl px-5 py-4 shadow-sm hover:shadow-md transition duration-150">
|
<div class="p4 bg-win7-bg border border-win7-border rounded-xl px-5 py-4 shadow-sm hover:shadow-md transition duration-150">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<a href="/blogs/{{blog.id}}" class="text-xl font-semibold text-win7-link hover:underline transition">
|
<a href="/blogs/{{blog.id}}" class="text-xl font-semibold text-win7-link hover:underline transition">{{blog.title}}</a>
|
||||||
{{blog.title}}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
@if ($.allowed)
|
@if ($.allowed)
|
||||||
<button
|
<div class="flex items-center gap-4">
|
||||||
id="delete-post-{{blog.id}}"
|
<a href="/blogs/{{blog.id}}/edit"
|
||||||
class="text-sm text-win7-red hover:text-red-800 transition"
|
class="text-sm text-win7-link hover:underline transition"
|
||||||
>
|
>
|
||||||
Delete
|
Edit
|
||||||
</button>
|
</a>
|
||||||
@end
|
<button
|
||||||
</div>
|
id="delete-post-{{blog.id}}"
|
||||||
|
class="text-sm text-win7-red hover:text-red-800 transition"
|
||||||
<p class="text-xs text-[#4a5c75] mt-2">
|
>
|
||||||
{{zmpl.fmt.datetime(blog.get("created_at"), "%Y-%m-%d %H:%M")}}
|
Delete
|
||||||
</p>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@end
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-[#4a5c75] mt-2">{{zmpl.fmt.datetime(blog.get("created_at"), "%Y-%m-%d %H:%M")}}</p>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if ($.allowed)
|
@if ($.allowed)
|
||||||
@ -35,22 +37,22 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if ($.allowed)
|
@if ($.allowed)
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
document.querySelectorAll('[id^="delete-post-"]').forEach(button => {
|
document.querySelectorAll('[id^="delete-post-"]').forEach(button => {
|
||||||
button.addEventListener("click", () => {
|
button.addEventListener("click", () => {
|
||||||
const id = button.id.replace("delete-post-", "");
|
const id = button.id.replace("delete-post-", "");
|
||||||
fetch(`/blogs/${id}`, {
|
fetch(`/blogs/${id}`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(() => window.location.reload())
|
.then(() => window.location.reload())
|
||||||
.catch(err => console.error("Failed to delete post:", err));
|
.catch(err => console.error("Failed to delete post:", err));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -105,6 +105,8 @@ pub const jetzig_options = struct {
|
|||||||
|
|
||||||
pub fn init(app: *jetzig.App) !void {
|
pub fn init(app: *jetzig.App) !void {
|
||||||
app.route(.GET, "/rss.xml", @import("app/views/rss.zig"), .index);
|
app.route(.GET, "/rss.xml", @import("app/views/rss.zig"), .index);
|
||||||
|
app.route(.GET, "/blogs/:id/edit" , @import("app/views/blogs.zig"), .edit);
|
||||||
|
app.route(.POST, "/blogs/:id/edit" , @import("app/views/blogs.zig"), .edit);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user