Commit 5856791a by Awais Qureshi Committed by GitHub

Merge pull request #452 from edx/awais786/ECOM-5880-org/group-defalut-roles

Publisher | Org/Group default role assignment
parents ce6f8e12 bd24aef6
......@@ -162,9 +162,19 @@ class FAQAdmin(admin.ModelAdmin):
list_display = ('question',)
class OrganizationUserRoleInline(admin.TabularInline):
# course-meta-data models are importing in publisher app. So just for safe side
# to avoid any circular issue importing the publisher model here.
from course_discovery.apps.publisher.models import OrganizationUserRole
model = OrganizationUserRole
extra = 3
@admin.register(Organization)
class OrganizationAdmin(admin.ModelAdmin):
list_display = ('uuid', 'key', 'name',)
inlines = [OrganizationUserRoleInline, ]
list_filter = ('partner',)
readonly_fields = ('uuid',)
search_fields = ('uuid', 'name', 'key',)
......
from django.contrib import admin
from course_discovery.apps.publisher.models import Course, CourseRun, Seat, State, UserAttributes
from course_discovery.apps.publisher.models import (
Course, CourseRun, OrganizationUserRole, Seat, State, UserAttributes
)
admin.site.register(Course)
admin.site.register(CourseRun)
admin.site.register(OrganizationUserRole)
admin.site.register(Seat)
admin.site.register(State)
admin.site.register(UserAttributes)
# Name of the administrative group for the Publisher app
ADMIN_GROUP_NAME = 'Publisher Admins'
# Permissions/Roles
COORDINATOR = 'partner_coordinator'
REVIEWER = 'marketing_reviewer'
PUBLISHER = 'publisher'
# -*- coding: utf-8 -*-
# Generated by Django 1.9.11 on 2016-11-29 09:10
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django_extensions.db.fields
class Migration(migrations.Migration):
dependencies = [
('course_metadata', '0038_seat_sku'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('publisher', '0015_auto_20161117_1210'),
]
operations = [
migrations.CreateModel(
name='HistoricalOrganizationUserRole',
fields=[
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name='created')),
('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name='modified')),
('role', models.CharField(choices=[('partner_coordinator', 'Partner Coordinator'), ('marketing_reviewer', 'Reviewer'), ('publisher', 'Publisher')], max_length=63, verbose_name='Role Type')),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
('organization', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='course_metadata.Organization')),
('user', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'get_latest_by': 'history_date',
'ordering': ('-history_date', '-history_id'),
'verbose_name': 'historical organization user role',
},
),
migrations.CreateModel(
name='OrganizationUserRole',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name='created')),
('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name='modified')),
('role', models.CharField(choices=[('partner_coordinator', 'Partner Coordinator'), ('marketing_reviewer', 'Reviewer'), ('publisher', 'Publisher')], max_length=63, verbose_name='Role Type')),
('organization', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_roles', to='course_metadata.Organization')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organization_user_roles', to=settings.AUTH_USER_MODEL)),
],
),
migrations.AlterUniqueTogether(
name='organizationuserrole',
unique_together=set([('organization', 'user', 'role')]),
),
]
......@@ -19,6 +19,7 @@ from course_discovery.apps.course_metadata.choices import CourseRunPacing
from course_discovery.apps.course_metadata.models import LevelType, Subject, Person, Organization
from course_discovery.apps.course_metadata.utils import UploadToFieldNamePath
from course_discovery.apps.ietf_language_tags.models import LanguageTag
from course_discovery.apps.publisher.constants import COORDINATOR, REVIEWER, PUBLISHER
from course_discovery.apps.publisher.emails import send_email_for_change_state
from course_discovery.apps.publisher.utils import is_email_notification_enabled
......@@ -360,3 +361,30 @@ class UserAttributes(TimeStampedModel):
class Meta:
verbose_name_plural = 'UserAttributes'
class OrganizationUserRole(TimeStampedModel):
""" User Roles model for Organization. """
ROLES_TYPE_CHOICES = (
(COORDINATOR, _('Partner Coordinator')),
(REVIEWER, _('Reviewer')),
(PUBLISHER, _('Publisher')),
)
organization = models.ForeignKey(Organization, related_name='user_roles')
user = models.ForeignKey(User, related_name='organization_user_roles')
role = models.CharField(max_length=63, choices=ROLES_TYPE_CHOICES, verbose_name='Role Type')
history = HistoricalRecords()
class Meta:
unique_together = (
('organization', 'user', 'role'),
)
def __str__(self):
return '{organization}: {user}: {role}'.format(
organization=self.organization,
user=self.user,
role=self.role
)
......@@ -11,7 +11,9 @@ from course_discovery.apps.core.tests.factories import UserFactory
from course_discovery.apps.course_metadata.choices import CourseRunPacing
from course_discovery.apps.course_metadata.tests import factories
from course_discovery.apps.ietf_language_tags.models import LanguageTag
from course_discovery.apps.publisher.models import Course, CourseRun, Seat, State, UserAttributes
from course_discovery.apps.publisher.models import (
Course, CourseRun, OrganizationUserRole, Seat, State, UserAttributes
)
class StateFactory(factory.DjangoModelFactory):
......@@ -84,3 +86,12 @@ class UserAttributeFactory(factory.DjangoModelFactory):
class Meta:
model = UserAttributes
class OrganizationUserRoleFactory(factory.DjangoModelFactory):
organization = factory.SubFactory(factories.OrganizationFactory)
user = factory.SubFactory(UserFactory)
role = FuzzyChoice([name for name, __ in OrganizationUserRole.ROLES_TYPE_CHOICES])
class Meta:
model = OrganizationUserRole
# pylint: disable=no-member
import ddt
from django.db import IntegrityError
from django.core.urlresolvers import reverse
from django.test import TestCase
from django_fsm import TransitionNotAllowed
from course_discovery.apps.core.tests.factories import UserFactory
from course_discovery.apps.course_metadata.tests.factories import OrganizationFactory
from course_discovery.apps.publisher.constants import COORDINATOR
from course_discovery.apps.publisher.models import State, Course
from course_discovery.apps.publisher.tests import factories
......@@ -189,3 +192,33 @@ class UserAttributeTests(TestCase):
enable_email_notification=self.user_attr.enable_email_notification
)
)
class OrganizationUserRoleTests(TestCase):
"""Tests of the OrganizationUserRole model."""
def setUp(self):
super(OrganizationUserRoleTests, self).setUp()
self.user = UserFactory()
self.organization = OrganizationFactory()
self.role = COORDINATOR
self.org_user_role = factories.OrganizationUserRoleFactory(
user=self.user, organization=self.organization, role=COORDINATOR
)
def test_str(self):
"""Verify that a organization-user-role is properly converted to a str."""
self.assertEqual(
str(self.org_user_role), '{organization}: {user}: {role}'.format(
organization=self.org_user_role.organization,
user=self.org_user_role.user,
role=self.org_user_role.role
)
)
def test_unique_constraint(self):
"""Verify that a organization-user-role not allow same user roles under one organization."""
with self.assertRaises(IntegrityError):
factories.OrganizationUserRoleFactory(
user=self.user, organization=self.organization, role=COORDINATOR
)
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-23 16:57-0500\n"
"POT-Creation-Date: 2016-11-29 15:24+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -559,6 +559,18 @@ msgstr ""
msgid "Professional (no ID verifiation)"
msgstr ""
#: apps/publisher/models.py
msgid "Partner Coordinator"
msgstr ""
#: apps/publisher/models.py
msgid "Reviewer"
msgstr ""
#: apps/publisher/models.py
msgid "Publisher"
msgstr ""
#: apps/publisher/views.py
msgid "Course created successfully."
msgstr ""
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-23 16:57-0500\n"
"POT-Creation-Date: 2016-11-29 15:24+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-23 16:57-0500\n"
"POT-Creation-Date: 2016-11-29 15:24+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -679,6 +679,18 @@ msgid "Professional (no ID verifiation)"
msgstr ""
"Pröféssïönäl (nö ÌD vérïfïätïön) Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тє#"
#: apps/publisher/models.py
msgid "Partner Coordinator"
msgstr "Pärtnér Çöördïnätör Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#"
#: apps/publisher/models.py
msgid "Reviewer"
msgstr "Révïéwér Ⱡ'σяєм ιρѕυм ∂#"
#: apps/publisher/models.py
msgid "Publisher"
msgstr "Püßlïshér Ⱡ'σяєм ιρѕυм ∂σł#"
#: apps/publisher/views.py
msgid "Course created successfully."
msgstr "Çöürsé çréätéd süççéssfüllý. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#"
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-23 16:57-0500\n"
"POT-Creation-Date: 2016-11-29 15:24+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment