__init__.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. from rest_framework import serializers
  2. from django.core.exceptions import PermissionDenied
  3. from django.http import QueryDict
  4. from django.utils import timezone
  5. from django.utils.module_loading import import_string
  6. from ....conf import settings
  7. class PostingInterrupt(Exception):
  8. def __init__(self, message): # pylint: disable=super-init-not-called
  9. if not message:
  10. raise ValueError("You have to provide PostingInterrupt message.")
  11. self.message = message
  12. class PostingEndpoint:
  13. START = 0
  14. REPLY = 1
  15. EDIT = 2
  16. def __init__(self, request, mode, **kwargs):
  17. # we are using lock on user model to protect us from flood
  18. request.user.lock()
  19. # build kwargs dict for passing to middlewares
  20. self.kwargs = kwargs
  21. self.kwargs.update(
  22. {
  23. "mode": mode,
  24. "request": request,
  25. "settings": request.settings,
  26. "user": request.user,
  27. "user_acl": request.user_acl,
  28. }
  29. )
  30. self.__dict__.update(kwargs)
  31. # some middlewares (eg. emailnotification) may call render()
  32. # which will crash if this isn't set to false
  33. request.include_frontend_context = False
  34. self.datetime = timezone.now()
  35. self.errors = {}
  36. self._is_validated = False
  37. self.middlewares = self._load_middlewares()
  38. self._serializers = self._initialize_serializers()
  39. @property
  40. def is_start_endpoint(self):
  41. return self.mode == self.START
  42. @property
  43. def is_reply_endpoint(self):
  44. return self.mode == self.REPLY
  45. @property
  46. def is_edit_endpoint(self):
  47. return self.mode == self.EDIT
  48. def _load_middlewares(self):
  49. kwargs = self.kwargs.copy()
  50. kwargs.update({"datetime": self.datetime, "parsing_result": {}})
  51. middlewares = []
  52. for middleware in settings.MISAGO_POSTING_MIDDLEWARES:
  53. middleware_class = import_string(middleware)
  54. try:
  55. middleware_obj = middleware_class(prefix=middleware, **kwargs)
  56. if middleware_obj.use_this_middleware():
  57. middlewares.append((middleware, middleware_obj))
  58. except PostingInterrupt:
  59. raise ValueError(
  60. "Posting process can only be interrupted during pre_save phase"
  61. )
  62. return middlewares
  63. def get_serializers(self):
  64. """return list of serializers belonging to serializerset"""
  65. return self._serializers
  66. def _initialize_serializers(self):
  67. try:
  68. serializers = {}
  69. for middleware, obj in self.middlewares:
  70. serializer = obj.get_serializer()
  71. if serializer:
  72. serializers[middleware] = serializer
  73. return serializers
  74. except PostingInterrupt:
  75. raise ValueError(
  76. "Posting process can only be interrupted during pre_save phase"
  77. )
  78. def is_valid(self):
  79. """validate data against all serializers"""
  80. for serializer in self._serializers.values():
  81. if not serializer.is_valid():
  82. self.errors.update(serializer.errors)
  83. self._is_validated = True
  84. return not self.errors
  85. def save(self):
  86. """save new state to backend"""
  87. if not self._is_validated or self.errors:
  88. raise RuntimeError(
  89. "You need to validate posting data successfully before calling save"
  90. )
  91. try:
  92. for middleware, obj in self.middlewares:
  93. obj.pre_save(self._serializers.get(middleware))
  94. except PostingInterrupt as e:
  95. raise ValueError(
  96. "Posting process can only be interrupted "
  97. "from within interrupt_posting method"
  98. )
  99. try:
  100. for middleware, obj in self.middlewares:
  101. obj.interrupt_posting(self._serializers.get(middleware))
  102. except PostingInterrupt as e:
  103. raise PermissionDenied(e.message)
  104. try:
  105. for middleware, obj in self.middlewares:
  106. obj.save(self._serializers.get(middleware))
  107. for middleware, obj in self.middlewares:
  108. obj.post_save(self._serializers.get(middleware))
  109. except PostingInterrupt as e:
  110. raise ValueError(
  111. "Posting process can only be interrupted "
  112. "from within interrupt_posting method"
  113. )
  114. class PostingMiddleware:
  115. """abstract middleware class"""
  116. def __init__(self, **kwargs):
  117. self.kwargs = kwargs
  118. self.__dict__.update(kwargs)
  119. def use_this_middleware(self):
  120. return True
  121. def get_serializer(self):
  122. pass
  123. def pre_save(self, serializer):
  124. pass
  125. def interrupt_posting(self, serializer):
  126. pass
  127. def save(self, serializer):
  128. pass
  129. def post_save(self, serializer):
  130. pass