Repository: zostera/django-bootstrap4

Issue:
Putting a link in bootstrap_alert
How do I put a link in `bootstrap_alert`?

```
msg=mark_safe('Please visit our forum site <a href="talk.edgle.com" class="alert-link">Edgle Talk</a> as well!')

render_alert(msg)
'<div class="alert alert-info alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>Please visit our forum site &lt;a href=&quot;talk.edgle.com&quot; class=&quot;alert-link&quot;&gt;Edgle Talk&lt;/a&gt; as well!</div>'
```

As seen, html elements are escaped due to the following chain of commands: 

bootstrap_alert -> render_alert -> render_tag ->format_html -> conditional_escape


Discussion:
The problem is here `render_alert` line: 26:

`content=button_placeholder + text_value(content),`

str + SafeText => str
And it would be solved if '\__\__BUTTON\__\__' was marked safe (line 22). 

Resolving patch:
diff --git a/src/bootstrap4/components.py b/src/bootstrap4/components.py
--- a/src/bootstrap4/components.py
+++ b/src/bootstrap4/components.py
@@ -21,6 +21,6 @@ def render_alert(content, alert_type=None, dismissible=True):
         render_tag(
             "div",
             attrs={"class": " ".join(css_classes), "role": "alert"},
-            content=button_placeholder + text_value(content),
+            content=mark_safe(button_placeholder) + text_value(content),
         ).replace(button_placeholder, button)
     )


Test patch:
diff --git a/tests/test_components.py b/tests/test_components.py
--- a/tests/test_components.py
+++ b/tests/test_components.py
@@ -1,10 +1,11 @@
 from django.test import TestCase
+from django.utils.safestring import mark_safe
 
 from bootstrap4.components import render_alert
 
 
 class ComponentsTest(TestCase):
-    def test_render_alert_with_type(self):
+    def test_render_alert_without_type(self):
         alert = render_alert("content")
         self.assertEqual(
             alert,
@@ -13,3 +14,35 @@ def test_render_alert_with_type(self):
             + 'aria-label="close">'
             + "&times;</button>content</div>",
         )
+
+    def test_render_alert_with_type(self):
+        alert = render_alert("content", alert_type="danger")
+        self.assertEqual(
+            alert,
+            '<div class="alert alert-danger alert-dismissible" role="alert">'
+            + '<button type="button" class="close" data-dismiss="alert" '
+            + 'aria-label="close">'
+            + "&times;</button>content</div>",
+        )
+
+    def test_render_alert_with_safe_content(self):
+        msg = mark_safe('This is <a href="https://example.com" class="alert-link">a safe link</a>!')
+        alert = render_alert(msg)
+        self.assertEqual(
+            alert,
+            '<div class="alert alert-info alert-dismissible" role="alert">'
+            + '<button type="button" class="close" data-dismiss="alert" '
+            + 'aria-label="close">'
+            + '&times;</button>This is <a href="https://example.com" class="alert-link">a safe link</a>!</div>',
+        )
+
+    def test_render_alert_with_unsafe_content(self):
+        msg = "This is <b>unsafe</b>!"
+        alert = render_alert(msg)
+        self.assertEqual(
+            alert,
+            '<div class="alert alert-info alert-dismissible" role="alert">'
+            + '<button type="button" class="close" data-dismiss="alert" '
+            + 'aria-label="close">'
+            + "&times;</button>This is &lt;b&gt;unsafe&lt;/b&gt;!</div>",
+        )