123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- from django.db import models
- from django.utils.html import conditional_escape, mark_safe
- from django.utils.translation import ugettext_lazy as _
- from mptt.forms import * # noqa
- from misago.core import forms
- from misago.core.validators import validate_sluggable
- from misago.forums.models import FORUMS_TREE_ID, Forum, ForumRole
- """
- Fields
- """
- class AdminForumFieldMixin(object):
- def __init__(self, *args, **kwargs):
- self.base_level = kwargs.pop('base_level', 1)
- kwargs['level_indicator'] = kwargs.get('level_indicator', '- - ')
- queryset = Forum.objects.filter(tree_id=FORUMS_TREE_ID)
- if not kwargs.pop('include_root', False):
- queryset = queryset.exclude(special_role="root_category")
- kwargs.setdefault('queryset',
- queryset)
- super(AdminForumFieldMixin, self).__init__(*args, **kwargs)
- def _get_level_indicator(self, obj):
- level = getattr(obj, obj._mptt_meta.level_attr) - self.base_level
- if level > 0:
- return mark_safe(conditional_escape(self.level_indicator) * level)
- else:
- return ''
- class AdminForumChoiceField(AdminForumFieldMixin, TreeNodeChoiceField):
- pass
- class AdminForumMultipleChoiceField(AdminForumFieldMixin,
- TreeNodeMultipleChoiceField):
- pass
- class MisagoForumMixin(object):
- def __init__(self, *args, **kwargs):
- self.parent = None
- if not 'queryset' in kwargs:
- kwargs['queryset'] = Forum.objects.order_by('lft')
- if kwargs.get('error_messages', {}):
- kwargs['error_messages'].update({
- 'invalid_choice': self.INVALID_CHOICE_ERROR
- })
- else:
- kwargs['error_messages'] = {
- 'invalid_choice': self.INVALID_CHOICE_ERROR
- }
- super(MisagoForumMixin, self).__init__(*args, **kwargs)
- def set_acl(self, acl=None):
- queryset = Forum.objects.root_category().get_descendants()
- if acl:
- allowed_ids = [0]
- for forum_id, perms in acl.get('forums', {}).items():
- if perms.get('can_see') and perms.get('can_browse'):
- allowed_ids.append(forum_id)
- queryset = queryset.filter(id__in=allowed_ids)
- self.queryset = queryset
- def _get_level_indicator(self, obj):
- level = obj.level - 1
- return mark_safe(conditional_escape('- - ') * level)
- class ForumChoiceField(MisagoForumMixin, TreeNodeChoiceField):
- INVALID_CHOICE_ERROR = _("Select valid forum.")
- class ForumsMultipleChoiceField(MisagoForumMixin, TreeNodeMultipleChoiceField):
- INVALID_CHOICE_ERROR = _("Select valid forums.")
- """
- Forms
- """
- FORUM_ROLES = (
- ('category', _('Category')),
- ('forum', _('Forum')),
- ('redirect', _('Redirect')),
- )
- class ForumFormBase(forms.ModelForm):
- role = forms.ChoiceField(label=_("Type"), choices=FORUM_ROLES)
- name = forms.CharField(
- label=_("Name"),
- validators=[validate_sluggable()])
- description = forms.CharField(
- label=_("Description"), max_length=2048, required=False,
- widget=forms.Textarea(attrs={'rows': 3}),
- help_text=_("Optional description explaining forum intented "
- "purpose."))
- redirect_url = forms.URLField(
- label=_("Redirect URL"),
- validators=[validate_sluggable()],
- help_text=_('If forum type is redirect, enter here its URL.'),
- required=False)
- css_class = forms.CharField(
- label=_("CSS class"), required=False,
- help_text=_("Optional CSS class used to customize this forum "
- "appearance from templates."))
- is_closed = forms.YesNoSwitch(
- label=_("Closed forum"), required=False,
- help_text=_("Only members with valid permissions can post in "
- "closed forums."))
- css_class = forms.CharField(
- label=_("CSS class"), required=False,
- help_text=_("Optional CSS class used to customize this forum "
- "appearance from templates."))
- prune_started_after = forms.IntegerField(
- label=_("Thread age"), min_value=0,
- help_text=_("Prune thread if number of days since its creation is "
- "greater than specified. Enter 0 to disable this "
- "pruning criteria."))
- prune_replied_after = forms.IntegerField(
- label=_("Last reply"), min_value=0,
- help_text=_("Prune thread if number of days since last reply is "
- "greater than specified. Enter 0 to disable this "
- "pruning criteria."))
- class Meta:
- model = Forum
- fields = [
- 'role',
- 'name',
- 'description',
- 'redirect_url',
- 'css_class',
- 'is_closed',
- 'prune_started_after',
- 'prune_replied_after',
- 'archive_pruned_in',
- ]
- def clean_copy_permissions(self):
- data = self.cleaned_data['copy_permissions']
- if data and data.pk == self.instance.pk:
- message = _("Permissions cannot be copied from forum into itself.")
- raise forms.ValidationError(message)
- return data
- def clean_archive_pruned_in(self):
- data = self.cleaned_data['archive_pruned_in']
- if data and data.pk == self.instance.pk:
- message = _("Forum cannot act as archive for itself.")
- raise forms.ValidationError(message)
- return data
- def clean(self):
- data = super(ForumFormBase, self).clean()
- self.instance.set_name(data.get('name'))
- if data['role'] != 'category':
- if not data['new_parent'].level:
- message = _("Only categories can have no parent category.")
- raise forms.ValidationError(message)
- if data['role'] == 'redirect':
- if not data.get('redirect_url'):
- message = _("This forum is redirect, yet you haven't "
- "specified URL to which it should redirect "
- "after click.")
- raise forms.ValidationError(message)
- return data
- def ForumFormFactory(instance):
- parent_queryset = Forum.objects.all_forums(True).order_by('lft')
- if instance.pk:
- not_siblings = models.Q(lft__lt=instance.lft)
- not_siblings = not_siblings | models.Q(rght__gt=instance.rght)
- parent_queryset = parent_queryset.filter(not_siblings)
- return type('ForumFormFinal', (ForumFormBase,), {
- 'new_parent': AdminForumChoiceField(
- label=_("Parent forum"),
- queryset=parent_queryset,
- initial=instance.parent,
- empty_label=None),
- 'copy_permissions': AdminForumChoiceField(
- label=_("Copy permissions"),
- help_text=_("You can replace this forum permissions with "
- "permissions copied from forum selected here."),
- queryset=Forum.objects.all_forums(),
- empty_label=_("Don't copy permissions"),
- required=False),
- 'archive_pruned_in': AdminForumChoiceField(
- label=_("Archive"),
- help_text=_("Instead of being deleted, pruned threads can be "
- "moved to designated forum."),
- queryset=Forum.objects.all_forums(),
- empty_label=_("Don't archive pruned threads"),
- required=False),
- })
- class DeleteForumFormBase(forms.ModelForm):
- class Meta:
- model = Forum
- fields = []
- def clean(self):
- data = super(DeleteForumFormBase, self).clean()
- if data.get('move_threads_to'):
- if data['move_threads_to'].pk == self.instance.pk:
- message = _("You are trying to move this forum threads to "
- "itself.")
- raise forms.ValidationError(message)
- if data['move_threads_to'].role == 'category':
- message = _("Threads can't be moved to category.")
- raise forms.ValidationError(message)
- if data['move_threads_to'].role == 'redirect':
- message = _("Threads can't be moved to redirect.")
- raise forms.ValidationError(message)
- moving_to_child = self.instance.has_child(data['move_threads_to'])
- if moving_to_child and not data.get('move_children_to'):
- message = _("You are trying to move this forum threads to a "
- "child forum that will be deleted together with "
- "this forum.")
- raise forms.ValidationError(message)
- if data.get('move_children_to'):
- if data['move_children_to'].special_role == 'root_category':
- for child in self.instance.get_children().iterator():
- if child.role != 'category':
- message = _("One or more child forums in forum are "
- "not categories and thus cannot be made "
- "root categories.")
- raise forms.ValidationError(message)
- return data
- def DeleteFormFactory(instance):
- content_queryset = Forum.objects.all_forums().order_by('lft')
- fields = {
- 'move_threads_to': AdminForumChoiceField(
- label=_("Move forum threads to"),
- queryset=content_queryset,
- initial=instance.parent,
- empty_label=_('Delete with forum'),
- required=False),
- }
- not_siblings = models.Q(lft__lt=instance.lft)
- not_siblings = not_siblings | models.Q(rght__gt=instance.rght)
- children_queryset = Forum.objects.all_forums(True)
- children_queryset = children_queryset.filter(not_siblings).order_by('lft')
- if children_queryset.exists():
- fields['move_children_to'] = AdminForumChoiceField(
- label=_("Move child forums to"),
- queryset=children_queryset,
- empty_label=_('Delete with forum'),
- required=False)
- return type('DeleteForumFormFinal', (DeleteForumFormBase,), fields)
- class ForumRoleForm(forms.ModelForm):
- name = forms.CharField(label=_("Role name"))
- class Meta:
- model = ForumRole
- fields = ['name']
- def RoleForumACLFormFactory(forum, forum_roles, selected_role):
- attrs = {
- 'forum': forum,
- 'role': forms.ModelChoiceField(
- label=_("Role"),
- required=False,
- queryset=forum_roles,
- initial=selected_role,
- empty_label=_("No access"))
- }
- return type('RoleForumACLForm', (forms.Form,), attrs)
- def ForumRolesACLFormFactory(role, forum_roles, selected_role):
- attrs = {
- 'role': role,
- 'forum_role': forms.ModelChoiceField(
- label=_("Role"),
- required=False,
- queryset=forum_roles,
- initial=selected_role,
- empty_label=_("No access"))
- }
- return type('ForumRolesACLForm', (forms.Form,), attrs)
|