__init__.py 5.3 KB

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