models.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. from urllib import parse
  2. from django.contrib.auth.models import (
  3. AbstractBaseUser,
  4. BaseUserManager,
  5. PermissionsMixin,
  6. )
  7. from django.db import models
  8. from django.db.models import Q
  9. from django.utils.translation import gettext_lazy as _
  10. class UserManager(BaseUserManager):
  11. """
  12. A custom user manager to deal with emails as unique identifiers for auth
  13. instead of usernames. The default that's used is "UserManager"
  14. """
  15. def create_user(self, email, password, **extra_fields):
  16. """
  17. Creates and saves a User with the given email and password.
  18. """
  19. if not email:
  20. raise ValueError("The Email must be set")
  21. email = self.normalize_email(email)
  22. user = self.model(email=email, **extra_fields)
  23. user.set_password(password)
  24. user.save()
  25. return user
  26. def create_superuser(self, email, password, **extra_fields):
  27. extra_fields.setdefault("is_staff", True)
  28. extra_fields.setdefault("is_superuser", True)
  29. extra_fields.setdefault("is_active", True)
  30. if extra_fields.get("is_staff") is not True:
  31. raise ValueError("Superuser must have is_staff=True.")
  32. if extra_fields.get("is_superuser") is not True:
  33. raise ValueError("Superuser must have is_superuser=True.")
  34. return self.create_user(email, password, **extra_fields)
  35. def alert_notification_recipients(self, notification):
  36. """ Distinct users associated with a project notification who should receive alerts """
  37. queryset = self.filter(
  38. organizations_ext_organizationuser__team__projects__projectalert__notification=notification
  39. )
  40. return self._exclude_recipients(queryset, notification.project_alert.project)
  41. def uptime_monitor_recipients(self, monitor):
  42. """ Distinct users associated with a project uptime monitor who should receive alerts """
  43. queryset = self.filter(
  44. organizations_ext_organizationuser__team__projects__monitor=monitor
  45. )
  46. return self._exclude_recipients(queryset, monitor.project)
  47. def _exclude_recipients(self, queryset, project):
  48. """ Exclude from queryset users who have a preference not to receive notifications """
  49. return queryset.exclude(
  50. Q(
  51. userprojectalert__project=project,
  52. userprojectalert__status=ProjectAlertStatus.OFF,
  53. )
  54. | Q(subscribe_by_default=False, userprojectalert=None),
  55. ).distinct()
  56. class User(AbstractBaseUser, PermissionsMixin):
  57. email = models.EmailField(unique=True)
  58. name = models.CharField(_("name"), max_length=255, blank=True)
  59. is_staff = models.BooleanField(
  60. _("staff status"),
  61. default=False,
  62. help_text=_("Designates whether the user can log into this site."),
  63. )
  64. is_active = models.BooleanField(
  65. _("active"),
  66. default=True,
  67. help_text=_(
  68. "Designates whether this user should be treated as active. "
  69. "Unselect this instead of deleting accounts."
  70. ),
  71. )
  72. analytics = models.JSONField(null=True, blank=True)
  73. created = models.DateTimeField(auto_now_add=True)
  74. subscribe_by_default = models.BooleanField(
  75. default=True,
  76. help_text="Subscribe to project notifications by default. Overrides project settings",
  77. )
  78. USERNAME_FIELD = "email"
  79. EMAIL_FIELD = "email"
  80. objects = UserManager()
  81. def __str__(self):
  82. return self.email
  83. def get_full_name(self):
  84. return self.email
  85. def get_short_name(self):
  86. return self.email
  87. @property
  88. def username(self):
  89. return self.email
  90. @property
  91. def auth_token(self):
  92. return None
  93. def set_register_analytics_tags(self, tags: str):
  94. """
  95. Set UTM querystring to user's analytics field
  96. """
  97. parsed_tags = parse.parse_qsl(tags.strip("?"))
  98. if self.analytics is None:
  99. self.analytics = {}
  100. self.analytics["register"] = {
  101. tag[0]: tag[1] for tag in parsed_tags if tag[0].startswith("utm_")
  102. }
  103. class ProjectAlertStatus(models.IntegerChoices):
  104. OFF = 0, "off"
  105. ON = 1, "on"
  106. class UserProjectAlert(models.Model):
  107. """
  108. Determine if user alert notifications should always happen, never, or defer to default
  109. Default is stored as the lack of record.
  110. """
  111. user = models.ForeignKey(User, on_delete=models.CASCADE)
  112. project = models.ForeignKey("projects.Project", on_delete=models.CASCADE)
  113. status = models.PositiveSmallIntegerField(choices=ProjectAlertStatus.choices)
  114. class Meta:
  115. unique_together = ("user", "project")