models.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import uuid
  2. from django.contrib.postgres.indexes import GinIndex
  3. from django.contrib.postgres.search import SearchVectorField
  4. from django.db import models
  5. from psqlextra.models import PostgresPartitionedModel
  6. from psqlextra.types import PostgresPartitioningMethod
  7. from glitchtip.model_utils import FromStringIntegerChoices
  8. class IssueEventType(models.IntegerChoices):
  9. DEFAULT = 0, "default"
  10. ERROR = 1, "error"
  11. CSP = 2, "csp"
  12. class EventStatus(FromStringIntegerChoices):
  13. UNRESOLVED = 0, "unresolved"
  14. RESOLVED = 1, "resolved"
  15. IGNORED = 2, "ignored"
  16. class LogLevel(FromStringIntegerChoices):
  17. NOTSET = 0, "sample"
  18. DEBUG = 1, "debug"
  19. INFO = 2, "info"
  20. WARNING = 3, "warning"
  21. ERROR = 4, "error"
  22. FATAL = 5, "fatal"
  23. class Issue(models.Model):
  24. created = models.DateTimeField(auto_now_add=True)
  25. culprit = models.CharField(max_length=1024, blank=True, null=True)
  26. is_public = models.BooleanField(default=False)
  27. level = models.PositiveSmallIntegerField(
  28. choices=LogLevel.choices, default=LogLevel.ERROR
  29. )
  30. project = models.ForeignKey(
  31. "projects.Project", on_delete=models.CASCADE, related_name="issues"
  32. )
  33. title = models.CharField(max_length=255)
  34. type = models.PositiveSmallIntegerField(
  35. choices=IssueEventType.choices, default=IssueEventType.DEFAULT
  36. )
  37. status = models.PositiveSmallIntegerField(
  38. choices=EventStatus.choices, default=EventStatus.UNRESOLVED
  39. )
  40. short_id = models.PositiveIntegerField(null=True)
  41. class Meta:
  42. unique_together = (("project", "short_id"),)
  43. class IssueStats(models.Model):
  44. issue = models.OneToOneField(Issue, primary_key=True, on_delete=models.CASCADE)
  45. search_vector = SearchVectorField(null=True, editable=False)
  46. search_vector_created = models.DateTimeField(auto_now_add=True)
  47. count = models.PositiveIntegerField(default=1, editable=False)
  48. last_seen = models.DateTimeField(auto_now_add=True, db_index=True)
  49. class Meta:
  50. indexes = [GinIndex(fields=["search_vector"])]
  51. class IssueHash(models.Model):
  52. issue = models.ForeignKey(
  53. "issues.Issue", on_delete=models.CASCADE, related_name="hashes"
  54. )
  55. # Redundant project allows for unique constraint
  56. project = models.ForeignKey(
  57. "projects.Project", on_delete=models.CASCADE, related_name="+"
  58. )
  59. value = models.UUIDField(db_index=True)
  60. class Meta:
  61. constraints = [
  62. models.UniqueConstraint(
  63. fields=["project", "value"], name="issue hash project"
  64. )
  65. ]
  66. class Comment(models.Model):
  67. created = models.DateTimeField(auto_now_add=True)
  68. issue = models.ForeignKey(
  69. "issues.Issue", on_delete=models.CASCADE, related_name="comments"
  70. )
  71. user = models.ForeignKey(
  72. "users.User", null=True, on_delete=models.SET_NULL, related_name="+"
  73. )
  74. text = models.TextField(blank=True, null=True)
  75. class Meta:
  76. ordering = ("-created",)
  77. class IssueEvent(PostgresPartitionedModel, models.Model):
  78. id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
  79. issue = models.ForeignKey(Issue, on_delete=models.CASCADE)
  80. type = models.PositiveSmallIntegerField(default=0, choices=IssueEventType.choices)
  81. created = models.DateTimeField(auto_now_add=True)
  82. data = models.JSONField()
  83. class PartitioningMeta:
  84. method = PostgresPartitioningMethod.RANGE
  85. key = ["created"]