-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨(plugin) add notifications to courses
Add a new plugin to create warning or information notifications. This plugin is only available on course detail pages.
- Loading branch information
1 parent
e1ae633
commit 2272d34
Showing
16 changed files
with
342 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
src/frontend/scss/components/templates/courses/plugins/_notifications_plugin.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// change measurement units to rem | ||
.notification-alert { | ||
&__wrapper { | ||
display: flex; | ||
padding: 1rem; | ||
border-radius: r-theme-val(notification-plugin, border-radius); | ||
width: 100%; | ||
margin-block-end: 1rem; | ||
} | ||
|
||
&__icon { | ||
display: flex; | ||
align-items: center; | ||
padding: 1rem; | ||
margin-inline-end: 0.4rem; | ||
|
||
& svg { | ||
fill: none !important; | ||
stroke: r-theme-val(notification-plugin, icon-stroke-color); | ||
height: r-theme-val(notification-plugin, icon-height); | ||
width: r-theme-val(notification-plugin, icon-width); | ||
flex-shrink: 0; | ||
} | ||
} | ||
|
||
&__content { | ||
h2 { | ||
margin-block-start: 0.6rem; | ||
font-size: 0.9rem; | ||
} | ||
|
||
p { | ||
margin-block-end: 0.6rem; | ||
font-size: 0.9rem; | ||
} | ||
} | ||
} | ||
|
||
.info { | ||
background-color: r-theme-val(notification-plugin, info-background-color); | ||
color: r-theme-val(notification-plugin, text-color); | ||
} | ||
|
||
.warning { | ||
background-color: r-theme-val(notification-plugin, warn-background-color); | ||
color: r-theme-val(notification-plugin, text-color); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
""" | ||
Notification CMS plugin | ||
""" | ||
from django.utils.translation import gettext_lazy as _ | ||
|
||
from cms.plugin_base import CMSPluginBase | ||
from cms.plugin_pool import plugin_pool | ||
|
||
from richie.apps.core.defaults import PLUGINS_GROUP | ||
|
||
from .models import Notification | ||
|
||
|
||
@plugin_pool.register_plugin | ||
class NotificationPlugin(CMSPluginBase): | ||
""" | ||
A plugin to add plain text. | ||
""" | ||
|
||
allow_children = False | ||
cache = True | ||
disable_child_plugins = True | ||
fieldsets = ((None, {"fields": ["title", "message", "template"]}),) | ||
model = Notification | ||
module = PLUGINS_GROUP | ||
name = _("Notification") | ||
render_template = "richie/notification/notification.html" | ||
|
||
def render(self, context, instance, placeholder): | ||
""" | ||
Build plugin context passed to its template to perform rendering | ||
""" | ||
context = super().render(context, instance, placeholder) | ||
context.update({"instance": instance}) | ||
return context |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
""" | ||
PlainText CMS plugin factories | ||
""" | ||
import random | ||
|
||
import factory | ||
|
||
from .models import Notification | ||
|
||
|
||
class NotificationFactory(factory.django.DjangoModelFactory): | ||
""" | ||
Factory to create random instances of Notification for testing. | ||
""" | ||
|
||
class Meta: | ||
model = Notification | ||
|
||
title = factory.Faker("text", max_nb_chars=42) | ||
message = factory.Faker("text", max_nb_chars=42) | ||
template = ( | ||
Notification.NOTIFICATION_TYPES[1][0] | ||
if random.randint(0, 1) > 0 | ||
else Notification.NOTIFICATION_TYPES[0][0] | ||
) |
47 changes: 47 additions & 0 deletions
47
src/richie/plugins/notification/migrations/0001_initial.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Generated by Django 3.2.23 on 2024-01-15 14:58 | ||
|
||
import django.db.models.deletion | ||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
initial = True | ||
|
||
dependencies = [ | ||
("cms", "0022_auto_20180620_1551"), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name="Notification", | ||
fields=[ | ||
( | ||
"cmsplugin_ptr", | ||
models.OneToOneField( | ||
auto_created=True, | ||
on_delete=django.db.models.deletion.CASCADE, | ||
parent_link=True, | ||
primary_key=True, | ||
related_name="notification_notification", | ||
serialize=False, | ||
to="cms.cmsplugin", | ||
), | ||
), | ||
("title", models.CharField(blank=True, max_length=255)), | ||
("message", models.CharField(max_length=255, verbose_name="Message")), | ||
( | ||
"template", | ||
models.CharField( | ||
choices=[("info", "Information"), ("warning", "Warning")], | ||
default=("info", "Information"), | ||
max_length=16, | ||
verbose_name="Type", | ||
), | ||
), | ||
], | ||
options={ | ||
"abstract": False, | ||
}, | ||
bases=("cms.cmsplugin",), | ||
), | ||
] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
""" | ||
Notification plugin models | ||
""" | ||
from django.db import models | ||
from django.utils.translation import gettext_lazy as _ | ||
|
||
from cms.models.pluginmodel import CMSPlugin | ||
|
||
|
||
class Notification(CMSPlugin): | ||
""" | ||
Notification plugin model. | ||
To be user to output notification messages on course pages. | ||
""" | ||
|
||
NOTIFICATION_TYPES = ( | ||
("info", _("Information")), | ||
("warning", _("Warning")), | ||
) | ||
|
||
title = models.CharField(max_length=255, blank=True) | ||
message = models.CharField(_("Message"), max_length=255) | ||
template = models.CharField( | ||
_("Type"), | ||
choices=NOTIFICATION_TYPES, | ||
default=NOTIFICATION_TYPES[0], | ||
max_length=16, | ||
) |
16 changes: 16 additions & 0 deletions
16
src/richie/plugins/notification/templates/richie/notification/notification.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{% load i18n %} | ||
|
||
<div class="notification-alert__wrapper {{instance.template}}"> | ||
<div class="notification-alert__icon"> | ||
{% if instance.template == 'info' %} | ||
<svg xmlns="http://www.w3.org/2000/svg" id="info-icon" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg> | ||
{% else %} | ||
<svg xmlns="http://www.w3.org/2000/svg" id="warn-icon" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></path></svg> | ||
{% endif %} | ||
</div> | ||
<div class="notification-alert__content"> | ||
{% trans 'Warning' as transl_title %} | ||
<h2>{{ instance.title|default_if_none:transl_title }}</h2> | ||
<p>{{ instance.message }}</p> | ||
</div> | ||
</div> |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
"""Testing DjangoCMS plugin declaration for Richie's notifications plugin.""" | ||
from django.test import TestCase | ||
from django.test.client import RequestFactory | ||
|
||
from cms.api import add_plugin | ||
from cms.models import Placeholder | ||
from cms.plugin_rendering import ContentRenderer | ||
|
||
from richie.plugins.notification.cms_plugins import NotificationPlugin | ||
from richie.plugins.notification.factories import NotificationFactory | ||
|
||
|
||
class NotificationPluginTestCase(TestCase): | ||
"""Test suite for the notification plugin.""" | ||
|
||
def test_cms_plugins_notification_context_and_html(self): | ||
""" | ||
Instanciating this plugin with an instance should populate the context | ||
and render in the template. | ||
""" | ||
placeholder = Placeholder.objects.create(slot="test") | ||
|
||
# Create random values for parameters with a factory | ||
notification = NotificationFactory() | ||
fields_list = [ | ||
"title", | ||
"message", | ||
"template", | ||
] | ||
|
||
model_instance = add_plugin( | ||
placeholder, | ||
NotificationPlugin, | ||
"en", | ||
**{field: getattr(notification, field) for field in fields_list}, | ||
) | ||
plugin_instance = model_instance.get_plugin_class_instance() | ||
context = plugin_instance.render({}, model_instance, None) | ||
|
||
# Check if "instance" is in context | ||
self.assertIn("instance", context) | ||
|
||
# Check if parameters, generated by the factory, are correctly set in "instance" of context | ||
self.assertEqual(context["instance"].title, notification.title) | ||
self.assertEqual(context["instance"].message, notification.message) | ||
self.assertEqual(context["instance"].template, notification.template) | ||
|
||
# Get generated html for plain text body | ||
renderer = ContentRenderer(request=RequestFactory()) | ||
html = renderer.render_plugin(model_instance, {}) | ||
|
||
# Check rendered body is correct after save and sanitize | ||
self.assertIn(notification.title, html) | ||
self.assertIn(notification.message, html) | ||
self.assertIn(notification.template, html) | ||
|
||
def test_cms_plugins_notification_info_template(self): | ||
""" | ||
Instanciating this plugin with an instance to populate the context | ||
""" | ||
placeholder = Placeholder.objects.create(slot="test") | ||
|
||
# Create random values for parameters with a factory with an info template | ||
notification = NotificationFactory(template="info") | ||
fields_list = [ | ||
"title", | ||
"message", | ||
"template", | ||
] | ||
|
||
model_instance = add_plugin( | ||
placeholder, | ||
NotificationPlugin, | ||
"en", | ||
**{field: getattr(notification, field) for field in fields_list}, | ||
) | ||
|
||
# Get the generated html | ||
renderer = ContentRenderer(request=RequestFactory()) | ||
html = renderer.render_plugin(model_instance, {}) | ||
|
||
# Check that all expected elements are in the html | ||
self.assertIn('class="notification-alert__wrapper info"', html) | ||
self.assertIn('class="notification-alert__icon"', html) | ||
self.assertTrue('id="info-icon"' in html) | ||
|
||
def test_cms_plugins_notification_warn_template(self): | ||
""" | ||
Instanciating this plugin with an instance to populate the context | ||
""" | ||
placeholder = Placeholder.objects.create(slot="test") | ||
|
||
# Create random values for parameters with a factory with a warning template | ||
notification = NotificationFactory(template="warning") | ||
fields_list = [ | ||
"title", | ||
"message", | ||
"template", | ||
] | ||
|
||
model_instance = add_plugin( | ||
placeholder, | ||
NotificationPlugin, | ||
"en", | ||
**{field: getattr(notification, field) for field in fields_list}, | ||
) | ||
|
||
# Get the generated html | ||
renderer = ContentRenderer(request=RequestFactory()) | ||
html = renderer.render_plugin(model_instance, {}) | ||
|
||
# Check that all expected elements are in the html | ||
self.assertIn('class="notification-alert__wrapper warning"', html) | ||
self.assertIn('class="notification-alert__icon"', html) | ||
self.assertTrue('id="warn-icon"' in html) |