Files
2021-10-25 12:59:54 +05:00

118 lines
5.1 KiB
Python

"""
Table for storing information about whether or not Studio users have course creation privileges.
"""
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.db import models
from django.db.models.signals import post_init, post_save
from django.dispatch import Signal, receiver
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from organizations.models import Organization
# A signal that will be sent when users should be added or removed from the creator group
# providing_args=["caller", "user", "state", "organizations"]
update_creator_state = Signal()
# A signal that will be sent when admin should be notified of a pending user request
# providing_args=["user"]
send_admin_notification = Signal()
# A signal that will be sent when user should be notified of change in course creator privileges
# providing_args=["user", "state"]
send_user_notification = Signal()
class CourseCreator(models.Model):
"""
Creates the database table model.
.. no_pii:
"""
UNREQUESTED = 'unrequested'
PENDING = 'pending'
GRANTED = 'granted'
DENIED = 'denied'
# Second value is the "human-readable" version.
STATES = (
(UNREQUESTED, _('unrequested')),
(PENDING, _('pending')),
(GRANTED, _('granted')),
(DENIED, _('denied')),
)
user = models.OneToOneField(User, help_text=_("Studio user"), on_delete=models.CASCADE)
state_changed = models.DateTimeField('state last updated', auto_now_add=True,
help_text=_("The date when state was last updated"))
state = models.CharField(max_length=24, blank=False, choices=STATES, default=UNREQUESTED,
help_text=_("Current course creator state"))
note = models.CharField(max_length=512, blank=True, help_text=_("Optional notes about this user (for example, "
"why course creation access was denied)"))
organizations = models.ManyToManyField(Organization, blank=True,
help_text=_("Organizations under which the user is allowed "
"to create courses."))
all_organizations = models.BooleanField(default=True,
help_text=_("Grant the user the permission to create courses "
"in ALL organizations"))
def __str__(self):
return f"{self.user} | {self.state} [{self.state_changed}]"
@receiver(post_init, sender=CourseCreator)
def post_init_callback(sender, **kwargs): # lint-amnesty, pylint: disable=unused-argument
"""
Extend to store previous state.
"""
instance = kwargs['instance']
instance.orig_state = instance.state
instance.orig_all_organizations = instance.all_organizations
@receiver(post_save, sender=CourseCreator)
def post_save_callback(sender, **kwargs):
"""
Extend to update state_changed time and fire event to update course creator group, if appropriate.
"""
instance = kwargs['instance']
# We only wish to modify the state_changed time if the state has been modified. We don't wish to
# modify it for changes to the notes field.
# We need to keep track of all_organization switch. If this switch is changed we are going to remove the
# Course Creator group.
if instance.state != instance.orig_state or instance.all_organizations != instance.orig_all_organizations:
granted_state_change = instance.state == CourseCreator.GRANTED or instance.orig_state == CourseCreator.GRANTED # pylint: disable=consider-using-in
# If either old or new state is 'granted', we must manipulate the course creator
# group maintained by authz. That requires staff permissions (stored admin).
if granted_state_change:
assert hasattr(instance, 'admin'), 'Must have stored staff user to change course creator group'
update_creator_state.send(
sender=sender,
caller=instance.admin,
user=instance.user,
state=instance.state,
all_organizations=instance.all_organizations
)
# If user has been denied access, granted access, or previously granted access has been
# revoked, send a notification message to the user.
if instance.state == CourseCreator.DENIED or granted_state_change:
send_user_notification.send(
sender=sender,
user=instance.user,
state=instance.state
)
# If the user has gone into the 'pending' state, send a notification to interested admin.
if instance.state == CourseCreator.PENDING:
send_admin_notification.send(
sender=sender,
user=instance.user
)
instance.state_changed = timezone.now()
instance.orig_state = instance.state
instance.orig_all_organizations = instance.all_organizations
instance.save()