From 586b0df3d7678101c786eef924d91beb716edc96 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 21 Sep 2024 21:09:26 +0200 Subject: [PATCH 1/2] feat: add csv_attachment component --- .../csv_attachment.sql | 6 ++++++ .../todo application (PostgreSQL)/index.sql | 6 +++++- sqlpage/templates/csv_attachment.handlebars | 6 ++++++ src/render.rs | 20 +++++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 examples/todo application (PostgreSQL)/csv_attachment.sql create mode 100644 sqlpage/templates/csv_attachment.handlebars diff --git a/examples/todo application (PostgreSQL)/csv_attachment.sql b/examples/todo application (PostgreSQL)/csv_attachment.sql new file mode 100644 index 00000000..8c37a9b8 --- /dev/null +++ b/examples/todo application (PostgreSQL)/csv_attachment.sql @@ -0,0 +1,6 @@ +select + 'csv_attachment' as component, + ';' as separator, + 'todo.csv' as filename; + +select * from todos; \ No newline at end of file diff --git a/examples/todo application (PostgreSQL)/index.sql b/examples/todo application (PostgreSQL)/index.sql index 699d08db..2217c300 100644 --- a/examples/todo application (PostgreSQL)/index.sql +++ b/examples/todo application (PostgreSQL)/index.sql @@ -17,4 +17,8 @@ select 'todo_form.sql' as link, 'green' as color, 'Add new todo' as title, - 'circle-plus' as icon; \ No newline at end of file + 'circle-plus' as icon; +select + '/csv_attachment.sql' as link, + 'Download' as title, + 'download' as icon; \ No newline at end of file diff --git a/sqlpage/templates/csv_attachment.handlebars b/sqlpage/templates/csv_attachment.handlebars new file mode 100644 index 00000000..774dc6cc --- /dev/null +++ b/sqlpage/templates/csv_attachment.handlebars @@ -0,0 +1,6 @@ +{{#each_row}} +{{#if (eq @row_index 0)}} +{{#each this}}{{@key}}{{#unless @last}}{{default ../../separator ","}}{{/unless}}{{/each}}{{../linebreak}} +{{/if}} +{{#each this}}{{this}}{{#unless @last}}{{default ../../separator ","}}{{/unless}}{{/each}}{{../linebreak}} +{{/each_row}} diff --git a/src/render.rs b/src/render.rs index 403124aa..69a07430 100644 --- a/src/render.rs +++ b/src/render.rs @@ -60,6 +60,7 @@ impl<'a, W: std::io::Write> HeaderContext { Some("http_header") => self.add_http_header(&data).map(PageContext::Header), Some("redirect") => self.redirect(&data).map(PageContext::Close), Some("json") => self.json(&data).map(PageContext::Close), + Some("csv_attachment") => self.csv_attachment(data).await, Some("cookie") => self.add_cookie(&data).map(PageContext::Header), Some("authentication") => self.authentication(data).await, _ => self.start_body(data).await, @@ -201,6 +202,25 @@ impl<'a, W: std::io::Write> HeaderContext { Ok(self.response.body(json_response)) } + async fn csv_attachment(mut self, data: JsonValue) -> anyhow::Result> { + let filename = data + .get("filename") + .and_then(JsonValue::as_str) + .unwrap_or("output.csv"); + + self.response + .insert_header((header::CONTENT_TYPE, "text/csv")) + .insert_header(( + header::CONTENT_DISPOSITION, + format!("attachment; filename=\"{}\"", filename), + )); + + self.request_context.is_embedded = true; + let page_content = self.start_body(data).await?; + + Ok(page_content) + } + async fn authentication(mut self, mut data: JsonValue) -> anyhow::Result> { let password_hash = take_object_str(&mut data, "password_hash"); let password = take_object_str(&mut data, "password"); From 13007566ba706ca328ec2ea954ac8e391dbe9f67 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 22 Sep 2024 22:14:16 +0200 Subject: [PATCH 2/2] fix: cargo fmt --- src/render.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render.rs b/src/render.rs index 69a07430..471459d5 100644 --- a/src/render.rs +++ b/src/render.rs @@ -202,7 +202,7 @@ impl<'a, W: std::io::Write> HeaderContext { Ok(self.response.body(json_response)) } - async fn csv_attachment(mut self, data: JsonValue) -> anyhow::Result> { + async fn csv_attachment(mut self, data: JsonValue) -> anyhow::Result> { let filename = data .get("filename") .and_then(JsonValue::as_str) @@ -214,7 +214,7 @@ impl<'a, W: std::io::Write> HeaderContext { header::CONTENT_DISPOSITION, format!("attachment; filename=\"{}\"", filename), )); - + self.request_context.is_embedded = true; let page_content = self.start_body(data).await?;