devilry_account
— User account models and views¶
The devilry_account
module takes care of autentication,
user profile editing, user profile creation, etc.
About the devilry User model¶
Devilry uses a completely custom Django user model:
- It does not have the permission framework.
- Only superusers get access to the Django admin UI.
- We use full names instead of separate
first_name
andlast_name
fields, but we store the last name to make it possible to sort on that. - We support multiple usernames for each user (only used when the authentication backend uses usernames).
- We support multiple email addresses per user.
- We do not use a boolean field for
is_active
. Instead we handle this via asuspended_datetime
field, and we have a field where reason for suspension can be set. - We have a field for storing the preferred language of the user.
Datamodel API¶
The data models was introduced by issue 780.
-
class
devilry.devilry_account.models.
UserQuerySet
(model=None, query=None, using=None, hints=None)¶ Bases:
django.db.models.query.QuerySet
Use this if need to get efficient access to the primary
UserEmail
.This will add the
notification_useremail_objects
attribute to each returnedUser
.notification_useremail_objects
is a list that you can use if you need access to theUserEmail
objects. UseUser.notification_emails()
to access the emails as a list of strings.
Use this if need to get efficient access to the primary
UserEmail
.This will add the
primary_useremail_objects
attribute to each returnedUser
.primary_useremail_objects
is a list, and you should not use it directly. UseUser.primary_useremail_object()
orUser.primary_email()
to access the primary email.
Use this if need to get efficient access to the primary
UserName
.This will add the
primary_username_objects
attribute to each returnedUser
.primary_username_objects
is a list, and you should not use it directly. UseUser.primary_username_object()
orUser.primary_username()
to access the primary username.
-
filter_by_emails
(emails)¶ Filter the queryset to only include users with email address in the
emails
iterable.
-
filter_by_usernames
(usernames)¶ Filter the queryset to only include users with username in the
usernames
iterable.
-
class
devilry.devilry_account.models.
UserManager
¶ Bases:
django.contrib.auth.base_user.BaseUserManager
Manager for
User
.-
get_queryset
()¶ Return a new QuerySet object. Subclasses can override this method to customize the behavior of the Manager.
-
filter_by_emails
(emails)¶
-
filter_by_usernames
(usernames)¶
-
user_is_basenodeadmin
(user, *basenode_modelsclasses)¶ Check if the given user is admin on any of the given
basenode_modelsclasses
.Parameters: basenode_modelsclasses – Model classes. They must have an admins
one-to-many relationship with User.
-
user_is_admin
(user)¶ Check if the given user is admin on any subject or period.
-
user_is_admin_or_superuser
(user)¶ Return
True
ifuser.is_superuser
, and fall back to callinguser_is_admin()
if not.
-
user_is_examiner
(user)¶ Returns
True
if the givenuser
is examiner on any AssignmentGroup.
-
user_is_student
(user)¶ Returns
True
if the givenuser
is candidate on any AssignmentGroup.
-
create_user
(username='', email='', password=None, **kwargs)¶ Create a new user.
Requires
username
oremail
, and both can be supplied. Ifusername
is supplied, we create a UserName object withis_primary=True
, and ifemail
is supplied, we create a UserEmail object withuse_for_notifications=True
.If
password
is supplied, we set the password, otherwise we set an unusable password.Other than that, you can provide any
User
fields exceptshortname
.shortname
is created from username or email (in that order).
-
create_superuser
(password=None, **kwargs)¶ Create a new superuser.
-
get_by_email
(email)¶ Get a user by any of their emails.
Raises: User.DoesNotExist
– If noUserEmail
with the given email is found.Returns: The user object. Return type: User
-
get_by_username
(username)¶ Get a user by any of their username.
Raises: User.DoesNotExist
– If noUserName
with the given username is found.Returns: The user object. Return type: User
-
bulk_create_from_emails
(emails)¶ Bulk create users for all the emails in the given
emails
iterator.All users is created with unusable password.
We create a
UserEmail
object for each of the created users. This UserEmail object hasis_primary
set toTrue
.Raises: devilry_account.exceptions.IllegalOperationError
– If theCRADMIN_LEGACY_USE_EMAIL_AUTH_BACKEND
-setting isFalse
.
Returns: A
(created_users, excluded_emails)
-tuple.created_users
is a queryset with the created users.excluded_emails
is a set of the emails that already existed.
-
bulk_create_from_usernames
(usernames)¶ Bulk create users for all the usernames in the given
usernames
iterator.All users is created with unusable password.
We create a
UserName
object for each of the created users. This UserName object hasis_primary
set toTrue
.Raises: devilry_account.exceptions.IllegalOperationError
– If theCRADMIN_LEGACY_USE_EMAIL_AUTH_BACKEND
-setting isTrue
.
Returns: A
(created_users, excluded_usernames)
-tuple.created_users
is a queryset with the created users.excluded_usernames
is a set of the usernames that already existed.
-
-
class
devilry.devilry_account.models.
User
(*args, **kwargs)¶ Bases:
django.contrib.auth.base_user.AbstractBaseUser
User model for Devilry.
-
is_superuser
¶ Is this user a superuser?
-
shortname
¶ Short name for the user. This will be set to the primary email address or to the primary username depending on the auth backend. Must be unique.
-
fullname
¶ Full name of the user. Optional.
-
lastname
¶ The last name of the user. Optional. Used to sort by last name.
-
datetime_joined
¶ The datetime the user was created.
-
suspended_datetime
¶ Datetime when this account was suspended.
-
suspended_reason
¶ Reason why the account is suspended.
-
languagecode
¶ The language code for the preferred language for the user.
-
is_active
¶ bool(x) -> bool
Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.
-
get_short_name
()¶ Get the short name for the user.
-
get_displayname
()¶ Get as much of the name as possible. If we have only shortname, return that, if we have both shortname and fullname, return
<fullname> (<shortname>)
.
-
get_initials
()¶ Get the initials of the users name.
-
clean
()¶ Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.
-
notification_emails
¶ Get the notification emails as a list of strings.
Only works if you have used
UserQuerySet.prefetch_related_notification_emails()
on the queryset.
-
primary_useremail_object
¶ Get the primary email address of the user as a
UserEmail
object.Only works if you have used
UserQuerySet.prefetch_related_primary_email()
on the queryset.Returns
None
if we have no primary email.
-
primary_email
¶ Get the primary email address of the user as a string.
Only works if you have used
UserQuerySet.prefetch_related_primary_email()
on the queryset.Returns
None
if we have no primary email.
-
primary_username_object
¶ Get the primary username of the user as a
UserName
object.Only works if you have used
UserQuerySet.prefetch_related_primary_username()
on the queryset.Returns
None
if we have no primary username.
-
primary_username
¶ Get the primary username of the user as a string.
Only works if you have used
UserQuerySet.prefetch_related_primary_username()
on the queryset.Returns
None
if we have no primary username.
-
exception
DoesNotExist
¶ Bases:
django.core.exceptions.ObjectDoesNotExist
-
exception
MultipleObjectsReturned
¶ Bases:
django.core.exceptions.MultipleObjectsReturned
-
-
class
devilry.devilry_account.models.
MergedUser
(*args, **kwargs)¶ Bases:
django.db.models.base.Model
A merge user is created when two users are merged by devilry.devilry_account.user_merger.UserMerger.
-
source_user
¶ The user we merged from. This user will have lost most of their data after the merge, but some foreign keys like created_by etc. will still remain.
-
target_user
¶ The target of the merge. Most foreign keys previously pointing to MergedUser.source_user will have been moved to this user. This is all documented in MergedUser.summary_json.
-
summary_json
¶ Summary of the merge as JSON.
Documents what changes was made during the merge.
-
exception
DoesNotExist
¶ Bases:
django.core.exceptions.ObjectDoesNotExist
-
exception
MultipleObjectsReturned
¶ Bases:
django.core.exceptions.MultipleObjectsReturned
-
-
class
devilry.devilry_account.models.
AbstractUserIdentity
(*args, **kwargs)¶ Bases:
django.db.models.base.Model
Base class for
UserEmail
andUserName
.-
user
¶ Foreign key to the user owning this email address.
-
created_datetime
¶ The datetime when this was created.
-
last_updated_datetime
¶ The datetime when this was last updated.
-
clean
()¶ Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.
-
-
class
devilry.devilry_account.models.
UserEmail
(*args, **kwargs)¶ Bases:
devilry.devilry_account.models.AbstractUserIdentity
Stores a single email address for a
User
.-
email
¶ The email address of the user. Must be unique.
-
use_for_notifications
¶ Is this a notification email for the user? A user can have multiple notification emails.
-
is_primary
¶ Is this the primary email for the user? Valid values are:
None
andTrue
, and only one UserEmail per user can haveis_primary=True
.
-
clean
()¶ Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.
-
exception
DoesNotExist
¶ Bases:
django.core.exceptions.ObjectDoesNotExist
-
exception
MultipleObjectsReturned
¶ Bases:
django.core.exceptions.MultipleObjectsReturned
-
-
class
devilry.devilry_account.models.
UserName
(*args, **kwargs)¶ Bases:
devilry.devilry_account.models.AbstractUserIdentity
Stores a single username for a
User
.The username is used for login, and the primary username is synced into
User.shortname
.-
username
¶ The username of the user. Must be unique.
-
is_primary
¶ Is this the primary username for the user? Valid values are:
None
andTrue
, and only one UserName per user can haveis_primary=True
.
-
clean
()¶ Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.
-
exception
DoesNotExist
¶ Bases:
django.core.exceptions.ObjectDoesNotExist
-
exception
MultipleObjectsReturned
¶ Bases:
django.core.exceptions.MultipleObjectsReturned
-
-
class
devilry.devilry_account.models.
PermissionGroupUser
(*args, **kwargs)¶ Bases:
django.db.models.base.Model
Defines the many-to-many relationship between
User
andPermissionGroup
.-
permissiongroup
¶ The group.
-
user
¶ The user.
-
exception
DoesNotExist
¶ Bases:
django.core.exceptions.ObjectDoesNotExist
-
exception
MultipleObjectsReturned
¶ Bases:
django.core.exceptions.MultipleObjectsReturned
-
-
class
devilry.devilry_account.models.
PermissionGroupQuerySet
(model=None, query=None, using=None, hints=None)¶ Bases:
django.db.models.query.QuerySet
-
class
devilry.devilry_account.models.
PermissionGroup
(*args, **kwargs)¶ Bases:
django.db.models.base.Model
Permission group data model.
Each group has a
grouptype
which determines the type of objects it can be added to.-
GROUPTYPE_DEPARTMENTADMIN
= 'departmentadmin'¶ The value for
grouptype
that identifies the group as a departmentadmin permission group.
-
GROUPTYPE_SUBJECTADMIN
= 'subjectadmin'¶ The value for
grouptype
that identifies the group as a subjectadmin permission group.
-
GROUPTYPE_PERIODADMIN
= 'periodadmin'¶ The value for
grouptype
that identifies the group as a periodadmin permission group.
-
GROUPTYPE_CHOICES
= (('departmentadmin', 'Department administrator group'), ('subjectadmin', 'Course administrator group'), ('periodadmin', 'Semester administrator group'))¶ Choices for
grouptype
.
-
name
¶ The name of the group. Must be unique.
-
created_datetime
¶ The time this group was created.
-
updated_datetime
¶ Last time this group was updated.
-
syncsystem_update_datetime
¶ Last time this group was updated from a third party sync system.
-
grouptype
¶ The grouptype determines what kind of object a group can be added to –
subjectadmin
: Can be assigned to a singledevilry.apps.core.models.Subject
.periodadmin
: Can be assigned to a singledevilry.apps.core.models.Period
.departmentadmin
: Can be assigned to multipledevilry.apps.core.models.Subject
.
-
is_custom_manageable
¶ Is this group manageable by normal admins?
Only superusers can edit the group if this is
False
. Use cases for setting this toFalse
:- Superusers want to create groups that they have full control over.
- Groups imported from a third party sync system.
If grouptype is
departmentadmin
, this can not beTrue
.
-
users
¶ Users belonging to this group.
-
clean
()¶ Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.
-
exception
DoesNotExist
¶ Bases:
django.core.exceptions.ObjectDoesNotExist
-
exception
MultipleObjectsReturned
¶ Bases:
django.core.exceptions.MultipleObjectsReturned
-
-
class
devilry.devilry_account.models.
PeriodPermissionGroupQuerySet
(model=None, query=None, using=None, hints=None)¶ Bases:
django.db.models.query.QuerySet
QuerySet for
PeriodPermission
.-
user_is_periodadmin_for_period
(user, period)¶ Find out if the given
user
is"periodadmin"
on the givenperiod
.You normally do not use this directly, but use
get_devilryrole_for_user_on_period()
.Parameters: - period – A
devilry.apps.core.models.Subject
object. - user – A User object.
Returns: True
if the given user is periodadmin on the given period, otherwise it returnsFalse
.Return type: bool
- period – A
-
get_devilryrole_for_user_on_period
(user, period)¶ Get the devilryrole for the given
user
on the givenperiod
.See also
If you need to find the same information for a subject, use
SubjectPermissionGroupQuerySet.get_devilryrole_for_user_on_subject()
.Parameters: - period – A
devilry.apps.core.models.Subject
object. - user – A User object.
Returns: One of the following looked up in the listed order:
"departmentadmin"
: If the user is superuser or in aSubjectPermissionGroup
withPermissionGroup.GROUPTYPE_DEPARTMENTADMIN
for the subject owning the period."subjectadmin"
: If the user is in aSubjectPermissionGroup
withPermissionGroup.GROUPTYPE_SUBJECTADMIN
for the subject owning the period."periodadmin"
: If the user is in aPeriodPermissionGroup
for the period.None
: If no of the conditions listed above is met.
Return type: str
- period – A
-
get_custom_managable_periodpermissiongroup_for_period
(period)¶ Get the PeriodPermissionGroup where
PermissionGroup.is_custom_manageable
isTrue
for the givenperiod
.Each
devilry.apps.core.models.Period
has exactly one custom managablePermissionGroup
, which is the permission group where admins added by non-superusers via the admin UI are added.Note
The queryset used does
select_related('permissiongroup')
, so looking up permissiongroup for the returned PeriodPermissionGroup does not require an extra database query.Parameters: period – A devilry.apps.core.models.Period
object.Raises: PeriodPermissionGroup.DoesNotExist
– If no custom managable PermissionGroup exists for the given period.
-
-
class
devilry.devilry_account.models.
PeriodPermissionGroup
(*args, **kwargs)¶ Bases:
django.db.models.base.Model
Defines the many-to-many relationship between
devilry.apps.core.Period
andPermissionGroup
.-
permissiongroup
¶ The group.
-
period
¶ The
devilry.apps.core.Period
.
-
clean
()¶ Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.
-
exception
DoesNotExist
¶ Bases:
django.core.exceptions.ObjectDoesNotExist
-
exception
MultipleObjectsReturned
¶ Bases:
django.core.exceptions.MultipleObjectsReturned
-
-
class
devilry.devilry_account.models.
SubjectPermissionGroupQuerySet
(model=None, query=None, using=None, hints=None)¶ Bases:
django.db.models.query.QuerySet
QuerySet for
SubjectPermission
.-
user_is_departmentadmin_for_subject
(user, subject)¶ Find out if the given
user
is"departmentadmin"
on the givensubject
.You normally do not use this directly, but use
get_devilryrole_for_user_on_subject()
.Parameters: - subject – A
devilry.apps.core.models.Subject
object. - user – A User object.
Returns: True
if the given user is departmentadmin on the given subject, otherwise it returnsFalse
.Return type: bool
- subject – A
-
user_is_subjectadmin_for_subject
(user, subject)¶ Find out if the given
user
is"subjectadmin"
on the givensubject
.This does not take higher permissions into consideration, so you should check if the user is departmentadmin with
user_is_departmentadmin_for_subject()
if you want to find the highest permission for the user.You normally do not use this directly, but use
get_devilryrole_for_user_on_subject()
.Parameters: - subject – A
devilry.apps.core.models.Subject
object. - user – A User object.
Returns: True
if the given user is subjectadmin on the given subject, otherwise it returnsFalse
.Return type: bool
- subject – A
-
get_devilryrole_for_user_on_subject
(user, subject)¶ Get the devilryrole for the given
user
on the givensubject
.See also
If you need to find the same information for a period, use
PeriodPermissionGroupQuerySet.get_devilryrole_for_user_on_period()
.Parameters: - subject – A
devilry.apps.core.models.Subject
object. - user – A User object.
Returns: One of the following looked up in the listed order:
"departmentadmin"
: If the user is superuser or in aSubjectPermissionGroup
withPermissionGroup.GROUPTYPE_DEPARTMENTADMIN
for the subject owning the period."subjectadmin"
: If the user is in aSubjectPermissionGroup
withPermissionGroup.GROUPTYPE_SUBJECTADMIN
for the subject owning the period.None
: If no of the conditions listed above is met.
Return type: str
- subject – A
-
get_custom_managable_subjectpermissiongroup_for_subject
(subject)¶ Get the SubjectPermissionGroup where
PermissionGroup.is_custom_manageable
isTrue
for the givensubject
.Each
devilry.apps.core.models.Subject
has exactly one custom managablePermissionGroup
, which is the permission group where admins added by non-superusers via the admin UI are added.Note
The queryset used does
select_related('permissiongroup')
, so looking up permissiongroup for the returned SubjectPermissionGroup does not require an extra database query.Parameters: subject – A devilry.apps.core.models.Subject
object.Raises: SubjectPermissionGroup.DoesNotExist
– If no custom managable PermissionGroup exists for the given subject.
-
-
class
devilry.devilry_account.models.
SubjectPermissionGroup
(*args, **kwargs)¶ Bases:
django.db.models.base.Model
Defines the many-to-many relationship between
devilry.apps.core.Subject
andPermissionGroup
.-
permissiongroup
¶ The permissiongroup.
-
subject
¶ The
devilry.apps.core.Subject
.
-
clean
()¶ Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.
-
exception
DoesNotExist
¶ Bases:
django.core.exceptions.ObjectDoesNotExist
-
exception
MultipleObjectsReturned
¶ Bases:
django.core.exceptions.MultipleObjectsReturned
-
-
exception
devilry.devilry_account.models.
AssignmentGuidelinesLookupError
¶ Bases:
Exception
-
class
devilry.devilry_account.models.
PeriodUserGuidelineAcceptanceQuerySet
(model=None, query=None, using=None, hints=None)¶ Bases:
django.db.models.query.QuerySet
-
mark_guidelines_as_accepted
(user: devilry.devilry_account.models.User, period: Period, devilryrole: str) → bool¶ Mark guidelines as accepted unless they already are for the given user, period and devilryrole.
Returns: True if a new PeriodUserGuidelineAcceptance instance was created, otherwise return False. Return type: bool
-
-
class
devilry.devilry_account.models.
PeriodUserGuidelineAcceptance
(id, user, period, devilryrole, accepted_datetime, guidelines_version, matched_regex)¶ Bases:
django.db.models.base.Model
-
exception
DoesNotExist
¶ Bases:
django.core.exceptions.ObjectDoesNotExist
-
exception
MultipleObjectsReturned
¶ Bases:
django.core.exceptions.MultipleObjectsReturned
-
exception