post.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. from django.contrib.postgres.fields import JSONField
  2. from django.core.urlresolvers import reverse
  3. from django.db import models
  4. from django.dispatch import receiver
  5. from django.utils import timezone
  6. from misago.conf import settings
  7. from .. import threadtypes
  8. from ..checksums import is_post_valid, update_post_checksum
  9. class Post(models.Model):
  10. category = models.ForeignKey('misago_categories.Category')
  11. thread = models.ForeignKey('misago_threads.Thread')
  12. poster = models.ForeignKey(
  13. settings.AUTH_USER_MODEL,
  14. blank=True,
  15. null=True,
  16. on_delete=models.SET_NULL,
  17. )
  18. poster_name = models.CharField(max_length=255)
  19. poster_ip = models.GenericIPAddressField()
  20. original = models.TextField()
  21. parsed = models.TextField()
  22. checksum = models.CharField(max_length=64, default='-')
  23. mentions = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="mention_set")
  24. has_attachments = models.BooleanField(default=False)
  25. attachments_cache = JSONField(null=True, blank=True)
  26. posted_on = models.DateTimeField()
  27. updated_on = models.DateTimeField()
  28. hidden_on = models.DateTimeField(default=timezone.now)
  29. edits = models.PositiveIntegerField(default=0)
  30. last_editor = models.ForeignKey(
  31. settings.AUTH_USER_MODEL,
  32. blank=True,
  33. null=True,
  34. on_delete=models.SET_NULL,
  35. related_name='+',
  36. )
  37. last_editor_name = models.CharField(max_length=255, null=True, blank=True)
  38. last_editor_slug = models.SlugField(max_length=255, null=True, blank=True)
  39. hidden_by = models.ForeignKey(
  40. settings.AUTH_USER_MODEL,
  41. blank=True,
  42. null=True,
  43. on_delete=models.SET_NULL,
  44. related_name='+',
  45. )
  46. hidden_by_name = models.CharField(max_length=255, null=True, blank=True)
  47. hidden_by_slug = models.SlugField(max_length=255, null=True, blank=True)
  48. has_reports = models.BooleanField(default=False)
  49. has_open_reports = models.BooleanField(default=False)
  50. is_unapproved = models.BooleanField(default=False, db_index=True)
  51. is_hidden = models.BooleanField(default=False)
  52. is_protected = models.BooleanField(default=False)
  53. is_event = models.BooleanField(default=False, db_index=True)
  54. event_type = models.CharField(max_length=255, null=True, blank=True)
  55. event_context = JSONField(null=True, blank=True)
  56. class Meta:
  57. index_together = [
  58. ('is_event', 'is_hidden')
  59. ]
  60. def __unicode__(self):
  61. return '%s...' % self.original[10:].strip()
  62. def delete(self, *args, **kwargs):
  63. from ..signals import delete_post
  64. delete_post.send(sender=self)
  65. super(Post, self).delete(*args, **kwargs)
  66. def merge(self, other_post):
  67. if self.thread_id != other_post.thread_id:
  68. message = "only posts belonging to same thread can be merged"
  69. raise ValueError(message)
  70. message = "posts made by different authors can't be merged"
  71. if self.poster_id and other_post.poster_id:
  72. if self.poster_id != other_post.poster_id:
  73. raise ValueError(message)
  74. else:
  75. raise ValueError(message)
  76. if self.pk == other_post.pk:
  77. raise ValueError("post can't be merged with itself")
  78. other_post.original = '%s\n\n%s' % (other_post.original, self.original)
  79. other_post.parsed = '%s\n%s' % (other_post.parsed, self.parsed)
  80. update_post_checksum(other_post)
  81. from ..signals import merge_post
  82. merge_post.send(sender=self, other_thread=other_post)
  83. def move(self, new_thread):
  84. from ..signals import move_post
  85. self.category = new_thread.category
  86. self.thread = new_thread
  87. move_post.send(sender=self)
  88. @property
  89. def thread_type(self):
  90. return self.category.thread_type
  91. def get_absolute_url(self):
  92. return self.thread_type.get_post_absolute_url(self)
  93. def get_api_url(self):
  94. return self.thread_type.get_post_api_url(self)
  95. @property
  96. def short(self):
  97. if self.is_valid:
  98. if len(self.original) > 150:
  99. return '%s...' % self.original[:150].strip()
  100. else:
  101. return self.original
  102. else:
  103. return ''
  104. @property
  105. def is_valid(self):
  106. return is_post_valid(self)
  107. @property
  108. def is_first_post(self):
  109. return self.pk == self.thread.first_post_id