Add support for showing the current user's events
Add support kwargs to the SourceColumn class. Improve the event widgets, views and tests. Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
@@ -104,6 +104,9 @@
|
|||||||
* Add group created and group edited events.
|
* Add group created and group edited events.
|
||||||
* Add support for SourceColumn widgets.
|
* Add support for SourceColumn widgets.
|
||||||
* Improve styling of the template debug view.
|
* Improve styling of the template debug view.
|
||||||
|
* Add support for showing the current user's events.
|
||||||
|
* Add support kwargs to the SourceColumn class.
|
||||||
|
* Improve the event widgets, views and tests.
|
||||||
|
|
||||||
3.1.11 (2019-04-XX)
|
3.1.11 (2019-04-XX)
|
||||||
===================
|
===================
|
||||||
|
|||||||
@@ -136,6 +136,9 @@ Other changes
|
|||||||
* Add group created and group edited events.
|
* Add group created and group edited events.
|
||||||
* Add support for SourceColumn widgets.
|
* Add support for SourceColumn widgets.
|
||||||
* Improve styling of the template debug view.
|
* Improve styling of the template debug view.
|
||||||
|
* Add support for showing the current user's events.
|
||||||
|
* Add support kwargs to the SourceColumn class.
|
||||||
|
* Improve the event widgets, views and tests.
|
||||||
|
|
||||||
Removals
|
Removals
|
||||||
--------
|
--------
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from mayan.apps.common.apps import MayanAppConfig
|
from mayan.apps.common.apps import MayanAppConfig
|
||||||
@@ -11,13 +10,15 @@ from mayan.apps.common.menus import (
|
|||||||
from mayan.apps.common.widgets import TwoStateWidget
|
from mayan.apps.common.widgets import TwoStateWidget
|
||||||
from mayan.apps.navigation import SourceColumn
|
from mayan.apps.navigation import SourceColumn
|
||||||
|
|
||||||
|
from .html_widgets import (
|
||||||
|
ObjectLinkWidget, widget_event_actor_link, widget_event_type_link
|
||||||
|
)
|
||||||
from .links import (
|
from .links import (
|
||||||
link_events_list, link_event_types_subscriptions_list,
|
link_current_user_events, link_event_types_subscriptions_list,
|
||||||
link_notification_mark_read, link_notification_mark_read_all,
|
link_events_list, link_notification_mark_read,
|
||||||
link_user_events, link_user_notifications_list,
|
link_notification_mark_read_all, link_user_notifications_list,
|
||||||
)
|
)
|
||||||
from .licenses import * # NOQA
|
from .licenses import * # NOQA
|
||||||
from .widgets import event_object_link, event_type_link, event_user_link
|
|
||||||
|
|
||||||
|
|
||||||
class EventsApp(MayanAppConfig):
|
class EventsApp(MayanAppConfig):
|
||||||
@@ -33,24 +34,23 @@ class EventsApp(MayanAppConfig):
|
|||||||
Action = apps.get_model(app_label='actstream', model_name='Action')
|
Action = apps.get_model(app_label='actstream', model_name='Action')
|
||||||
Notification = self.get_model(model_name='Notification')
|
Notification = self.get_model(model_name='Notification')
|
||||||
StoredEventType = self.get_model(model_name='StoredEventType')
|
StoredEventType = self.get_model(model_name='StoredEventType')
|
||||||
User = get_user_model()
|
|
||||||
|
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=Action, label=_('Timestamp'), attribute='timestamp'
|
source=Action, label=_('Timestamp'), attribute='timestamp'
|
||||||
)
|
)
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=Action, label=_('Actor'),
|
func=widget_event_actor_link, label=_('Actor'), source=Action
|
||||||
func=lambda context: event_user_link(context['object'])
|
|
||||||
)
|
)
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=Action, label=_('Event'),
|
func=widget_event_type_link, label=_('Event'), source=Action
|
||||||
func=lambda context: event_type_link(context['object'])
|
|
||||||
)
|
)
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=Action, label=_('Action object'),
|
attribute='action_object', label=_('Action object'), source=Action,
|
||||||
func=lambda context: event_object_link(
|
widget=ObjectLinkWidget
|
||||||
entry=context['object'], attribute='action_object'
|
)
|
||||||
)
|
SourceColumn(
|
||||||
|
attribute='target', label=_('Target'), source=Action,
|
||||||
|
widget=ObjectLinkWidget
|
||||||
)
|
)
|
||||||
|
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
@@ -64,17 +64,20 @@ class EventsApp(MayanAppConfig):
|
|||||||
source=Notification, label=_('Timestamp'),
|
source=Notification, label=_('Timestamp'),
|
||||||
attribute='action.timestamp'
|
attribute='action.timestamp'
|
||||||
)
|
)
|
||||||
|
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=Notification, label=_('Actor'), attribute='action.actor'
|
func=widget_event_actor_link, label=_('Actor'),
|
||||||
|
kwargs={'attribute': 'action'}, source=Notification
|
||||||
)
|
)
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=Notification, label=_('Event'),
|
func=widget_event_type_link, label=_('Event'),
|
||||||
func=lambda context: event_type_link(context['object'].action)
|
kwargs={'attribute': 'action'}, source=Notification
|
||||||
)
|
)
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=Notification, label=_('Target'),
|
attribute='action.target', label=_('Target'), source=Notification,
|
||||||
func=lambda context: event_object_link(context['object'].action)
|
widget=ObjectLinkWidget
|
||||||
)
|
)
|
||||||
|
|
||||||
SourceColumn(
|
SourceColumn(
|
||||||
source=Notification, label=_('Seen'),
|
source=Notification, label=_('Seen'),
|
||||||
func=lambda context: TwoStateWidget(
|
func=lambda context: TwoStateWidget(
|
||||||
@@ -88,14 +91,13 @@ class EventsApp(MayanAppConfig):
|
|||||||
menu_object.bind_links(
|
menu_object.bind_links(
|
||||||
links=(link_notification_mark_read,), sources=(Notification,)
|
links=(link_notification_mark_read,), sources=(Notification,)
|
||||||
)
|
)
|
||||||
menu_object.bind_links(
|
|
||||||
links=(link_user_events,), sources=(User,)
|
|
||||||
)
|
|
||||||
menu_secondary.bind_links(
|
menu_secondary.bind_links(
|
||||||
links=(link_notification_mark_read_all,),
|
links=(link_notification_mark_read_all,),
|
||||||
sources=('events:user_notifications_list',)
|
sources=('events:user_notifications_list',)
|
||||||
)
|
)
|
||||||
menu_tools.bind_links(links=(link_events_list,))
|
menu_tools.bind_links(links=(link_events_list,))
|
||||||
menu_user.bind_links(
|
menu_user.bind_links(
|
||||||
links=(link_event_types_subscriptions_list,), position=50
|
links=(
|
||||||
|
link_event_types_subscriptions_list, link_current_user_events
|
||||||
|
), position=50
|
||||||
)
|
)
|
||||||
|
|||||||
82
mayan/apps/events/html_widgets.py
Normal file
82
mayan/apps/events/html_widgets.py
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
|
from django.template import Context, Template
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.encoding import force_text
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from .classes import EventType
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectLinkWidget(object):
|
||||||
|
template_string = '<a href="{{ url }}">{{ object_type }}{{ label }}</a>'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.template = Template(template_string=self.template_string)
|
||||||
|
|
||||||
|
def render(self, name=None, value=None):
|
||||||
|
label = ''
|
||||||
|
object_type = ''
|
||||||
|
url = None
|
||||||
|
|
||||||
|
if value:
|
||||||
|
label = force_text(value)
|
||||||
|
object_type = '{}: '.format(value._meta.verbose_name)
|
||||||
|
try:
|
||||||
|
url = value.get_absolute_url()
|
||||||
|
except AttributeError:
|
||||||
|
url = None
|
||||||
|
|
||||||
|
return self.template.render(
|
||||||
|
context=Context(
|
||||||
|
{'label': label, 'object_type': object_type, 'url': url or '#'}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def widget_event_actor_link(context, attribute=None):
|
||||||
|
entry = context['object']
|
||||||
|
|
||||||
|
ContentType = apps.get_model(
|
||||||
|
app_label='contenttypes', model_name='ContentType'
|
||||||
|
)
|
||||||
|
|
||||||
|
if attribute:
|
||||||
|
entry = getattr(entry, attribute)
|
||||||
|
|
||||||
|
if entry.actor == entry.target:
|
||||||
|
label = _('System')
|
||||||
|
url = None
|
||||||
|
else:
|
||||||
|
label = entry.actor
|
||||||
|
content_type = ContentType.objects.get_for_model(model=entry.actor)
|
||||||
|
|
||||||
|
url = reverse(
|
||||||
|
viewname='events:events_for_object', kwargs={
|
||||||
|
'app_label': content_type.app_label, 'model': content_type.model,
|
||||||
|
'object_id': entry.actor.pk
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if url:
|
||||||
|
return Template(
|
||||||
|
template_string='<a href="{{ url }}">{{ label }}</a>'
|
||||||
|
).render(context=Context({'label': entry.actor, 'url': url}))
|
||||||
|
else:
|
||||||
|
return label
|
||||||
|
|
||||||
|
|
||||||
|
def widget_event_type_link(context, attribute=None):
|
||||||
|
entry = context['object']
|
||||||
|
|
||||||
|
if attribute:
|
||||||
|
entry = getattr(entry, attribute)
|
||||||
|
|
||||||
|
return mark_safe(
|
||||||
|
'<a href="%(url)s">%(label)s</a>' % {
|
||||||
|
'url': reverse(viewname='events:events_by_verb', kwargs={'verb': entry.verb}),
|
||||||
|
'label': EventType.get(name=entry.verb)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -5,9 +5,8 @@ from mayan.apps.appearance.classes import Icon
|
|||||||
icon_event_types_subscriptions_list = Icon(
|
icon_event_types_subscriptions_list = Icon(
|
||||||
driver_name='fontawesome', symbol='list-ol'
|
driver_name='fontawesome', symbol='list-ol'
|
||||||
)
|
)
|
||||||
icon_events_list = Icon(driver_name='fontawesome', symbol='list-ol')
|
|
||||||
icon_events_for_object = Icon(driver_name='fontawesome', symbol='list-ol')
|
icon_events_for_object = Icon(driver_name='fontawesome', symbol='list-ol')
|
||||||
icon_events_user_list = Icon(driver_name='fontawesome', symbol='rss')
|
icon_events_list = Icon(driver_name='fontawesome', symbol='list-ol')
|
||||||
icon_object_event_types_user_subcriptions_list = Icon(
|
icon_object_event_types_user_subcriptions_list = Icon(
|
||||||
driver_name='fontawesome', symbol='rss'
|
driver_name='fontawesome', symbol='rss'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ def get_unread_notification_count(context):
|
|||||||
).filter(read=False).count()
|
).filter(read=False).count()
|
||||||
|
|
||||||
|
|
||||||
link_events_list = Link(
|
link_current_user_events = Link(
|
||||||
icon_class=icon_events_list, permissions=(permission_events_view,),
|
icon_class=icon_events_list, text=_('My events'),
|
||||||
text=_('Events'), view='events:events_list'
|
view='events:current_user_events'
|
||||||
)
|
)
|
||||||
link_events_details = Link(
|
link_events_details = Link(
|
||||||
text=_('Events'), view='events:events_list'
|
text=_('Events'), view='events:events_list'
|
||||||
@@ -54,6 +54,10 @@ link_events_for_object = Link(
|
|||||||
permissions=(permission_events_view,), text=_('Events'),
|
permissions=(permission_events_view,), text=_('Events'),
|
||||||
view='events:events_for_object',
|
view='events:events_for_object',
|
||||||
)
|
)
|
||||||
|
link_events_list = Link(
|
||||||
|
icon_class=icon_events_list, permissions=(permission_events_view,),
|
||||||
|
text=_('Events'), view='events:events_list'
|
||||||
|
)
|
||||||
link_event_types_subscriptions_list = Link(
|
link_event_types_subscriptions_list = Link(
|
||||||
icon_class=icon_event_types_subscriptions_list,
|
icon_class=icon_event_types_subscriptions_list,
|
||||||
text=_('Event subscriptions'),
|
text=_('Event subscriptions'),
|
||||||
@@ -72,10 +76,6 @@ link_object_event_types_user_subcriptions_list = Link(
|
|||||||
permissions=(permission_events_view,), text=_('Subscriptions'),
|
permissions=(permission_events_view,), text=_('Subscriptions'),
|
||||||
view='events:object_event_types_user_subcriptions_list',
|
view='events:object_event_types_user_subcriptions_list',
|
||||||
)
|
)
|
||||||
link_user_events = Link(
|
|
||||||
args='resolved_object.pk', text=_('User events'),
|
|
||||||
view='events:user_events'
|
|
||||||
)
|
|
||||||
link_user_notifications_list = Link(
|
link_user_notifications_list = Link(
|
||||||
badge_text=get_unread_notification_count,
|
badge_text=get_unread_notification_count,
|
||||||
icon_class=icon_user_notifications_list, text='',
|
icon_class=icon_user_notifications_list, text='',
|
||||||
|
|||||||
6
mayan/apps/events/tests/literals.py
Normal file
6
mayan/apps/events/tests/literals.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
TEST_EVENT_TYPE_NAMESPACE_LABEL = 'test event type namespace label'
|
||||||
|
TEST_EVENT_TYPE_NAMESPACE_NAME = 'test_event_type_namespace_name'
|
||||||
|
TEST_EVENT_TYPE_LABEL = 'test event type label'
|
||||||
|
TEST_EVENT_TYPE_NAME = 'test_event_type_name'
|
||||||
20
mayan/apps/events/tests/mixins.py
Normal file
20
mayan/apps/events/tests/mixins.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from ..classes import EventTypeNamespace
|
||||||
|
|
||||||
|
from .literals import (
|
||||||
|
TEST_EVENT_TYPE_LABEL, TEST_EVENT_TYPE_NAME,
|
||||||
|
TEST_EVENT_TYPE_NAMESPACE_LABEL, TEST_EVENT_TYPE_NAMESPACE_NAME
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class EventTypeTestMixin(object):
|
||||||
|
def _create_test_event_type(self):
|
||||||
|
self.test_event_type_namespace = EventTypeNamespace(
|
||||||
|
label=TEST_EVENT_TYPE_NAMESPACE_LABEL,
|
||||||
|
name=TEST_EVENT_TYPE_NAMESPACE_NAME
|
||||||
|
)
|
||||||
|
self.test_event_type = self.test_event_type_namespace.add_event_type(
|
||||||
|
label=TEST_EVENT_TYPE_LABEL,
|
||||||
|
name=TEST_EVENT_TYPE_NAME
|
||||||
|
)
|
||||||
@@ -1,9 +1,69 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
|
from rest_framework import status
|
||||||
|
|
||||||
|
from mayan.apps.documents.tests import DocumentTestMixin
|
||||||
from mayan.apps.rest_api.tests import BaseAPITestCase
|
from mayan.apps.rest_api.tests import BaseAPITestCase
|
||||||
|
|
||||||
|
from ..permissions import permission_events_view
|
||||||
|
|
||||||
|
from .mixins import EventTypeTestMixin
|
||||||
|
|
||||||
|
|
||||||
|
class EventTypeNamespaceAPITestCase(EventTypeTestMixin, BaseAPITestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(EventTypeNamespaceAPITestCase, self).setUp()
|
||||||
|
self._create_test_event_type()
|
||||||
|
|
||||||
class EventAPITestCase(BaseAPITestCase):
|
|
||||||
def test_evet_type_list_view(self):
|
def test_evet_type_list_view(self):
|
||||||
response = self.get(viewname='rest_api:event-type-list')
|
response = self.get(viewname='rest_api:event-type-list')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
def test_event_type_namespace_list_view(self):
|
||||||
|
response = self.get(viewname='rest_api:event-type-namespace-list')
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
def test_event_type_namespace_event_type_list_view(self):
|
||||||
|
response = self.get(
|
||||||
|
viewname='rest_api:event-type-namespace-event-type-list',
|
||||||
|
kwargs={
|
||||||
|
'name': self.test_event_type_namespace.name
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectEventAPITestCase(DocumentTestMixin, BaseAPITestCase):
|
||||||
|
auto_upload_document = False
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ObjectEventAPITestCase, self).setUp()
|
||||||
|
self.test_object = self.test_document_type
|
||||||
|
|
||||||
|
content_type = ContentType.objects.get_for_model(model=self.test_object)
|
||||||
|
|
||||||
|
self.view_arguments = {
|
||||||
|
'app_label': content_type.app_label,
|
||||||
|
'model': content_type.model,
|
||||||
|
'object_id': self.test_object.pk
|
||||||
|
}
|
||||||
|
|
||||||
|
def _request_object_event_list_api_view(self):
|
||||||
|
return self.get(
|
||||||
|
viewname='rest_api:object-event-list',
|
||||||
|
kwargs=self.view_arguments
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_object_event_list_view_no_permission(self):
|
||||||
|
response = self._request_object_event_list_api_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
|
def test_object_event_list_view_with_access(self):
|
||||||
|
self.grant_access(
|
||||||
|
obj=self.test_object, permission=permission_events_view
|
||||||
|
)
|
||||||
|
response = self._request_object_event_list_api_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|||||||
@@ -8,15 +8,18 @@ from ..permissions import permission_events_view
|
|||||||
|
|
||||||
|
|
||||||
class EventsViewTestCase(GenericDocumentViewTestCase):
|
class EventsViewTestCase(GenericDocumentViewTestCase):
|
||||||
|
auto_upload_document = False
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(EventsViewTestCase, self).setUp()
|
super(EventsViewTestCase, self).setUp()
|
||||||
|
self.test_object = self.test_document_type
|
||||||
|
|
||||||
content_type = ContentType.objects.get_for_model(self.test_document)
|
content_type = ContentType.objects.get_for_model(self.test_object)
|
||||||
|
|
||||||
self.view_arguments = {
|
self.view_arguments = {
|
||||||
'app_label': content_type.app_label,
|
'app_label': content_type.app_label,
|
||||||
'model': content_type.model,
|
'model': content_type.model,
|
||||||
'object_id': self.document.pk
|
'object_id': self.test_object.pk
|
||||||
}
|
}
|
||||||
|
|
||||||
def _request_events_for_object_view(self):
|
def _request_events_for_object_view(self):
|
||||||
@@ -27,19 +30,15 @@ class EventsViewTestCase(GenericDocumentViewTestCase):
|
|||||||
def test_events_for_object_view_no_permission(self):
|
def test_events_for_object_view_no_permission(self):
|
||||||
response = self._request_events_for_object_view()
|
response = self._request_events_for_object_view()
|
||||||
self.assertNotContains(
|
self.assertNotContains(
|
||||||
response=response, text=self.test_document.label, status_code=403
|
response=response, text=self.test_object.label, status_code=404
|
||||||
)
|
|
||||||
self.assertNotContains(
|
|
||||||
response=response, text='otal:', status_code=403
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_events_for_object_view_with_permission(self):
|
def test_events_for_object_view_with_permission(self):
|
||||||
self.grant_permission(permission=permission_events_view)
|
self.grant_access(
|
||||||
|
obj=self.test_object, permission=permission_events_view
|
||||||
|
)
|
||||||
|
|
||||||
response = self._request_events_for_object_view()
|
response = self._request_events_for_object_view()
|
||||||
self.assertContains(
|
self.assertContains(
|
||||||
response=response, text=self.test_document.label, status_code=200
|
response=response, text=self.test_object.label, status_code=200
|
||||||
)
|
|
||||||
self.assertNotContains(
|
|
||||||
response=response, text='otal: 0', status_code=200
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ from .api_views import (
|
|||||||
APINotificationListView, APIObjectEventListView
|
APINotificationListView, APIObjectEventListView
|
||||||
)
|
)
|
||||||
from .views import (
|
from .views import (
|
||||||
EventListView, EventTypeSubscriptionListView, NotificationListView,
|
CurrentUserEventListView, EventListView, EventTypeSubscriptionListView,
|
||||||
NotificationMarkRead, NotificationMarkReadAll, ObjectEventListView,
|
NotificationListView, NotificationMarkRead, NotificationMarkReadAll,
|
||||||
ObjectEventTypeSubscriptionListView, UserEventListView, VerbEventListView
|
ObjectEventListView, ObjectEventTypeSubscriptionListView,
|
||||||
|
VerbEventListView
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@@ -31,15 +32,15 @@ urlpatterns = [
|
|||||||
regex=r'^notifications/all/mark_read/$',
|
regex=r'^notifications/all/mark_read/$',
|
||||||
view=NotificationMarkReadAll.as_view(), name='notification_mark_read_all'
|
view=NotificationMarkReadAll.as_view(), name='notification_mark_read_all'
|
||||||
),
|
),
|
||||||
|
url(
|
||||||
|
regex=r'^user/events/$', name='current_user_events',
|
||||||
|
view=CurrentUserEventListView.as_view()
|
||||||
|
),
|
||||||
url(
|
url(
|
||||||
regex=r'^user/(?P<app_label>[-\w]+)/(?P<model>[-\w]+)/(?P<object_id>\d+)/subscriptions/$',
|
regex=r'^user/(?P<app_label>[-\w]+)/(?P<model>[-\w]+)/(?P<object_id>\d+)/subscriptions/$',
|
||||||
view=ObjectEventTypeSubscriptionListView.as_view(),
|
view=ObjectEventTypeSubscriptionListView.as_view(),
|
||||||
name='object_event_types_user_subcriptions_list'
|
name='object_event_types_user_subcriptions_list'
|
||||||
),
|
),
|
||||||
url(
|
|
||||||
regex=r'^user/(?P<pk>\d+)/events/$', view=UserEventListView.as_view(),
|
|
||||||
name='user_events'
|
|
||||||
),
|
|
||||||
url(
|
url(
|
||||||
regex=r'^user/event_types/subscriptions/$',
|
regex=r'^user/event_types/subscriptions/$',
|
||||||
view=EventTypeSubscriptionListView.as_view(),
|
view=EventTypeSubscriptionListView.as_view(),
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.http import Http404, HttpResponseRedirect
|
from django.http import Http404, HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
@@ -13,7 +12,6 @@ from actstream.models import Action, any_stream
|
|||||||
|
|
||||||
from mayan.apps.acls.models import AccessControlList
|
from mayan.apps.acls.models import AccessControlList
|
||||||
from mayan.apps.common.generics import FormView, SimpleView
|
from mayan.apps.common.generics import FormView, SimpleView
|
||||||
from mayan.apps.common.utils import encapsulate
|
|
||||||
from mayan.apps.common.views import SingleObjectListView
|
from mayan.apps.common.views import SingleObjectListView
|
||||||
|
|
||||||
from .classes import EventType, ModelEventType
|
from .classes import EventType, ModelEventType
|
||||||
@@ -21,12 +19,11 @@ from .forms import (
|
|||||||
EventTypeUserRelationshipFormSet, ObjectEventTypeUserRelationshipFormSet
|
EventTypeUserRelationshipFormSet, ObjectEventTypeUserRelationshipFormSet
|
||||||
)
|
)
|
||||||
from .icons import (
|
from .icons import (
|
||||||
icon_events_list, icon_events_user_list, icon_user_notifications_list
|
icon_events_list, icon_user_notifications_list
|
||||||
)
|
)
|
||||||
from .links import link_event_types_subscriptions_list
|
from .links import link_event_types_subscriptions_list
|
||||||
from .models import StoredEventType
|
from .models import StoredEventType
|
||||||
from .permissions import permission_events_view
|
from .permissions import permission_events_view
|
||||||
from .widgets import event_object_link
|
|
||||||
|
|
||||||
|
|
||||||
class EventListView(SingleObjectListView):
|
class EventListView(SingleObjectListView):
|
||||||
@@ -34,14 +31,6 @@ class EventListView(SingleObjectListView):
|
|||||||
|
|
||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
return {
|
return {
|
||||||
'extra_columns': (
|
|
||||||
{
|
|
||||||
'name': _('Target'),
|
|
||||||
'attribute': encapsulate(
|
|
||||||
lambda entry: event_object_link(entry)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
'hide_object': True,
|
'hide_object': True,
|
||||||
'title': _('Events'),
|
'title': _('Events'),
|
||||||
}
|
}
|
||||||
@@ -154,26 +143,10 @@ class NotificationMarkReadAll(SimpleView):
|
|||||||
|
|
||||||
|
|
||||||
class ObjectEventListView(EventListView):
|
class ObjectEventListView(EventListView):
|
||||||
view_permissions = None
|
view_permission = None
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.object_content_type = get_object_or_404(
|
self.object = self.get_object()
|
||||||
klass=ContentType, app_label=self.kwargs['app_label'],
|
|
||||||
model=self.kwargs['model']
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.content_object = self.object_content_type.get_object_for_this_type(
|
|
||||||
pk=self.kwargs['object_id']
|
|
||||||
)
|
|
||||||
except self.object_content_type.model_class().DoesNotExist:
|
|
||||||
raise Http404
|
|
||||||
|
|
||||||
AccessControlList.objects.check_access(
|
|
||||||
permissions=permission_events_view, user=request.user,
|
|
||||||
obj=self.content_object
|
|
||||||
)
|
|
||||||
|
|
||||||
return super(
|
return super(
|
||||||
ObjectEventListView, self
|
ObjectEventListView, self
|
||||||
).dispatch(request, *args, **kwargs)
|
).dispatch(request, *args, **kwargs)
|
||||||
@@ -188,13 +161,28 @@ class ObjectEventListView(EventListView):
|
|||||||
'or using this object.'
|
'or using this object.'
|
||||||
),
|
),
|
||||||
'no_results_title': _('There are no events for this object'),
|
'no_results_title': _('There are no events for this object'),
|
||||||
'object': self.content_object,
|
'object': self.object,
|
||||||
'title': _('Events for: %s') % self.content_object,
|
'title': _('Events for: %s') % self.object,
|
||||||
})
|
})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
def get_object(self):
|
||||||
|
content_type = get_object_or_404(
|
||||||
|
klass=ContentType, app_label=self.kwargs['app_label'],
|
||||||
|
model=self.kwargs['model']
|
||||||
|
)
|
||||||
|
|
||||||
|
queryset = AccessControlList.objects.filter_by_access(
|
||||||
|
permission=permission_events_view,
|
||||||
|
queryset=content_type.model_class().objects.all(),
|
||||||
|
user=self.request.user
|
||||||
|
)
|
||||||
|
return get_object_or_404(
|
||||||
|
klass=queryset, pk=self.kwargs['object_id']
|
||||||
|
)
|
||||||
|
|
||||||
def get_object_list(self):
|
def get_object_list(self):
|
||||||
return any_stream(self.content_object)
|
return any_stream(self.object)
|
||||||
|
|
||||||
|
|
||||||
class ObjectEventTypeSubscriptionListView(FormView):
|
class ObjectEventTypeSubscriptionListView(FormView):
|
||||||
@@ -270,50 +258,14 @@ class ObjectEventTypeSubscriptionListView(FormView):
|
|||||||
return ModelEventType.get_for_instance(instance=self.get_object())
|
return ModelEventType.get_for_instance(instance=self.get_object())
|
||||||
|
|
||||||
|
|
||||||
class UserEventListView(SingleObjectListView):
|
class CurrentUserEventListView(ObjectEventListView):
|
||||||
view_permission = permission_events_view
|
def get_object(self):
|
||||||
|
return self.request.user
|
||||||
def get_extra_context(self):
|
|
||||||
return {
|
|
||||||
'extra_columns': (
|
|
||||||
{
|
|
||||||
'name': _('Target'),
|
|
||||||
'attribute': encapsulate(
|
|
||||||
lambda entry: event_object_link(entry)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
'hide_object': True,
|
|
||||||
'no_results_icon': icon_events_user_list,
|
|
||||||
'no_results_text': _(
|
|
||||||
'Events are actions that have been performed to this '
|
|
||||||
'user account or by this user account.'
|
|
||||||
),
|
|
||||||
'no_results_title': _('There are no events for this user'),
|
|
||||||
'object': self.get_user(),
|
|
||||||
'title': _(
|
|
||||||
'Events for user: %s'
|
|
||||||
) % self.get_user(),
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_object_list(self):
|
|
||||||
return Action.objects.actor(obj=self.get_user())
|
|
||||||
|
|
||||||
def get_user(self):
|
|
||||||
return get_object_or_404(klass=get_user_model(), pk=self.kwargs['pk'])
|
|
||||||
|
|
||||||
|
|
||||||
class VerbEventListView(SingleObjectListView):
|
class VerbEventListView(SingleObjectListView):
|
||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
return {
|
return {
|
||||||
'extra_columns': (
|
|
||||||
{
|
|
||||||
'name': _('Target'),
|
|
||||||
'attribute': encapsulate(
|
|
||||||
lambda entry: event_object_link(entry)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
'hide_object': True,
|
'hide_object': True,
|
||||||
'title': _(
|
'title': _(
|
||||||
'Events of type: %s'
|
'Events of type: %s'
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils.encoding import force_text
|
|
||||||
from django.utils.safestring import mark_safe
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from .classes import EventType
|
|
||||||
|
|
||||||
|
|
||||||
def event_object_link(entry, attribute='target'):
|
|
||||||
label = ''
|
|
||||||
url = '#'
|
|
||||||
obj_type = ''
|
|
||||||
|
|
||||||
obj = getattr(entry, attribute)
|
|
||||||
|
|
||||||
if obj:
|
|
||||||
obj_type = '{}: '.format(obj._meta.verbose_name)
|
|
||||||
if hasattr(obj, 'get_absolute_url'):
|
|
||||||
url = obj.get_absolute_url()
|
|
||||||
label = force_text(obj)
|
|
||||||
|
|
||||||
return mark_safe(
|
|
||||||
'<a href="%(url)s">%(obj_type)s%(label)s</a>' % {
|
|
||||||
'url': url, 'label': label, 'obj_type': obj_type
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def event_type_link(entry):
|
|
||||||
return mark_safe(
|
|
||||||
'<a href="%(url)s">%(label)s</a>' % {
|
|
||||||
'url': reverse('events:events_by_verb', kwargs={'verb': entry.verb}),
|
|
||||||
'label': EventType.get(name=entry.verb)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def event_user_link(entry):
|
|
||||||
if entry.actor == entry.target:
|
|
||||||
return _('System')
|
|
||||||
else:
|
|
||||||
return mark_safe(
|
|
||||||
'<a href="%(url)s">%(label)s</a>' % {
|
|
||||||
'url': reverse('events:user_events', kwargs={'pk': entry.actor.pk}),
|
|
||||||
'label': entry.actor
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -14,7 +14,7 @@ from django.urls import resolve, reverse
|
|||||||
from django.utils.encoding import force_str, force_text
|
from django.utils.encoding import force_str, force_text
|
||||||
|
|
||||||
from mayan.apps.common.settings import setting_home_view
|
from mayan.apps.common.settings import setting_home_view
|
||||||
from mayan.apps.common.utils import return_attrib
|
from mayan.apps.common.utils import resolve_attribute, return_attrib
|
||||||
from mayan.apps.permissions import Permission
|
from mayan.apps.permissions import Permission
|
||||||
|
|
||||||
from .utils import get_current_view_name
|
from .utils import get_current_view_name
|
||||||
@@ -536,11 +536,12 @@ class SourceColumn(object):
|
|||||||
# unhashable type: list
|
# unhashable type: list
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
def __init__(self, source, label=None, attribute=None, func=None, order=None, widget=None):
|
def __init__(self, source, label=None, attribute=None, func=None, kwargs=None, order=None, widget=None):
|
||||||
self.source = source
|
self.source = source
|
||||||
self._label = label
|
self._label = label
|
||||||
self.attribute = attribute
|
self.attribute = attribute
|
||||||
self.func = func
|
self.func = func
|
||||||
|
self.kwargs = kwargs or {}
|
||||||
self.order = order or 0
|
self.order = order or 0
|
||||||
self.__class__._registry.setdefault(source, [])
|
self.__class__._registry.setdefault(source, [])
|
||||||
self.__class__._registry[source].append(self)
|
self.__class__._registry[source].append(self)
|
||||||
@@ -561,9 +562,12 @@ class SourceColumn(object):
|
|||||||
|
|
||||||
def resolve(self, context):
|
def resolve(self, context):
|
||||||
if self.attribute:
|
if self.attribute:
|
||||||
result = return_attrib(context['object'], self.attribute)
|
result = resolve_attribute(
|
||||||
|
attribute=self.attribute, kwargs=self.kwargs,
|
||||||
|
obj=context['object']
|
||||||
|
)
|
||||||
elif self.func:
|
elif self.func:
|
||||||
result = self.func(context=context)
|
result = self.func(context=context, **self.kwargs)
|
||||||
|
|
||||||
if self.widget:
|
if self.widget:
|
||||||
widget_instance = self.widget()
|
widget_instance = self.widget()
|
||||||
|
|||||||
Reference in New Issue
Block a user