Source code for town6.forms.settings
import json
from wtforms.fields import BooleanField, RadioField
from wtforms.validators import InputRequired
from onegov.form import Form
from onegov.form.fields import ChosenSelectField, ChosenSelectMultipleField
from onegov.form.fields import TagsField
from onegov.org.forms.settings import (
GeneralSettingsForm as OrgGeneralSettingsForm)
from onegov.town6 import _
from onegov.user import UserCollection, User
from onegov.town6.theme import user_options
from wtforms.fields import StringField
from typing import Any, TYPE_CHECKING
if TYPE_CHECKING:
from onegov.org.models import Organisation
from webob import Response
[docs]
class GeneralSettingsForm(OrgGeneralSettingsForm):
""" Defines the settings form for onegov org. """
[docs]
page_image_position = RadioField(
fieldset=_('Images'),
description=_(
'Choose the position of the page images on the content pages'),
label=_('Page image position'),
choices=(
('as_content', _('As a content image (between the title and text '
'of a content page)')),
('header', _('As header image (wide above the page content)'))
),
default='as_content'
)
[docs]
body_font_family_ui = ChosenSelectField(
fieldset=_('Fonts'),
label=_('Font family serif'),
description=_('Used for text in html body'),
choices=[],
validators=[InputRequired()]
)
[docs]
header_font_family_ui = ChosenSelectField(
fieldset=_('Fonts'),
label=_('Font family sans-serif'),
description=_('Used for all the headings'),
choices=[],
validators=[InputRequired()]
)
@property
[docs]
def theme_options(self) -> dict[str, Any]:
options = self.model.theme_options
if self.primary_color.data is None:
options['primary-color-ui'] = user_options['primary-color-ui']
else:
options['primary-color-ui'] = self.primary_color.data
if self.page_image_position.data is None:
options['page-image-position'] = user_options[
'page-image-position']
else:
options['page-image-position'] = self.page_image_position.data
body_family = self.body_font_family_ui.data
if body_family not in self.theme.font_families.values():
options['body-font-family-ui'] = self.default_font_family
else:
options['body-font-family-ui'] = body_family
header_family = self.header_font_family_ui.data
if header_family not in self.theme.font_families.values():
options['header-font-family-ui'] = self.default_font_family
else:
options['header-font-family-ui'] = header_family
# override the options using the default values if no value was given
for key in options:
if not options[key]:
options[key] = user_options[key]
return options
@theme_options.setter
def theme_options(self, options: dict[str, Any]) -> None:
self.primary_color.data = options.get('primary-color-ui')
self.page_image_position.data = options.get('page-image-position')
self.body_font_family_ui.data = options.get(
'body-font-family-ui') or self.default_font_family
self.header_font_family_ui.data = options.get(
'header-font-family-ui') or self.default_font_family
@property
[docs]
def default_font_family(self) -> str | None:
return self.theme.default_options.get('body-font-family-ui')
@property
[docs]
def header_font_family(self) -> str | None:
return self.theme.default_options.get('header-font-family-ui')
[docs]
def populate_font_families(self) -> None:
self.body_font_family_ui.choices = [
(value, label) for label, value in self.theme.font_families.items()
]
self.header_font_family_ui.choices = [
(value, label) for label, value in self.theme.font_families.items()
]
[docs]
def on_request(self) -> None:
self.populate_font_families()
# We delete this from the org form
self.delete_field('font_family_sans_serif')
@self.request.after
def clear_locale(response: 'Response') -> None:
response.delete_cookie('locale')
[docs]
class ChatSettingsForm(Form):
[docs]
chat_topics = TagsField(
label=_('Chat Topics'),
description=_(
"The topics can be chosen on the form at the start of the chat. "
"Example topics are 'Social', 'Clubs' or 'Planning & Construction'"
". If left empty, all Chats get the topic 'General'."),
)
[docs]
specific_opening_hours = BooleanField(
label=_('Specific Opening Hours'),
description=_('If unchecked, the chat is open 24/7.'),
fieldset=_('Opening Hours'),
)
[docs]
opening_hours_chat = StringField(
label=_('Opening Hours'),
fieldset=_('Opening Hours'),
depends_on=('specific_opening_hours', 'y'),
render_kw={'class_': 'many many-opening-hours'}
)
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
[docs]
def process_obj(
self,
obj: 'Organisation' # type:ignore[override]
) -> None:
super().process_obj(obj)
self.chat_staff.data = obj.chat_staff or []
self.enable_chat.data = obj.enable_chat or False
self.chat_topics.data = obj.chat_topics or []
self.specific_opening_hours.data = obj.specific_opening_hours
if not obj.opening_hours_chat:
self.opening_hours_chat.data = self.time_to_json(None)
else:
self.opening_hours_chat.data = self.time_to_json(
obj.opening_hours_chat
)
[docs]
def populate_obj( # type:ignore[override]
self,
obj: 'Organisation', # type:ignore[override]
*args: Any,
**kwargs: Any
) -> None:
super().populate_obj(obj, *args, **kwargs)
obj.chat_staff = self.chat_staff.data
obj.enable_chat = self.enable_chat.data
obj.chat_topics = self.chat_topics.data # type:ignore[assignment]
obj.specific_opening_hours = self.specific_opening_hours.data
obj.opening_hours_chat = self.json_to_time(
self.opening_hours_chat.data) or None
[docs]
def populate_chat_staff(self) -> None:
people = UserCollection(self.request.session).query().filter(
User.role.in_(['editor', 'admin']))
staff_members = [(
(p.id.hex, p.username)
) for p in people]
self.chat_staff.choices = list(staff_members)
[docs]
def ensure_valid_opening_hours(self) -> bool:
if not self.specific_opening_hours.data:
return True
opening_times = self.json_to_time(self.opening_hours_chat.data)
if not opening_times:
assert isinstance(self.opening_hours_chat.errors, list)
self.opening_hours_chat.errors.append(
_('Please add a day and times to each opening hour '
'entry or deactivate specific opening hours.')
)
return False
result = True
for day, start, end in opening_times:
# FIXME: shouldn't this use time_errors?
if not (day and start and end):
assert isinstance(self.opening_hours_chat.errors, list)
self.opening_hours_chat.errors.append(
_('Please add a day and times to each opening hour '
'entry or deactivate specific opening hours.')
)
result = False
if start > end:
assert isinstance(self.opening_hours_chat.errors, list)
self.opening_hours_chat.errors.append(
_('Start time cannot be later than end time.')
)
result = False
return result
[docs]
def json_to_time(self, text: str | None = None) -> list[list[str]]:
if not text:
return []
return [
[
value.get('day', ''),
value.get('start', ''),
value.get('end', '')
]
for value in json.loads(text).get('values', [])
]
[docs]
def time_to_json(
self,
opening_hours: list[list[str]] | None = None
) -> str:
opening_hours = opening_hours or []
return json.dumps({
'labels': {
'day': self.request.translate(_('day')),
'start': self.request.translate(_('Start')),
'end': self.request.translate(_('End')),
'add': self.request.translate(_('Add')),
'remove': self.request.translate(_('Remove')),
},
'values': [
{
'day': o[0],
'start': o[1],
'end': o[2],
'error': self.time_errors.get(ix, '')
} for ix, o in enumerate(opening_hours)
],
'days': {
0: self.request.translate(_('Mo')),
1: self.request.translate(_('Tu')),
2: self.request.translate(_('We')),
3: self.request.translate(_('Th')),
4: self.request.translate(_('Fr')),
5: self.request.translate(_('Sa')),
6: self.request.translate(_('Su'))
}
})