__init__.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. """
  2. Posting process implementation
  3. """
  4. from importlib import import_module
  5. from django.utils import timezone
  6. from misago.conf import settings
  7. from misago.core import forms
  8. START = 0
  9. REPLY = 1
  10. EDIT = 2
  11. class PostingInterrupt(Exception):
  12. def __init__(self, message):
  13. if not message:
  14. raise ValueError("You have to provide PostingInterrupt message.")
  15. self.message = message
  16. class EditorFormset(object):
  17. def __init__(self, **kwargs):
  18. self.errors = []
  19. self._forms_list = []
  20. self._forms_dict = {}
  21. is_private = kwargs['forum'].special_role == "private_threads"
  22. kwargs['is_private'] = is_private
  23. self.kwargs = kwargs
  24. self.__dict__.update(kwargs)
  25. self.datetime = timezone.now()
  26. self.middlewares = []
  27. self._load_middlewares()
  28. @property
  29. def start_form(self):
  30. return self.mode == START
  31. @property
  32. def reply_form(self):
  33. return self.mode == REPLY
  34. @property
  35. def edit_form(self):
  36. return self.mode == EDIT
  37. def _load_middlewares(self):
  38. kwargs = self.kwargs.copy()
  39. kwargs.update({
  40. 'datetime': self.datetime,
  41. 'parsing_result': {},
  42. })
  43. for middleware in settings.MISAGO_POSTING_MIDDLEWARES:
  44. module_name = '.'.join(middleware.split('.')[:-1])
  45. class_name = middleware.split('.')[-1]
  46. middleware_module = import_module(module_name)
  47. middleware_class = getattr(middleware_module, class_name)
  48. try:
  49. middleware_obj = middleware_class(prefix=middleware, **kwargs)
  50. if middleware_obj.use_this_middleware():
  51. self.middlewares.append((middleware, middleware_obj))
  52. except PostingInterrupt:
  53. raise ValueError("Posting process can only be "
  54. "interrupted during pre_save phase")
  55. def get_forms_list(self):
  56. """return list of forms belonging to formset"""
  57. if not self._forms_list:
  58. self._build_forms_cache()
  59. return self._forms_list
  60. def get_forms_dict(self):
  61. """return list of forms belonging to formset"""
  62. if not self._forms_dict:
  63. self._build_forms_cache()
  64. return self._forms_dict
  65. def _build_forms_cache(self):
  66. try:
  67. for middleware, obj in self.middlewares:
  68. form = obj.make_form()
  69. if form:
  70. self._forms_dict[middleware] = form
  71. self._forms_list.append(form)
  72. except PostingInterrupt:
  73. raise ValueError("Posting process can only be "
  74. "interrupted during pre_save phase")
  75. def get_main_forms(self):
  76. """return list of main forms"""
  77. main_forms = []
  78. for form in self.get_forms_list():
  79. try:
  80. if form.is_main and form.legend:
  81. main_forms.append(form)
  82. except AttributeError:
  83. pass
  84. return main_forms
  85. def get_supporting_forms(self):
  86. """return list of supporting forms"""
  87. supporting_forms = {}
  88. for form in self.get_forms_list():
  89. try:
  90. if form.is_supporting:
  91. supporting_forms.setdefault(form.location, []).append(form)
  92. except AttributeError:
  93. pass
  94. return supporting_forms
  95. def is_valid(self):
  96. """validate all forms"""
  97. all_forms_valid = True
  98. for form in self.get_forms_list():
  99. if not form.is_valid():
  100. if not form.is_bound:
  101. form_class = form.__class__.__name__
  102. raise ValueError("%s didn't receive any data" % form_class)
  103. all_forms_valid = False
  104. for field_errors in form.errors.as_data().values():
  105. self.errors.extend([unicode(e[0]) for e in field_errors])
  106. return all_forms_valid
  107. def save(self):
  108. """change state"""
  109. forms_dict = self.get_forms_dict()
  110. try:
  111. for middleware, obj in self.middlewares:
  112. obj.pre_save(forms_dict.get(middleware))
  113. except PostingInterrupt as e:
  114. raise ValueError("Posting process can only be interrupted "
  115. "from within interrupt_posting method")
  116. for middleware, obj in self.middlewares:
  117. obj.interrupt_posting(forms_dict.get(middleware))
  118. try:
  119. for middleware, obj in self.middlewares:
  120. obj.save(forms_dict.get(middleware))
  121. for middleware, obj in self.middlewares:
  122. obj.post_save(forms_dict.get(middleware))
  123. except PostingInterrupt as e:
  124. raise ValueError("Posting process can only be interrupted "
  125. "from within interrupt_posting method")
  126. def update(self):
  127. """handle POST that shouldn't result in state change"""
  128. forms_dict = self.get_forms_dict()
  129. for middleware, obj in self.middlewares:
  130. obj.pre_save(forms_dict.get(middleware))
  131. class PostingMiddleware(object):
  132. """
  133. Abstract middleware classes
  134. """
  135. def __init__(self, **kwargs):
  136. self.kwargs = kwargs
  137. self.__dict__.update(kwargs)
  138. def use_this_middleware(self):
  139. return True
  140. def make_form(self):
  141. pass
  142. def pre_save(self, form):
  143. pass
  144. def interrupt_posting(self, form):
  145. pass
  146. def save(self, form):
  147. pass
  148. def post_save(self, form):
  149. pass