diff --git a/mayan/apps/motd/managers.py b/mayan/apps/motd/managers.py index 29bfbf2e16..99b8eee8d1 100644 --- a/mayan/apps/motd/managers.py +++ b/mayan/apps/motd/managers.py @@ -1,7 +1,10 @@ +from django.conf import settings from django.db import models from django.db.models import Q from django.utils import timezone +from organizations.managers import CurrentOrganizationManager + class MessageManager(models.Manager): def get_for_now(self): @@ -9,3 +12,10 @@ class MessageManager(models.Manager): return self.filter(enabled=True).filter( Q(start_datetime__isnull=True) | Q(start_datetime__lte=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} + ) diff --git a/mayan/apps/motd/migrations/0001_initial.py b/mayan/apps/motd/migrations/0001_initial.py index 545f550f5d..1bac0dc4bf 100644 --- a/mayan/apps/motd/migrations/0001_initial.py +++ b/mayan/apps/motd/migrations/0001_initial.py @@ -13,12 +13,36 @@ class Migration(migrations.Migration): migrations.CreateModel( name='MessageOfTheDay', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=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)), + ( + 'id', models.AutoField( + verbose_name='ID', serialize=False, auto_created=True, + primary_key=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={ 'verbose_name': 'Message of the day', diff --git a/mayan/apps/motd/migrations/0002_auto_20160313_0340.py b/mayan/apps/motd/migrations/0002_auto_20160313_0340.py index e1d52bc36e..f5dd5098c6 100644 --- a/mayan/apps/motd/migrations/0002_auto_20160313_0340.py +++ b/mayan/apps/motd/migrations/0002_auto_20160313_0340.py @@ -14,11 +14,15 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='messageoftheday', 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( model_name='messageoftheday', 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 + ), ), ] diff --git a/mayan/apps/motd/migrations/0005_auto_20160510_0025.py b/mayan/apps/motd/migrations/0005_auto_20160510_0025.py index 2f87651d4c..cce5048849 100644 --- a/mayan/apps/motd/migrations/0005_auto_20160510_0025.py +++ b/mayan/apps/motd/migrations/0005_auto_20160510_0025.py @@ -14,21 +14,35 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='message', 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( model_name='message', 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( model_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( model_name='message', 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 + ), ), ] diff --git a/mayan/apps/motd/migrations/0006_message_organization.py b/mayan/apps/motd/migrations/0006_message_organization.py new file mode 100644 index 0000000000..9fbf268272 --- /dev/null +++ b/mayan/apps/motd/migrations/0006_message_organization.py @@ -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' + ), + ), + ] diff --git a/mayan/apps/motd/models.py b/mayan/apps/motd/models.py index a907e1af6d..e2d62fe6b5 100644 --- a/mayan/apps/motd/models.py +++ b/mayan/apps/motd/models.py @@ -4,11 +4,17 @@ from django.db import models from django.utils.encoding import python_2_unicode_compatible 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 class Message(models.Model): + organization = models.ForeignKey( + Organization, default=get_current_organization + ) label = models.CharField( max_length=32, help_text=_('Short description of this message.'), verbose_name=_('Label') @@ -30,6 +36,7 @@ class Message(models.Model): ) objects = MessageManager() + on_organization = OrganizationMessageManager() class Meta: verbose_name = _('Message') diff --git a/mayan/apps/motd/templatetags/motd_tags.py b/mayan/apps/motd/templatetags/motd_tags.py index 734e2184f5..e12c3305e8 100644 --- a/mayan/apps/motd/templatetags/motd_tags.py +++ b/mayan/apps/motd/templatetags/motd_tags.py @@ -9,4 +9,4 @@ register = Library() @register.inclusion_tag('motd/messages.html') def motd(): - return {'messages': Message.objects.get_for_now()} + return {'messages': Message.on_organization.get_for_now()} diff --git a/mayan/apps/motd/tests/literals.py b/mayan/apps/motd/tests/literals.py new file mode 100644 index 0000000000..7606df658b --- /dev/null +++ b/mayan/apps/motd/tests/literals.py @@ -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' diff --git a/mayan/apps/motd/tests/test_models.py b/mayan/apps/motd/tests/test_models.py index bb250982fa..bd05fd3023 100644 --- a/mayan/apps/motd/tests/test_models.py +++ b/mayan/apps/motd/tests/test_models.py @@ -5,20 +5,27 @@ from datetime import timedelta from django.test import TestCase from django.utils import timezone +from organizations.models import Organization +from organizations.utils import create_default_organization + from ..models import Message -TEST_LABEL = 'test label' -TEST_MESSAGE = 'test message' +from .literals import TEST_MESSAGE_LABEL, TEST_MESSAGE_TEXT class MOTDTestCase(TestCase): def setUp(self): - self.motd = Message.objects.create( - label=TEST_LABEL, message=TEST_MESSAGE + create_default_organization() + 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): - queryset = Message.objects.get_for_now() + queryset = Message.on_organization.get_for_now() self.assertEqual(queryset.exists(), True) @@ -26,7 +33,7 @@ class MOTDTestCase(TestCase): self.motd.start_datetime = timezone.now() - timedelta(days=1) self.motd.save() - queryset = Message.objects.get_for_now() + queryset = Message.on_organization.get_for_now() self.assertEqual(queryset.first(), self.motd) @@ -35,7 +42,7 @@ class MOTDTestCase(TestCase): self.motd.end_datetime = timezone.now() - timedelta(days=1) self.motd.save() - queryset = Message.objects.get_for_now() + queryset = Message.on_organization.get_for_now() self.assertEqual(queryset.exists(), False) @@ -43,6 +50,6 @@ class MOTDTestCase(TestCase): self.motd.enabled = False self.motd.save() - queryset = Message.objects.get_for_now() + queryset = Message.on_organization.get_for_now() self.assertEqual(queryset.exists(), False) diff --git a/mayan/apps/motd/tests/test_organization_views.py b/mayan/apps/motd/tests/test_organization_views.py new file mode 100644 index 0000000000..c167cd6055 --- /dev/null +++ b/mayan/apps/motd/tests/test_organization_views.py @@ -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 + ) diff --git a/mayan/apps/motd/urls.py b/mayan/apps/motd/urls.py index 709e8d7488..0f0d02f5e6 100644 --- a/mayan/apps/motd/urls.py +++ b/mayan/apps/motd/urls.py @@ -10,7 +10,9 @@ urlpatterns = patterns( '', url(r'^list/$', MessageListView.as_view(), name='message_list'), url(r'^create/$', MessageCreateView.as_view(), name='message_create'), - url(r'^(?P\d+)/edit/$', MessageEditView.as_view(), name='message_edit'), + url( + r'^(?P\d+)/edit/$', MessageEditView.as_view(), name='message_edit' + ), url( r'^(?P\d+)/delete/$', MessageDeleteView.as_view(), name='message_delete' diff --git a/mayan/apps/motd/views.py b/mayan/apps/motd/views.py index 8d1c391e7d..e0f460ee5e 100644 --- a/mayan/apps/motd/views.py +++ b/mayan/apps/motd/views.py @@ -21,7 +21,6 @@ logger = logging.getLogger(__name__) class MessageCreateView(SingleObjectCreateView): fields = ('label', 'message', 'enabled', 'start_datetime', 'end_datetime') - model = Message view_permission = permission_message_create def get_extra_context(self): @@ -29,9 +28,11 @@ class MessageCreateView(SingleObjectCreateView): 'title': _('Create message'), } + def get_queryset(self): + return Message.on_organization.all() + class MessageDeleteView(SingleObjectDeleteView): - model = Message object_permission = permission_message_delete post_action_redirect = reverse_lazy('motd:message_list') @@ -42,10 +43,12 @@ class MessageDeleteView(SingleObjectDeleteView): 'title': _('Delete the message: %s?') % self.get_object(), } + def get_queryset(self): + return Message.on_organization.all() + class MessageEditView(SingleObjectEditView): fields = ('label', 'message', 'enabled', 'start_datetime', 'end_datetime') - model = Message object_permission = permission_message_edit post_action_redirect = reverse_lazy('motd:message_list') @@ -55,9 +58,11 @@ class MessageEditView(SingleObjectEditView): 'title': _('Edit message: %s') % self.get_object(), } + def get_queryset(self): + return Message.on_organization.all() + class MessageListView(SingleObjectListView): - model = Message object_permission = permission_message_view def get_extra_context(self): @@ -65,3 +70,6 @@ class MessageListView(SingleObjectListView): 'hide_link': True, 'title': _('Messages'), } + + def get_queryset(self): + return Message.on_organization.all()