__init__.py 4.8 KB

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