Changeset View
Changeset View
Standalone View
Standalone View
users/models.py
| from typing import Optional | from typing import Optional | ||||
| import logging | import logging | ||||
| from actstream.models import Action | from actstream.models import Action | ||||
| from django.contrib.admin.utils import NestedObjects | |||||
| from django.contrib.auth.models import AbstractUser | from django.contrib.auth.models import AbstractUser | ||||
| from django.db import models | from django.contrib.sessions.models import Session | ||||
| from django.db import models, DEFAULT_DB_ALIAS | |||||
| from django.db.models import Case, When, Value, IntegerField | from django.db.models import Case, When, Value, IntegerField | ||||
| from django.templatetags.static import static | from django.templatetags.static import static | ||||
| from django.urls import reverse | from django.urls import reverse | ||||
| from django.utils.translation import gettext_lazy as _ | from django.utils.translation import gettext_lazy as _ | ||||
| from django_jsonfield_backport.models import JSONField | from django_jsonfield_backport.models import JSONField | ||||
| from common.upload_paths import get_upload_to_hashed_path | from common.upload_paths import get_upload_to_hashed_path | ||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||
| class User(AbstractUser): | class User(AbstractUser): | ||||
| class Meta: | class Meta: | ||||
| db_table = 'auth_user' | db_table = 'auth_user' | ||||
| permissions = [('can_view_content', 'Can view subscription-only content')] | permissions = [('can_view_content', 'Can view subscription-only content')] | ||||
| email = models.EmailField(_('email address'), blank=False, null=False, unique=True) | email = models.EmailField(_('email address'), blank=False, null=False, unique=True) | ||||
| full_name = models.CharField(max_length=255, blank=True, default='') | full_name = models.CharField(max_length=255, blank=True, default='') | ||||
| image = models.ImageField(upload_to=get_upload_to_hashed_path, blank=True, null=True) | image = models.ImageField(upload_to=get_upload_to_hashed_path, blank=True, null=True) | ||||
| is_subscribed_to_newsletter = models.BooleanField(default=False) | is_subscribed_to_newsletter = models.BooleanField(default=False) | ||||
| badges = JSONField(null=True, blank=True) | badges = JSONField(null=True, blank=True) | ||||
| date_deletion_requested = models.DateTimeField(null=True, blank=True) | |||||
| @property | @property | ||||
| def image_url(self) -> Optional[str]: | def image_url(self) -> Optional[str]: | ||||
| """Return a URL of the Profile image.""" | """Return a URL of the Profile image.""" | ||||
| if not self.image: | if not self.image: | ||||
| return static('common/images/blank-profile-pic.png') | return static('common/images/blank-profile-pic.png') | ||||
| return self.image.url | return self.image.url | ||||
| Show All 10 Lines | def notifications(self): | ||||
| # Unread notifications come first | # Unread notifications come first | ||||
| .order_by('unread', '-date_created') | .order_by('unread', '-date_created') | ||||
| ) | ) | ||||
| @property | @property | ||||
| def notifications_unread(self): | def notifications_unread(self): | ||||
| return self.notifications.filter(date_read__isnull=True) | return self.notifications.filter(date_read__isnull=True) | ||||
| def logout_everywhere(self): | |||||
| """Find **all** user sessions and delete them. | |||||
| Caveat emptor: unless sessions are cleaned regularly, this is an expensive brute-force op | |||||
fsiddi: Can you add more info about when this is used? | |||||
raillaAuthorUnsubmitted Done Inline Actionsthis is not used: it shouldn't be necessary, as sessions will expire eventually and get collected by clearsessions which is already called once a day. railla: this is not used: it shouldn't be necessary, as sessions will expire eventually and get… | |||||
| """ | |||||
| user_sessions = ( | |||||
| s for s in Session.objects.all() if s.get_decoded().get('_auth_user_id') == self.pk | |||||
| ) | |||||
| for session in user_sessions: | |||||
| session.delete() | |||||
| def _get_nested_objects_collector(self) -> NestedObjects: | |||||
| collector = NestedObjects(using=DEFAULT_DB_ALIAS) | |||||
| collector.collect([self]) | |||||
| return collector | |||||
| @property | |||||
| def can_be_deleted(self) -> bool: | |||||
| """Fetch objects referencing this profile and determine if it can be deleted.""" | |||||
| if self.is_staff or self.is_superuser: | |||||
| return False | |||||
| collector = self._get_nested_objects_collector() | |||||
| if collector.protected: | |||||
| return False | |||||
| return True | |||||
| def request_deletion(self, date_deletion_requested): | |||||
| """Store date of the deletion request and deactivate the user.""" | |||||
| if not self.can_be_deleted: | |||||
| logger.error('Deletion requested for a protected account pk=%s, ignoring', self.pk) | |||||
| return | |||||
| logger.warning( | |||||
| 'Deletion of pk=%s requested on %s, deactivating this account', | |||||
| self.pk, | |||||
| date_deletion_requested, | |||||
| ) | |||||
| self.is_active = False | |||||
| self.date_deletion_requested = date_deletion_requested | |||||
| self.is_subscribed_to_newsletter = False | |||||
| self.save(update_fields=[ | |||||
| 'is_active', 'date_deletion_requested', 'is_subscribed_to_newsletter' | |||||
| ]) | |||||
| class Notification(models.Model): | class Notification(models.Model): | ||||
| """Store additional data about an actstream notification. | """Store additional data about an actstream notification. | ||||
| In general, it's not easy to determine if an action qualifies as a notification | In general, it's not easy to determine if an action qualifies as a notification | ||||
| for a certain user because of the variaty of targets | for a certain user because of the variaty of targets | ||||
| (assets, comments with relations to different pages and so on), | (assets, comments with relations to different pages and so on), | ||||
| so it's best to link actions to their relevant users when a new action is created. | so it's best to link actions to their relevant users when a new action is created. | ||||
| Show All 17 Lines | |||||
Can you add more info about when this is used?