combo/combo/manager/forms.py

465 lines
16 KiB
Python

# combo - content management system
# Copyright (C) 2014-2016 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
from django import forms
from django.conf import settings
from django.contrib.auth.models import Group
from django.core.exceptions import ValidationError
from django.forms import formset_factory
from django.template import Template, TemplateSyntaxError
from django.template.loader import TemplateDoesNotExist, get_template
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from combo import utils
from combo.apps.wcs.utils import get_wcs_matching_card_model, get_wcs_options
from combo.data.forms import get_page_choices
from combo.data.models import Page, ParentContentCell, SiteSettings, compile_sub_slug
from .fields import ImageIncludingSvgField
@utils.cache_during_request
def get_groups_as_choices():
return [(x.id, x.name) for x in Group.objects.all().order_by('name')]
def get_template_name_choices(with_models=False):
def template_exists(template):
try:
get_template(settings.COMBO_PUBLIC_TEMPLATES[template].get('template'))
except TemplateDoesNotExist:
return False
return True
templates = [(x[0], x[1]['name']) for x in settings.COMBO_PUBLIC_TEMPLATES.items()]
templates = [x for x in templates if template_exists(x[0])]
templates.sort(key=lambda x: x[1])
if not with_models or settings.COMBO_PUBLIC_TEMPLATES_ROOT_PAGE is None:
return templates
try:
model_root_page = Page.objects.get(slug=settings.COMBO_PUBLIC_TEMPLATES_ROOT_PAGE)
except Page.DoesNotExist:
return templates
templates.extend([('model_%s' % p.slug, p.title) for p in model_root_page.get_descendants()])
templates.sort(key=lambda x: x[1])
return templates
def build_tab_is_not_default(form):
if getattr(form, 'is_not_default', None) is True:
return True
for field_name, field in form.fields.items():
if field.initial is not None:
if field.initial != form.initial.get(field_name):
return True
else:
if bool(form.initial.get(field_name)):
return True
return False
class PageDuplicateForm(forms.Form):
title = forms.CharField(label=_('New title'), max_length=150, required=False)
class PageExportForm(forms.Form):
with_subpages = forms.BooleanField(label=_('Also export subpages'), required=False)
class PageAddForm(forms.ModelForm):
class Meta:
model = Page
fields = ('title', 'template_name')
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
self.parent = kwargs.pop('parent', None)
super().__init__(*args, **kwargs)
self.fields['template_name'].widget = forms.Select(
choices=get_template_name_choices(with_models=True)
)
self.fields['template_name'].initial = settings.COMBO_DEFAULT_PUBLIC_TEMPLATE
def save(self, *args, **kwargs):
template_name = self.cleaned_data['template_name']
if template_name.startswith('model_'):
try:
model_page = Page.objects.get(slug=template_name[6:])
except Page.DoesNotExist:
pass
else:
# model page, create page by duplication
self.instance = model_page.duplicate(title=self.cleaned_data['title'], parent=self.parent)
if self.instance.pk is None:
# not a model page, create page from form
self.instance = super().save(commit=False, *args, **kwargs)
self.instance.parent = self.parent
self.instance.save()
if self.instance.slug != 'index' or self.parent:
for placeholder in self.instance.get_placeholders(request=self.request):
if not placeholder.acquired:
continue
ParentContentCell.objects.create(page=self.instance, placeholder=placeholder.key, order=0)
return self.instance
class PageRestrictedAddForm(PageAddForm):
class Meta:
model = Page
fields = ('title', 'template_name', 'parent')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
group_ids = [x.id for x in self.request.user.groups.all()]
self.fields['parent'].queryset = Page.objects.filter(subpages_edit_role_id__in=group_ids)
self.fields['parent'].required = True
self.fields['parent'].empty_label = None
def save(self, *args, **kwargs):
self.parent = self.cleaned_data.get('parent')
return super().save(*args, **kwargs)
class PageEditTitleForm(forms.ModelForm):
class Meta:
model = Page
fields = ('title',)
class PageEditSlugForm(forms.ModelForm):
class Meta:
model = Page
fields = ('slug', 'sub_slug')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance.sub_slug:
result = get_wcs_matching_card_model(self.instance.sub_slug)
if result:
del self.fields['sub_slug']
def clean_slug(self):
value = self.cleaned_data.get('slug')
if self.instance.slug == value:
return value
if Page.objects.filter(slug=value, parent_id=self.instance.parent_id).count() > 0:
raise ValidationError(_('Slug must be unique'), code='unique')
return value
def clean_sub_slug(self):
value = self.cleaned_data.get('sub_slug')
if not value:
return value
try:
compile_sub_slug(value)
except re.error:
raise ValidationError(_('Bad Regular expression.'), code='bad_regex')
return value
class PageEditLinkedCardForm(forms.ModelForm):
carddef_reference = forms.ChoiceField(
label=_('Linked card model'),
required=False,
)
class Meta:
model = Page
fields = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
card_models = get_wcs_options('/api/cards/@list')
self.fields['carddef_reference'].choices = [('', '-----')] + card_models
self.help_texts = {}
for card_model in card_models:
sub_slug = card_model[0].split(':')[1].replace('-', '_')
self.help_texts[card_model[0]] = mark_safe(
_('The card identifier will be available in the variable <code>%s_id</code>.') % sub_slug
)
if self.instance.sub_slug:
result = get_wcs_matching_card_model(self.instance.sub_slug)
if result:
self.initial['carddef_reference'] = result[0]
def save(self, commit=True, *args, **kwargs):
super().save(commit=False, *args, **kwargs)
if self.cleaned_data.get('carddef_reference'):
self.instance.sub_slug = '%s_id' % self.cleaned_data['carddef_reference'].split(':')[1]
else:
self.instance.sub_slug = ''
if commit:
self.instance.save()
return self.instance
class PageEditDescriptionForm(forms.ModelForm):
class Meta:
model = Page
fields = ('description',)
class PageEditPictureForm(forms.ModelForm):
class Meta:
model = Page
fields = ('picture',)
field_classes = {'picture': ImageIncludingSvgField}
class PageEditExtraVariableForm(forms.Form):
key = forms.CharField(label=_('Variable name'), required=False)
value = forms.CharField(
label=_('Value template'), widget=forms.TextInput(attrs={'size': 60}), required=False
)
PageEditExtraVariablesFormSet = formset_factory(PageEditExtraVariableForm)
class PageVisibilityForm(forms.ModelForm):
class Meta:
model = Page
fields = ('public', 'groups')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['groups'].queryset = Group.objects.order_by('name')
class PageSelectTemplateForm(forms.ModelForm):
class Meta:
model = Page
fields = ('template_name',)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['template_name'].widget = forms.Select(choices=get_template_name_choices())
class PageEditRedirectionForm(forms.ModelForm):
class Meta:
model = Page
fields = ('redirect_url',)
def clean_redirect_url(self):
value = self.cleaned_data.get('redirect_url')
if value:
try:
Template(value)
except TemplateSyntaxError as e:
raise ValidationError(_('syntax error: %s') % e)
return value
def save(self, *args, **kwargs):
page = super().save(*args, **kwargs)
page.redirect_url = page.redirect_url.strip()
page.save()
return page
class PageEditRolesForm(forms.ModelForm):
edit_role = forms.ModelChoiceField(
label=_('Edit Role'), required=False, queryset=Group.objects.all().order_by('name')
)
subpages_edit_role = forms.ModelChoiceField(
label=_('Subpages Edit Role'), required=False, queryset=Group.objects.all().order_by('name')
)
class Meta:
model = Page
fields = (
'edit_role',
'subpages_edit_role',
)
class PageEditIncludeInNavigationForm(forms.ModelForm):
include_in_navigation = forms.BooleanField(label=_('Include in navigation menus'), required=False)
apply_to_subpages = forms.BooleanField(label=_('Apply to subpages'), required=False)
class Meta:
model = Page
fields = []
def __init__(self, *args, **kwargs):
instance = kwargs['instance']
initial = kwargs.pop('initial', {})
initial['include_in_navigation'] = not instance.exclude_from_navigation
super().__init__(initial=initial, *args, **kwargs)
if initial['include_in_navigation'] or not instance.has_children():
del self.fields['apply_to_subpages']
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if self.cleaned_data.get('apply_to_subpages'):
subpages = self.instance.get_descendants(include_myself=True)
subpages.update(exclude_from_navigation=bool(not self.cleaned_data['include_in_navigation']))
else:
self.instance.exclude_from_navigation = not self.cleaned_data['include_in_navigation']
self.instance.save()
return self.instance
class CellVisibilityForm(forms.Form):
visibility = forms.ChoiceField(
label=_('Visibility'),
choices=[
('all', _('Everybody')),
('logged', _('Logged users')),
('unlogged', _('Unlogged users')),
('groups-any', _('Users with one of these groups')),
('groups-none', _('Users with none of these groups')),
],
initial='all',
)
groups = forms.MultipleChoiceField(label=_('Groups'), required=False, choices=get_groups_as_choices)
condition = forms.CharField(
label=_('Display condition'),
widget=forms.TextInput(attrs={'class': 'text-wide'}),
max_length=1000,
required=False,
)
def __init__(self, *args, **kwargs):
self.instance = instance = kwargs.pop('instance')
initial = kwargs.get('initial')
initial['groups'] = [x.id for x in instance.groups.all()]
if instance.public:
if instance.restricted_to_unlogged:
initial['visibility'] = 'unlogged'
else:
initial['visibility'] = 'all'
else:
initial['visibility'] = 'logged'
if initial['groups']:
if instance.restricted_to_unlogged:
initial['visibility'] = 'groups-none'
else:
initial['visibility'] = 'groups-any'
initial['condition'] = instance.condition
super().__init__(*args, **kwargs)
def clean_condition(self):
condition = self.cleaned_data['condition']
if not condition:
return condition
try:
Template('{%% if %s %%}OK{%% endif %%}' % condition)
except TemplateSyntaxError:
raise ValidationError(_('Invalid syntax.'))
return condition
def save(self):
if self.cleaned_data['visibility'] == 'all':
self.instance.public = True
self.instance.restricted_to_unlogged = False
self.instance.groups.clear()
elif self.cleaned_data['visibility'] == 'logged':
self.instance.public = False
self.instance.restricted_to_unlogged = False
self.instance.groups.clear()
elif self.cleaned_data['visibility'] == 'unlogged':
self.instance.public = True
self.instance.restricted_to_unlogged = True
self.instance.groups.clear()
elif self.cleaned_data['visibility'] == 'groups-any':
self.instance.public = False
self.instance.restricted_to_unlogged = False
self.instance.groups.set(self.cleaned_data['groups'])
elif self.cleaned_data['visibility'] == 'groups-none':
self.instance.public = False
self.instance.restricted_to_unlogged = True
self.instance.groups.set(self.cleaned_data['groups'])
self.instance.condition = self.cleaned_data.get('condition')
self.instance.save()
return self.instance
class CellDuplicateForm(forms.Form):
target_page = forms.ModelChoiceField(
label=_('Target page'),
queryset=Page.objects.all(),
)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
self.current_page = kwargs.pop('current_page')
super().__init__(*args, **kwargs)
self.fields['target_page'].widget = forms.Select(choices=get_page_choices())
self.fields['target_page'].initial = self.current_page
class SiteImportForm(forms.Form):
site_file = forms.FileField(label=_('Site Export File'))
class SiteExportForm(forms.Form):
pages = forms.BooleanField(label=_('Pages'), required=False, initial=True)
cartography = forms.BooleanField(label=_('Maps'), required=False, initial=True)
pwa = forms.BooleanField(label=_('Mobile Application (PWA)'), required=False, initial=True)
assets = forms.BooleanField(label=_('Assets'), required=False, initial=True)
asset_files = forms.BooleanField(label=_('Assets Files'), required=False, initial=False)
payment = forms.BooleanField(label=_('Online Payment'), required=False, initial=True)
site_settings = forms.BooleanField(label=_('Site Settings'), required=False, initial=True)
class SiteSettingsForm(forms.ModelForm):
class Meta:
model = SiteSettings
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['welcome_page'].widget.template_name = 'combo/widgets/select_with_other_option.html'
self.fields['welcome_page'].widget.attrs['class'] = 'page-selector'
self.fields['initial_login_page'].widget.template_name = 'combo/widgets/select_with_other_option.html'
self.fields['initial_login_page'].widget.attrs['class'] = 'page-selector'
self.fields['welcome_page'].queryset = self.fields['welcome_page'].queryset.filter(public=True)
class PlaceholderOptionsForm(forms.Form):
fx_grid_layout = forms.ChoiceField(
label=_('Grid Layout'),
required=False,
choices=[
('', _('Manual')),
('fx-grid', _('1 column')),
('fx-grid--t2', _('2 columns')),
('fx-grid--t3', _('3 columns')),
],
)
class PageSnapshotSaveForm(forms.Form):
label = forms.CharField(label=_('Label'), max_length=150, required=True)