mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-13 22:40:16 +02:00
Improve notifications
This commit is contained in:
parent
131cc5ed0a
commit
75bccf1b0f
@ -1,9 +1,3 @@
|
|||||||
|
from .core import notify # noqa: F401
|
||||||
|
|
||||||
default_app_config = 'allianceauth.notifications.apps.NotificationsConfig'
|
default_app_config = 'allianceauth.notifications.apps.NotificationsConfig'
|
||||||
|
|
||||||
|
|
||||||
def notify(
|
|
||||||
user: object, title: str, message: str = None, level: str = 'info'
|
|
||||||
) -> None:
|
|
||||||
"""Sends a new notification to user. Convenience function to manager pendant."""
|
|
||||||
from .models import Notification
|
|
||||||
Notification.objects.notify_user(user, title, message, level)
|
|
||||||
|
33
allianceauth/notifications/core.py
Normal file
33
allianceauth/notifications/core.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
class NotifyApiWrapper:
|
||||||
|
"""Wrapper to create notify API."""
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs): # provide old API for backwards compatibility
|
||||||
|
return self._add_notification(*args, **kwargs)
|
||||||
|
|
||||||
|
def danger(self, user: object, title: str, message: str = None) -> None:
|
||||||
|
"""Add danger notification for user."""
|
||||||
|
self._add_notification(user, title, message, level="danger")
|
||||||
|
|
||||||
|
def info(self, user: object, title: str, message: str = None) -> None:
|
||||||
|
"""Add info notification for user."""
|
||||||
|
self._add_notification(user=user, title=title, message=message, level="info")
|
||||||
|
|
||||||
|
def success(self, user: object, title: str, message: str = None) -> None:
|
||||||
|
"""Add success notification for user."""
|
||||||
|
self._add_notification(user, title, message, level="success")
|
||||||
|
|
||||||
|
def warning(self, user: object, title: str, message: str = None) -> None:
|
||||||
|
"""Add warning notification for user."""
|
||||||
|
self._add_notification(user, title, message, level="warning")
|
||||||
|
|
||||||
|
def _add_notification(
|
||||||
|
self, user: object, title: str, message: str = None, level: str = "info"
|
||||||
|
) -> None:
|
||||||
|
from .models import Notification
|
||||||
|
|
||||||
|
Notification.objects.notify_user(
|
||||||
|
user=user, title=title, message=message, level=level
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
notify = NotifyApiWrapper()
|
@ -5,91 +5,34 @@
|
|||||||
{% block page_title %}{% translate "Notifications" %}{% endblock %}
|
{% block page_title %}{% translate "Notifications" %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<h1 class="page-header text-center">{% translate "Notifications" %}</h1>
|
||||||
<h1 class="page-header text-center">{% translate "Notifications" %}</h1>
|
|
||||||
<div class="col-lg-12 container" id="example">
|
<div class="panel panel-default">
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
<div class="panel-heading">
|
||||||
<div class="panel panel-default">
|
<ul class="nav nav-pills">
|
||||||
<div class="panel-heading">
|
<li class="active"><a data-toggle="tab" href="#unread">{% translate "Unread" %}<b>({{ unread|length }})</b></a></li>
|
||||||
<ul class="nav nav-pills">
|
<li><a data-toggle="tab" href="#read">{% translate "Read" %} <b>({{ read|length }})</b></a></li>
|
||||||
<li class="active"><a data-toggle="pill" href="#unread">{% translate "Unread" %}
|
<div class="pull-right">
|
||||||
<b>({{ unread|length }})</b></a></li>
|
<a href="{% url 'notifications:mark_all_read' %}" class="btn btn-warning">{% translate "Mark All Read" %}</a>
|
||||||
<li><a data-toggle="pill" href="#read">{% translate "Read" %} <b>({{ read|length }})</b></a>
|
<a href="{% url 'notifications:delete_all_read' %}" class="btn btn-danger">{% translate "Delete All Read" %}</a>
|
||||||
</li>
|
|
||||||
<div class="pull-right">
|
|
||||||
<a href="{% url 'notifications:mark_all_read' %}" class="btn btn-primary">{% translate "Mark All Read" %}</a>
|
|
||||||
<a href="{% url 'notifications:delete_all_read' %}" class="btn btn-danger">{% translate "Delete All Read" %}</a>
|
|
||||||
</div>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<div class="tab-content">
|
|
||||||
<div id="unread" class="tab-pane fade in active">
|
|
||||||
<div class="table-responsive">
|
|
||||||
{% if unread %}
|
|
||||||
<table class="table table-condensed table-hover table-striped">
|
|
||||||
<tr>
|
|
||||||
<th class="text-center">{% translate "Timestamp" %}</th>
|
|
||||||
<th class="text-center">{% translate "Title" %}</th>
|
|
||||||
<th class="text-center">{% translate "Action" %}</th>
|
|
||||||
</tr>
|
|
||||||
{% for notif in unread %}
|
|
||||||
<tr class="{{ notif.level }}">
|
|
||||||
<td class="text-center">{{ notif.timestamp }}</td>
|
|
||||||
<td class="text-center">{{ notif.title }}</td>
|
|
||||||
<td class="text-center">
|
|
||||||
<a href="{% url 'notifications:view' notif.id %}" class="btn btn-success" title="View">
|
|
||||||
<span class="glyphicon glyphicon-eye-open"></span>
|
|
||||||
</a>
|
|
||||||
<a href="{% url 'notifications:remove' notif.id %}" class="btn btn-danger" title="Remove">
|
|
||||||
<span class="glyphicon glyphicon-remove"></span>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
<div class="alert alert-warning text-center">{% translate "No unread notifications." %}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="read" class="tab-pane fade">
|
|
||||||
<div class="panel-body">
|
|
||||||
<div class="table-responsive">
|
|
||||||
{% if read %}
|
|
||||||
<table class="table table-condensed table-hover table-striped">
|
|
||||||
<tr>
|
|
||||||
<th class="text-center">{% translate "Timestamp" %}</th>
|
|
||||||
<th class="text-center">{% translate "Title" %}</th>
|
|
||||||
<th class="text-center">{% translate "Action" %}</th>
|
|
||||||
</tr>
|
|
||||||
{% for notif in read %}
|
|
||||||
<tr class="{{ notif.level }}">
|
|
||||||
<td class="text-center">{{ notif.timestamp }}</td>
|
|
||||||
<td class="text-center">{{ notif.title }}</td>
|
|
||||||
<td class="text-center">
|
|
||||||
<a href="{% url 'notifications:view' notif.id %}" class="btn btn-success" title="View">
|
|
||||||
<span class="glyphicon glyphicon-eye-open"></span>
|
|
||||||
</a>
|
|
||||||
<a href="{% url 'notifications:remove' notif.id %}" class="btn btn-danger" title="remove">
|
|
||||||
<span class="glyphicon glyphicon-remove"></span>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
<div class="alert alert-warning text-center">{% translate "No read notifications." %}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="tab-content">
|
||||||
|
|
||||||
|
<div id="unread" class="tab-pane fade in active">
|
||||||
|
{% include "notifications/list_partial.html" with notifications=unread %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="read" class="tab-pane fade">
|
||||||
|
{% include "notifications/list_partial.html" with notifications=read %}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% if notifications %}
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-condensed table-hover table-striped">
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">{% translate "Timestamp" %}</th>
|
||||||
|
<th class="text-center">{% translate "Title" %}</th>
|
||||||
|
<th class="text-center">{% translate "Action" %}</th>
|
||||||
|
</tr>
|
||||||
|
{% for notif in notifications %}
|
||||||
|
<tr class="{{ notif.level }}">
|
||||||
|
<td class="text-center">{{ notif.timestamp }}</td>
|
||||||
|
<td class="text-center">{{ notif.title }}</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<a href="{% url 'notifications:view' notif.id %}" class="btn btn-primary" title="View">
|
||||||
|
<span class="glyphicon glyphicon-eye-open"></span>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'notifications:remove' notif.id %}" class="btn btn-danger" title="Remove">
|
||||||
|
<span class="glyphicon glyphicon-remove"></span>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-default text-center">{% translate "No notifications." %}</div>
|
||||||
|
{% endif %}
|
@ -5,25 +5,22 @@
|
|||||||
{% block page_title %}{% translate "View Notification" %}{% endblock page_title %}
|
{% block page_title %}{% translate "View Notification" %}{% endblock page_title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<h1 class="page-header text-center">
|
||||||
|
{% translate "View Notification" %}
|
||||||
|
<div class="text-right">
|
||||||
|
<a href="{% url 'notifications:list' %}" class="btn btn-primary btn-lg">
|
||||||
|
<span class="glyphicon glyphicon-arrow-left"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</h1>
|
||||||
|
|
||||||
<div class="col-lg-12">
|
<div class="row">
|
||||||
<h1 class="page-header text-center">
|
<div class="col-lg-12">
|
||||||
{% translate "View Notification" %}
|
<div class="panel panel-{{ notif.level }}">
|
||||||
<div class="text-right">
|
<div class="panel-heading">{{ notif.timestamp }} {{ notif.title }}</div>
|
||||||
<a href="{% url 'notifications:list' %}" class="btn btn-primary btn-lg">
|
<div class="panel-body"><pre>{{ notif.message }}</pre></div>
|
||||||
<span class="glyphicon glyphicon-arrow-left"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</h1>
|
|
||||||
<div class="col-lg-12 container">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<div class="panel panel-{{ notif.level }}">
|
|
||||||
<div class="panel-heading">{{ notif.timestamp }} {{ notif.title }}</div>
|
|
||||||
<div class="panel-body"><pre>{{ notif.message }}</pre></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
85
allianceauth/notifications/tests/test_core.py
Normal file
85
allianceauth/notifications/tests/test_core.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
|
||||||
|
from ..core import NotifyApiWrapper
|
||||||
|
from ..models import Notification
|
||||||
|
|
||||||
|
|
||||||
|
class TestUserNotificationCount(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls) -> None:
|
||||||
|
super().setUpClass()
|
||||||
|
cls.user = AuthUtils.create_user("bruce_wayne")
|
||||||
|
|
||||||
|
def test_should_add_danger_notification(self):
|
||||||
|
# given
|
||||||
|
notify = NotifyApiWrapper()
|
||||||
|
# when
|
||||||
|
notify.danger(user=self.user, title="title", message="message")
|
||||||
|
# then
|
||||||
|
obj = Notification.objects.first()
|
||||||
|
self.assertEqual(obj.user, self.user)
|
||||||
|
self.assertEqual(obj.title, "title")
|
||||||
|
self.assertEqual(obj.message, "message")
|
||||||
|
self.assertEqual(obj.level, Notification.Level.DANGER)
|
||||||
|
|
||||||
|
def test_should_add_info_notification(self):
|
||||||
|
# given
|
||||||
|
notify = NotifyApiWrapper()
|
||||||
|
# when
|
||||||
|
notify.info(user=self.user, title="title", message="message")
|
||||||
|
# then
|
||||||
|
obj = Notification.objects.first()
|
||||||
|
self.assertEqual(obj.user, self.user)
|
||||||
|
self.assertEqual(obj.title, "title")
|
||||||
|
self.assertEqual(obj.message, "message")
|
||||||
|
self.assertEqual(obj.level, Notification.Level.INFO)
|
||||||
|
|
||||||
|
def test_should_add_success_notification(self):
|
||||||
|
# given
|
||||||
|
notify = NotifyApiWrapper()
|
||||||
|
# when
|
||||||
|
notify.success(user=self.user, title="title", message="message")
|
||||||
|
# then
|
||||||
|
obj = Notification.objects.first()
|
||||||
|
self.assertEqual(obj.user, self.user)
|
||||||
|
self.assertEqual(obj.title, "title")
|
||||||
|
self.assertEqual(obj.message, "message")
|
||||||
|
self.assertEqual(obj.level, Notification.Level.SUCCESS)
|
||||||
|
|
||||||
|
def test_should_add_warning_notification(self):
|
||||||
|
# given
|
||||||
|
notify = NotifyApiWrapper()
|
||||||
|
# when
|
||||||
|
notify.warning(user=self.user, title="title", message="message")
|
||||||
|
# then
|
||||||
|
obj = Notification.objects.first()
|
||||||
|
self.assertEqual(obj.user, self.user)
|
||||||
|
self.assertEqual(obj.title, "title")
|
||||||
|
self.assertEqual(obj.message, "message")
|
||||||
|
self.assertEqual(obj.level, Notification.Level.WARNING)
|
||||||
|
|
||||||
|
def test_should_add_info_notification_via_callable(self):
|
||||||
|
# given
|
||||||
|
notify = NotifyApiWrapper()
|
||||||
|
# when
|
||||||
|
notify(user=self.user, title="title", message="message")
|
||||||
|
# then
|
||||||
|
obj = Notification.objects.first()
|
||||||
|
self.assertEqual(obj.user, self.user)
|
||||||
|
self.assertEqual(obj.title, "title")
|
||||||
|
self.assertEqual(obj.message, "message")
|
||||||
|
self.assertEqual(obj.level, Notification.Level.INFO)
|
||||||
|
|
||||||
|
def test_should_add_danger_notification_via_callable(self):
|
||||||
|
# given
|
||||||
|
notify = NotifyApiWrapper()
|
||||||
|
# when
|
||||||
|
notify(user=self.user, title="title", message="message", level="danger")
|
||||||
|
# then
|
||||||
|
obj = Notification.objects.first()
|
||||||
|
self.assertEqual(obj.user, self.user)
|
||||||
|
self.assertEqual(obj.title, "title")
|
||||||
|
self.assertEqual(obj.message, "message")
|
||||||
|
self.assertEqual(obj.level, Notification.Level.DANGER)
|
@ -4,11 +4,8 @@ from allianceauth.tests.auth_utils import AuthUtils
|
|||||||
from .. import notify
|
from .. import notify
|
||||||
from ..models import Notification
|
from ..models import Notification
|
||||||
|
|
||||||
MODULE_PATH = 'allianceauth.notifications'
|
|
||||||
|
|
||||||
|
|
||||||
class TestUserNotificationCount(TestCase):
|
class TestUserNotificationCount(TestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
cls.user = AuthUtils.create_user('magic_mike')
|
cls.user = AuthUtils.create_user('magic_mike')
|
||||||
@ -23,6 +20,18 @@ class TestUserNotificationCount(TestCase):
|
|||||||
alliance_name='RIDERS'
|
alliance_name='RIDERS'
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_can_notify(self):
|
def test_can_notify_short(self):
|
||||||
notify(self.user, 'dummy')
|
# when
|
||||||
|
notify(self.user, "dummy")
|
||||||
|
# then
|
||||||
self.assertEqual(Notification.objects.filter(user=self.user).count(), 1)
|
self.assertEqual(Notification.objects.filter(user=self.user).count(), 1)
|
||||||
|
|
||||||
|
def test_can_notify_full(self):
|
||||||
|
# when
|
||||||
|
notify(user=self.user, title="title", message="message", level="danger")
|
||||||
|
# then
|
||||||
|
obj = Notification.objects.first()
|
||||||
|
self.assertEqual(obj.user, self.user)
|
||||||
|
self.assertEqual(obj.title, "title")
|
||||||
|
self.assertEqual(obj.message, "message")
|
||||||
|
self.assertEqual(obj.level, "danger")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user