Update the Message of the day (motd) app to support organizations.
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from organizations.managers import CurrentOrganizationManager
|
||||||
|
|
||||||
|
|
||||||
class MessageManager(models.Manager):
|
class MessageManager(models.Manager):
|
||||||
def get_for_now(self):
|
def get_for_now(self):
|
||||||
@@ -9,3 +12,10 @@ class MessageManager(models.Manager):
|
|||||||
return self.filter(enabled=True).filter(
|
return self.filter(enabled=True).filter(
|
||||||
Q(start_datetime__isnull=True) | Q(start_datetime__lte=now)
|
Q(start_datetime__isnull=True) | Q(start_datetime__lte=now)
|
||||||
).filter(Q(end_datetime__isnull=True) | Q(end_datetime__gte=now))
|
).filter(Q(end_datetime__isnull=True) | Q(end_datetime__gte=now))
|
||||||
|
|
||||||
|
|
||||||
|
class OrganizationMessageManager(MessageManager, CurrentOrganizationManager):
|
||||||
|
def get_queryset(self):
|
||||||
|
return super(OrganizationMessageManager, self).get_queryset().filter(
|
||||||
|
**{self._get_field_name() + '__id': settings.ORGANIZATION_ID}
|
||||||
|
)
|
||||||
|
|||||||
@@ -13,12 +13,36 @@ class Migration(migrations.Migration):
|
|||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='MessageOfTheDay',
|
name='MessageOfTheDay',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
(
|
||||||
('label', models.CharField(max_length=32, verbose_name='Label')),
|
'id', models.AutoField(
|
||||||
('message', models.TextField(verbose_name='Message', blank=True)),
|
verbose_name='ID', serialize=False, auto_created=True,
|
||||||
('enabled', models.BooleanField(default=True, verbose_name='Enabled')),
|
primary_key=True
|
||||||
('start_datetime', models.DateTimeField(verbose_name='Start date time', blank=True)),
|
)
|
||||||
('end_datetime', models.DateTimeField(verbose_name='End date time', blank=True)),
|
),
|
||||||
|
(
|
||||||
|
'label',
|
||||||
|
models.CharField(max_length=32, verbose_name='Label')
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'message',
|
||||||
|
models.TextField(verbose_name='Message', blank=True)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'enabled',
|
||||||
|
models.BooleanField(default=True, verbose_name='Enabled')
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'start_datetime',
|
||||||
|
models.DateTimeField(
|
||||||
|
verbose_name='Start date time', blank=True
|
||||||
|
)
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'end_datetime',
|
||||||
|
models.DateTimeField(
|
||||||
|
verbose_name='End date time', blank=True
|
||||||
|
)
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Message of the day',
|
'verbose_name': 'Message of the day',
|
||||||
|
|||||||
@@ -14,11 +14,15 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='messageoftheday',
|
model_name='messageoftheday',
|
||||||
name='end_datetime',
|
name='end_datetime',
|
||||||
field=models.DateTimeField(null=True, verbose_name='End date time', blank=True),
|
field=models.DateTimeField(
|
||||||
|
null=True, verbose_name='End date time', blank=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='messageoftheday',
|
model_name='messageoftheday',
|
||||||
name='start_datetime',
|
name='start_datetime',
|
||||||
field=models.DateTimeField(null=True, verbose_name='Start date time', blank=True),
|
field=models.DateTimeField(
|
||||||
|
null=True, verbose_name='Start date time', blank=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,21 +14,35 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='message',
|
model_name='message',
|
||||||
name='end_datetime',
|
name='end_datetime',
|
||||||
field=models.DateTimeField(help_text='Date and time until when this message is to be displayed.', null=True, verbose_name='End date time', blank=True),
|
field=models.DateTimeField(
|
||||||
|
help_text='Date and time until when this message is to be '
|
||||||
|
'displayed.', null=True, verbose_name='End date time',
|
||||||
|
blank=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='message',
|
model_name='message',
|
||||||
name='label',
|
name='label',
|
||||||
field=models.CharField(help_text='Short description of this message.', max_length=32, verbose_name='Label'),
|
field=models.CharField(
|
||||||
|
help_text='Short description of this message.', max_length=32,
|
||||||
|
verbose_name='Label'
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='message',
|
model_name='message',
|
||||||
name='message',
|
name='message',
|
||||||
field=models.TextField(help_text='The actual message to be displayed.', verbose_name='Message'),
|
field=models.TextField(
|
||||||
|
help_text='The actual message to be displayed.',
|
||||||
|
verbose_name='Message'
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='message',
|
model_name='message',
|
||||||
name='start_datetime',
|
name='start_datetime',
|
||||||
field=models.DateTimeField(help_text='Date and time after which this message will be displayed.', null=True, verbose_name='Start date time', blank=True),
|
field=models.DateTimeField(
|
||||||
|
help_text='Date and time after which this message will be '
|
||||||
|
'displayed.', null=True, verbose_name='Start date time',
|
||||||
|
blank=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
24
mayan/apps/motd/migrations/0006_message_organization.py
Normal file
24
mayan/apps/motd/migrations/0006_message_organization.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import organizations.shortcuts
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('organizations', '0002_add_data_default_organization'),
|
||||||
|
('motd', '0005_auto_20160510_0025'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='message',
|
||||||
|
name='organization',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
default=organizations.shortcuts.get_current_organization,
|
||||||
|
to='organizations.Organization'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -4,11 +4,17 @@ from django.db import models
|
|||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from .managers import MessageManager
|
from organizations.models import Organization
|
||||||
|
from organizations.shortcuts import get_current_organization
|
||||||
|
|
||||||
|
from .managers import MessageManager, OrganizationMessageManager
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Message(models.Model):
|
class Message(models.Model):
|
||||||
|
organization = models.ForeignKey(
|
||||||
|
Organization, default=get_current_organization
|
||||||
|
)
|
||||||
label = models.CharField(
|
label = models.CharField(
|
||||||
max_length=32, help_text=_('Short description of this message.'),
|
max_length=32, help_text=_('Short description of this message.'),
|
||||||
verbose_name=_('Label')
|
verbose_name=_('Label')
|
||||||
@@ -30,6 +36,7 @@ class Message(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
objects = MessageManager()
|
objects = MessageManager()
|
||||||
|
on_organization = OrganizationMessageManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Message')
|
verbose_name = _('Message')
|
||||||
|
|||||||
@@ -9,4 +9,4 @@ register = Library()
|
|||||||
|
|
||||||
@register.inclusion_tag('motd/messages.html')
|
@register.inclusion_tag('motd/messages.html')
|
||||||
def motd():
|
def motd():
|
||||||
return {'messages': Message.objects.get_for_now()}
|
return {'messages': Message.on_organization.get_for_now()}
|
||||||
|
|||||||
5
mayan/apps/motd/tests/literals.py
Normal file
5
mayan/apps/motd/tests/literals.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
TEST_MESSAGE_LABEL = 'test message label'
|
||||||
|
TEST_MESSAGE_LABEL_EDITED = 'test message label edited'
|
||||||
|
TEST_MESSAGE_TEXT = 'test message text'
|
||||||
@@ -5,20 +5,27 @@ from datetime import timedelta
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from organizations.models import Organization
|
||||||
|
from organizations.utils import create_default_organization
|
||||||
|
|
||||||
from ..models import Message
|
from ..models import Message
|
||||||
|
|
||||||
TEST_LABEL = 'test label'
|
from .literals import TEST_MESSAGE_LABEL, TEST_MESSAGE_TEXT
|
||||||
TEST_MESSAGE = 'test message'
|
|
||||||
|
|
||||||
|
|
||||||
class MOTDTestCase(TestCase):
|
class MOTDTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.motd = Message.objects.create(
|
create_default_organization()
|
||||||
label=TEST_LABEL, message=TEST_MESSAGE
|
self.motd = Message.on_organization.create(
|
||||||
|
label=TEST_MESSAGE_LABEL, message=TEST_MESSAGE_TEXT
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
Organization.objects.all().delete()
|
||||||
|
Organization.objects.clear_cache()
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
queryset = Message.objects.get_for_now()
|
queryset = Message.on_organization.get_for_now()
|
||||||
|
|
||||||
self.assertEqual(queryset.exists(), True)
|
self.assertEqual(queryset.exists(), True)
|
||||||
|
|
||||||
@@ -26,7 +33,7 @@ class MOTDTestCase(TestCase):
|
|||||||
self.motd.start_datetime = timezone.now() - timedelta(days=1)
|
self.motd.start_datetime = timezone.now() - timedelta(days=1)
|
||||||
self.motd.save()
|
self.motd.save()
|
||||||
|
|
||||||
queryset = Message.objects.get_for_now()
|
queryset = Message.on_organization.get_for_now()
|
||||||
|
|
||||||
self.assertEqual(queryset.first(), self.motd)
|
self.assertEqual(queryset.first(), self.motd)
|
||||||
|
|
||||||
@@ -35,7 +42,7 @@ class MOTDTestCase(TestCase):
|
|||||||
self.motd.end_datetime = timezone.now() - timedelta(days=1)
|
self.motd.end_datetime = timezone.now() - timedelta(days=1)
|
||||||
self.motd.save()
|
self.motd.save()
|
||||||
|
|
||||||
queryset = Message.objects.get_for_now()
|
queryset = Message.on_organization.get_for_now()
|
||||||
|
|
||||||
self.assertEqual(queryset.exists(), False)
|
self.assertEqual(queryset.exists(), False)
|
||||||
|
|
||||||
@@ -43,6 +50,6 @@ class MOTDTestCase(TestCase):
|
|||||||
self.motd.enabled = False
|
self.motd.enabled = False
|
||||||
self.motd.save()
|
self.motd.save()
|
||||||
|
|
||||||
queryset = Message.objects.get_for_now()
|
queryset = Message.on_organization.get_for_now()
|
||||||
|
|
||||||
self.assertEqual(queryset.exists(), False)
|
self.assertEqual(queryset.exists(), False)
|
||||||
|
|||||||
67
mayan/apps/motd/tests/test_organization_views.py
Normal file
67
mayan/apps/motd/tests/test_organization_views.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from organizations.tests.test_organization_views import OrganizationViewTestCase
|
||||||
|
|
||||||
|
from ..models import Message
|
||||||
|
|
||||||
|
from .literals import (
|
||||||
|
TEST_MESSAGE_LABEL, TEST_MESSAGE_LABEL_EDITED, TEST_MESSAGE_TEXT
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class MessageOrganizationViewTestCase(OrganizationViewTestCase):
|
||||||
|
def create_message(self):
|
||||||
|
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
|
||||||
|
self.message = Message.on_organization.create(
|
||||||
|
label=TEST_MESSAGE_LABEL, message=TEST_MESSAGE_TEXT
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_message_create_view(self):
|
||||||
|
# Create a message for organization A
|
||||||
|
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
|
||||||
|
response = self.post(
|
||||||
|
'motd:message_create', data={
|
||||||
|
'label': TEST_MESSAGE_LABEL, 'message': TEST_MESSAGE_TEXT
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.assertNotContains(response, text='danger', status_code=302)
|
||||||
|
self.assertEqual(Message.on_organization.count(), 1)
|
||||||
|
|
||||||
|
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
|
||||||
|
self.assertEqual(Message.on_organization.count(), 0)
|
||||||
|
|
||||||
|
def test_message_delete_view(self):
|
||||||
|
# Create a message for organization A
|
||||||
|
self.create_message()
|
||||||
|
|
||||||
|
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
|
||||||
|
response = self.post(
|
||||||
|
'motd:message_delete', args=(self.message.pk,)
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
|
def test_message_edit_view(self):
|
||||||
|
# Create a message for organization A
|
||||||
|
self.create_message()
|
||||||
|
|
||||||
|
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
|
||||||
|
# Make sure admin for organization B cannot edit the message
|
||||||
|
response = self.post(
|
||||||
|
'motd:message_edit', args=(self.message.pk,), data={
|
||||||
|
'label': TEST_MESSAGE_LABEL_EDITED
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
|
def test_message_messageged_item_list_view(self):
|
||||||
|
# Create a message for organization A
|
||||||
|
self.create_message()
|
||||||
|
|
||||||
|
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
|
||||||
|
# Make sure admin for organization B cannot find the message for
|
||||||
|
# organization A
|
||||||
|
response = self.get('motd:message_list')
|
||||||
|
self.assertNotContains(
|
||||||
|
response, text=self.message.label, status_code=200
|
||||||
|
)
|
||||||
@@ -10,7 +10,9 @@ urlpatterns = patterns(
|
|||||||
'',
|
'',
|
||||||
url(r'^list/$', MessageListView.as_view(), name='message_list'),
|
url(r'^list/$', MessageListView.as_view(), name='message_list'),
|
||||||
url(r'^create/$', MessageCreateView.as_view(), name='message_create'),
|
url(r'^create/$', MessageCreateView.as_view(), name='message_create'),
|
||||||
url(r'^(?P<pk>\d+)/edit/$', MessageEditView.as_view(), name='message_edit'),
|
url(
|
||||||
|
r'^(?P<pk>\d+)/edit/$', MessageEditView.as_view(), name='message_edit'
|
||||||
|
),
|
||||||
url(
|
url(
|
||||||
r'^(?P<pk>\d+)/delete/$', MessageDeleteView.as_view(),
|
r'^(?P<pk>\d+)/delete/$', MessageDeleteView.as_view(),
|
||||||
name='message_delete'
|
name='message_delete'
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class MessageCreateView(SingleObjectCreateView):
|
class MessageCreateView(SingleObjectCreateView):
|
||||||
fields = ('label', 'message', 'enabled', 'start_datetime', 'end_datetime')
|
fields = ('label', 'message', 'enabled', 'start_datetime', 'end_datetime')
|
||||||
model = Message
|
|
||||||
view_permission = permission_message_create
|
view_permission = permission_message_create
|
||||||
|
|
||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
@@ -29,9 +28,11 @@ class MessageCreateView(SingleObjectCreateView):
|
|||||||
'title': _('Create message'),
|
'title': _('Create message'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return Message.on_organization.all()
|
||||||
|
|
||||||
|
|
||||||
class MessageDeleteView(SingleObjectDeleteView):
|
class MessageDeleteView(SingleObjectDeleteView):
|
||||||
model = Message
|
|
||||||
object_permission = permission_message_delete
|
object_permission = permission_message_delete
|
||||||
post_action_redirect = reverse_lazy('motd:message_list')
|
post_action_redirect = reverse_lazy('motd:message_list')
|
||||||
|
|
||||||
@@ -42,10 +43,12 @@ class MessageDeleteView(SingleObjectDeleteView):
|
|||||||
'title': _('Delete the message: %s?') % self.get_object(),
|
'title': _('Delete the message: %s?') % self.get_object(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return Message.on_organization.all()
|
||||||
|
|
||||||
|
|
||||||
class MessageEditView(SingleObjectEditView):
|
class MessageEditView(SingleObjectEditView):
|
||||||
fields = ('label', 'message', 'enabled', 'start_datetime', 'end_datetime')
|
fields = ('label', 'message', 'enabled', 'start_datetime', 'end_datetime')
|
||||||
model = Message
|
|
||||||
object_permission = permission_message_edit
|
object_permission = permission_message_edit
|
||||||
post_action_redirect = reverse_lazy('motd:message_list')
|
post_action_redirect = reverse_lazy('motd:message_list')
|
||||||
|
|
||||||
@@ -55,9 +58,11 @@ class MessageEditView(SingleObjectEditView):
|
|||||||
'title': _('Edit message: %s') % self.get_object(),
|
'title': _('Edit message: %s') % self.get_object(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return Message.on_organization.all()
|
||||||
|
|
||||||
|
|
||||||
class MessageListView(SingleObjectListView):
|
class MessageListView(SingleObjectListView):
|
||||||
model = Message
|
|
||||||
object_permission = permission_message_view
|
object_permission = permission_message_view
|
||||||
|
|
||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
@@ -65,3 +70,6 @@ class MessageListView(SingleObjectListView):
|
|||||||
'hide_link': True,
|
'hide_link': True,
|
||||||
'title': _('Messages'),
|
'title': _('Messages'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return Message.on_organization.all()
|
||||||
|
|||||||
Reference in New Issue
Block a user