Skip to content

Optional html blocks in markdown #856

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 17, 2025

Conversation

lovasoa
Copy link
Collaborator

@lovasoa lovasoa commented Mar 16, 2025

No description provided.

…nsafe optional parameter to MarkdownHelper, add tests for various permutations, extend text.handlebars to pass through parameter
Comment on lines +255 to +269
pub trait MarkdownConfig {
fn allow_dangerous_html(&self) -> bool;
fn allow_dangerous_protocol(&self) -> bool;
}

impl MarkdownConfig for AppConfig {
fn allow_dangerous_html(&self) -> bool {
self.markdown_allow_dangerous_html
}

fn allow_dangerous_protocol(&self) -> bool {
self.markdown_allow_dangerous_protocol
}
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is overkill

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to avoid testing with a full AppConfig. Do you have a better alternative in mind?

Copy link
Collaborator Author

@lovasoa lovasoa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the pr, @guspower ! I made some comments.


if !options.compile.allow_dangerous_html && args.len() > 1 {
let arg = &args[1];
if arg.relative_path() == Some(&Self::ALLOW_UNSAFE.to_string()) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's strange to use the path instead of the value. This means you cannot pass a variable to your helper. We should probably read the string value of the argument here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was based on my logging of what was going on with different combinations passed into the handler; I'll switch it to use the variable.

@@ -8,7 +8,7 @@
{{~/if~}}
{{~#if contents_md~}}
<div class="remove-bottom-margin {{#if center}}mx-auto{{/if}} {{#if article}}markdown article-text{{/if}}">
{{{~markdown contents_md~}}}
{{{~markdown contents_md allow_unsafe~}}}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the syntax should look like

Suggested change
{{{~markdown contents_md allow_unsafe~}}}
{{{~markdown contents_md 'allow_unsafe'~}}}

(pass a string to the helper)

@lovasoa
Copy link
Collaborator Author

lovasoa commented Mar 17, 2025

We don't want to take any existing safe code and make it unsafe. If we enable allow_unsafe somewhere, it should be in a new argument, with a big warning in the documentation.

@lovasoa
Copy link
Collaborator Author

lovasoa commented Mar 17, 2025

We should also document the new options to the markdown helper: https://sql-page.com/custom_components.sql

@guspower
Copy link
Contributor

We don't want to take any existing safe code and make it unsafe. If we enable allow_unsafe somewhere, it should be in a new argument, with a big warning in the documentation.

OK can you elaborate a bit further on this point so that I can better understand, specifically around the implementation details? If we use a hard coded string 'allow_unsafe' rather than reading a variable of the same name, this means that the user will have to create their own templates that supply that value rather than use the existing components? Sorry, I'm probably misunderstanding this point.

@lovasoa
Copy link
Collaborator Author

lovasoa commented Mar 17, 2025

I mean that all sqlpage code that exists today should continue to work as is in the next version. So we cannot take an existing contents_md that is safe today and make it unsafe. Instead, we should add a new unsafe_contents_md property. Users can explicitly switch to it if they assess it's safe in their case.

@guspower
Copy link
Contributor

I mean that all sqlpage code that exists today should continue to work as is in the next version. So we cannot take an existing contents_md that is safe today and make it unsafe. Instead, we should add a new unsafe_contents_md property. Users can explicitly switch to it if they assess it's safe in their case.

Right - gotcha; thanks for the explanation +1

@guspower
Copy link
Contributor

OK I've updated the implementation and extended the docs. Let me know what you think.

@lovasoa
Copy link
Collaborator Author

lovasoa commented Mar 17, 2025

@guspower , what about this:

diff --git a/src/template_helpers.rs b/src/template_helpers.rs
index 7be62c9..f6590c6 100644
--- a/src/template_helpers.rs
+++ b/src/template_helpers.rs
@@ -274,8 +274,6 @@ struct MarkdownHelper {
 }
 
 impl MarkdownHelper {
-    const ALLOW_UNSAFE: &'static str = "allow_unsafe";
-
     fn new(config: &impl MarkdownConfig) -> Self {
         Self {
             allow_dangerous_html: config.allow_dangerous_html(),
@@ -283,38 +281,39 @@ impl MarkdownHelper {
         }
     }
 
-    fn calculate_options(&self, args: &[PathAndJson]) -> markdown::Options {
-        let mut options = self.system_options();
-
-        if !options.compile.allow_dangerous_html && args.len() > 1 {
-            if let Some(arg) = args.get(1) {
-                if arg.value().as_str() == Some(Self::ALLOW_UNSAFE) {
-                    options.compile.allow_dangerous_html = true;
-                }
-            }
-        }
-
-        options
-    }
-
-    fn system_options(&self) -> markdown::Options {
+    fn system_options(&self, preset_name: &str) -> Result<markdown::Options, String> {
         let mut options = markdown::Options::gfm();
         options.compile.allow_dangerous_html = self.allow_dangerous_html;
         options.compile.allow_dangerous_protocol = self.allow_dangerous_protocol;
         options.compile.allow_any_img_src = true;
 
-        options
+        match preset_name {
+            "default" => {}
+            "allow_unsafe" => {
+                options.compile.allow_dangerous_html = true;
+                options.compile.allow_dangerous_protocol = true;
+            }
+            _ => return Err(format!("unknown markdown preset: {preset_name}")),
+        }
+
+        Ok(options)
     }
 }
 
 impl CanHelp for MarkdownHelper {
     fn call(&self, args: &[PathAndJson]) -> Result<JsonValue, String> {
-        let options = self.calculate_options(args);
-        let as_str = match args {
-            [v] | [v, _] => v.value(),
-            _ => return Err("expected one or two arguments".to_string()),
+        let (markdown_src_value, preset_name) = match args {
+            [v] => (v.value(), "default"),
+            [v, preset] => (
+                v.value(),
+                preset
+                    .value()
+                    .as_str()
+                    .ok_or("markdown template helper expects a string as preset name")?,
+            ),
+            _ => return Err("markdown template helper expects one or two arguments".to_string()),
         };
-        let as_str = match as_str {
+        let markdown_src = match markdown_src_value {
             JsonValue::String(s) => Cow::Borrowed(s),
             JsonValue::Array(arr) => Cow::Owned(
                 arr.iter()
@@ -326,7 +325,8 @@ impl CanHelp for MarkdownHelper {
             other => Cow::Owned(other.to_string()),
         };
 
-        markdown::to_html_with_options(&as_str, &options)
+        let options = self.system_options(preset_name)?;
+        markdown::to_html_with_options(&markdown_src, &options)
             .map(JsonValue::String)
             .map_err(|e| e.to_string())
     }

@lovasoa
Copy link
Collaborator Author

lovasoa commented Mar 17, 2025

This produces more meaningful errors when the helper is not used as expected

@guspower
Copy link
Contributor

Yep that looks good to me. My only comment would be to rename system_options to something like get_preset_options perhaps.

@lovasoa lovasoa merged commit f0329cd into sqlpage:main Mar 17, 2025
10 checks passed
@lovasoa
Copy link
Collaborator Author

lovasoa commented Mar 17, 2025

Thanks @guspower ! It's merged !

@guspower guspower deleted the optional-html-blocks-in-markdown branch March 17, 2025 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants