Source code for org.views.settings

""" The settings view, defining things like the logo or color of the org. """

from copy import copy
from dectate import Query
from markupsafe import Markup
from webob.exc import HTTPForbidden
from onegov.core.elements import Link, Confirm, Intercooler, BackLink
from onegov.core.security import Secret
from onegov.core.templates import render_macro
from onegov.form import Form
from onegov.org import _
from onegov.org.forms import AnalyticsSettingsForm
from onegov.org.forms import FooterSettingsForm
from onegov.org.forms import GeneralSettingsForm
from onegov.org.forms import HolidaySettingsForm
from onegov.org.forms import HomepageSettingsForm
from onegov.org.forms import MapSettingsForm
from onegov.org.forms import ModuleSettingsForm
from onegov.org.forms.settings import (
    OrgTicketSettingsForm, HeaderSettingsForm, FaviconSettingsForm,
    LinksSettingsForm, NewsletterSettingsForm, LinkMigrationForm,
    LinkHealthCheckForm, SocialMediaSettingsForm, EventSettingsForm,
    GeverSettingsForm, OneGovApiSettingsForm, DataRetentionPolicyForm)
from onegov.org.management import LinkHealthCheck
from onegov.org.layout import DefaultLayout
from onegov.org.layout import SettingsLayout
from onegov.org.management import LinkMigration
from onegov.org.models import Organisation
from onegov.org.models import SwissHolidays
from onegov.api.models import ApiKey
from onegov.org.app import OrgApp
from uuid import uuid4


from typing import Any, TYPE_CHECKING
if TYPE_CHECKING:
    from collections.abc import Iterator
    from onegov.core.types import RenderData
    from onegov.org.request import OrgRequest
    from typing import type_check_only
    from webob import Response

    @type_check_only




@OrgApp.html(
    model=Organisation,
    name='settings',
    template='settings.pt',
    permission=Secret
)
[docs] def view_settings( self: Organisation, request: 'OrgRequest', layout: SettingsLayout | None = None ) -> 'RenderData': layout = layout or SettingsLayout(self, request) def query_settings() -> 'Iterator[dict[str, Any]]': q = Query('view').filter(model=Organisation) for action, fn in q(request.app): if 'setting' in action.predicates: setting = copy(action.predicates) setting['title'] = setting['setting'] setting['link'] = request.link(self, name=setting['name']) yield setting settings = list(query_settings()) settings.sort(key=lambda s: s.get('order', 0)) return { 'layout': layout, 'title': _('Settings'), 'settings': settings }
[docs] def handle_generic_settings( self: Organisation, request: 'OrgRequest', form: Form, title: str, layout: SettingsLayout | None = None ) -> 'RenderData | Response': layout = layout or SettingsLayout(self, request, title) layout.edit_mode = True layout.editmode_links[1] = BackLink(attrs={'class': 'cancel-link'}) request.include('fontpreview') if form.submitted(request): form.populate_obj(self) request.success(_('Your changes were saved')) return request.redirect(request.link(self, name='settings')) elif request.method == 'GET': form.process(obj=self) return { 'layout': layout, 'title': title, 'form': form }
@OrgApp.form( model=Organisation, name='general-settings', template='form.pt', permission=Secret, form=GeneralSettingsForm, setting=_('General'), icon='fa-sliders', order=-1000)
[docs] def handle_general_settings( self: Organisation, request: 'OrgRequest', form: GeneralSettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData | Response': return handle_generic_settings(self, request, form, _('General'), layout)
@OrgApp.form( model=Organisation, name='homepage-settings', template='form.pt', permission=Secret, form=HomepageSettingsForm, setting=_('Homepage'), icon='fa-home', order=-995)
[docs] def handle_homepage_settings( self: Organisation, request: 'OrgRequest', form: HomepageSettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData | Response': return handle_generic_settings(self, request, form, _('Homepage'), layout)
@OrgApp.form( model=Organisation, name='favicon-settings', template='form.pt', permission=Secret, form=FaviconSettingsForm, setting=_('Favicon'), icon=' fa-external-link-square', order=-990)
[docs] def handle_favicon_settings( self: Organisation, request: 'OrgRequest', form: FaviconSettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData | Response': return handle_generic_settings(self, request, form, _('Favicon'), layout)
@OrgApp.form( model=Organisation, name='social-media-settings', template='form.pt', permission=Secret, form=SocialMediaSettingsForm, setting=_('Social Media'), icon=' fa fa-share-alt', order=-985)
[docs] def handle_social_media_settings( self: Organisation, request: 'OrgRequest', form: SocialMediaSettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData | Response': return handle_generic_settings( self, request, form, _('Social Media'), layout)
@OrgApp.form( model=Organisation, name='link-settings', template='form.pt', permission=Secret, form=LinksSettingsForm, setting=_('Links'), icon=' fa-link', order=-980) @OrgApp.form( model=Organisation, name='newsletter-settings', template='form.pt', permission=Secret, form=NewsletterSettingsForm, setting=_('Newsletter'), order=-951, icon='far fa-paper-plane' )
[docs] def handle_newsletter_settings( self: Organisation, request: 'OrgRequest', form: NewsletterSettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData | Response': return handle_generic_settings( self, request, form, _('Newsletter'), layout )
@OrgApp.form( model=Organisation, name='ticket-settings', template='form.pt', permission=Secret, form=OrgTicketSettingsForm, setting=_('Tickets'), order=-950, icon='fa-ticket' )
[docs] def handle_ticket_settings( self: Organisation, request: 'OrgRequest', form: OrgTicketSettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData | Response': resp = handle_generic_settings( self, request, form, _('Tickets'), layout) return resp
@OrgApp.form( model=Organisation, name='header-settings', template='form.pt', permission=Secret, form=HeaderSettingsForm, setting=_('Header'), icon='fa-window-maximize', order=-810)
[docs] def handle_header_settings( self: Organisation, request: 'OrgRequest', form: Form, layout: SettingsLayout | None = None ) -> 'RenderData | Response': layout = layout or SettingsLayout(self, request, _('Header')) return handle_generic_settings(self, request, form, _('Header'), layout)
@OrgApp.form( model=Organisation, name='footer-settings', template='form.pt', permission=Secret, form=FooterSettingsForm, setting=_('Footer'), icon='fa-window-minimize', order=-800) @OrgApp.form( model=Organisation, name='module-settings', template='form.pt', permission=Secret, form=ModuleSettingsForm, setting=_('Modules'), icon='fa-sitemap', order=-700)
[docs] def handle_module_settings( self: Organisation, request: 'OrgRequest', form: ModuleSettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData | Response': return handle_generic_settings( self, request, form, _('Modules'), layout)
@OrgApp.form( model=Organisation, name='map-settings', template='form.pt', permission=Secret, form=MapSettingsForm, setting=_('Map'), icon='fa-map-marker', order=-700)
[docs] def handle_map_settings( self: Organisation, request: 'OrgRequest', form: MapSettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData | Response': return handle_generic_settings(self, request, form, _('Map'), layout)
@OrgApp.form( model=Organisation, name='analytics-settings', template='form.pt', permission=Secret, form=AnalyticsSettingsForm, setting=_('Analytics'), icon='fa-line-chart ', order=-600)
[docs] def handle_analytics_settings( self: Organisation, request: 'OrgRequest', form: AnalyticsSettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData | Response': return handle_generic_settings(self, request, form, _('Analytics'), layout)
@OrgApp.form( model=Organisation, name='gever-credentials', template='form.pt', permission=Secret, form=GeverSettingsForm, setting='Gever API', icon='fa-key', order=400)
[docs] def handle_gever_settings( self: Organisation, request: 'OrgRequest', form: GeverSettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData | Response': return handle_generic_settings(self, request, form, 'Gever API', layout)
@OrgApp.form( model=Organisation, name='holiday-settings', template='form.pt', permission=Secret, form=HolidaySettingsForm, setting=_('Holidays'), icon='fa-calendar-o', order=-500)
[docs] def handle_holiday_settings( self: Organisation, request: 'OrgRequest', form: HolidaySettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData | Response': return handle_generic_settings(self, request, form, _('Holidays'), layout)
@OrgApp.form(model=Organisation, name='holiday-settings-preview', permission=Secret, form=HolidaySettingsForm)
[docs] def preview_holiday_settings( self: Organisation, request: 'OrgRequest', form: HolidaySettingsForm, layout: DefaultLayout | None = None ) -> str: layout = layout or DefaultLayout(self, request) if form.submitted(request): holidays = SwissHolidays( cantons=form.holiday_settings.get('cantons', ()), other=form.holiday_settings.get('other', ()) ) else: holidays = SwissHolidays( cantons=form.holiday_settings.get('cantons', ()) ) if not holidays.all(layout.today().year): msg = request.translate(_('No holidays defined')) return f'<i class="holidays">{msg}</i>' return render_macro( layout.macros['holidays'], request, { 'holidays': holidays, 'layout': layout, 'year': layout.today().year, } )
@OrgApp.form( model=Organisation, name='migrate-links', template='form.pt', permission=Secret, form=LinkMigrationForm, setting=_('Link Migration'), icon='fa fa-random', order=-400) @OrgApp.form( model=Organisation, name='link-check', template='linkcheck.pt', permission=Secret, form=LinkHealthCheckForm) @OrgApp.form( model=Organisation, name='event-settings', template='form.pt', permission=Secret, form=EventSettingsForm, setting=_('Events'), icon='fa-calendar', order=-700)
[docs] def handle_event_settings( self: Organisation, request: 'OrgRequest', form: EventSettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData | Response': return handle_generic_settings(self, request, form, _('Events'), layout)
@OrgApp.form( model=Organisation, name='api-keys', template='api_keys.pt', permission=Secret, form=OneGovApiSettingsForm, setting=_('OneGov API'), icon='fa-key', order=1)
[docs] def handle_api_keys( self: Organisation, request: 'OrgRequest', form: OneGovApiSettingsForm, layout: SettingsLayout | None = None ) -> 'RenderData': """Handles the generation of API access keys.""" request.include('fontpreview') title = _('OneGov API') user = request.current_user if not user: raise HTTPForbidden() if form.submitted(request): assert form.name.data is not None key = ApiKey( name=form.name.data, read_only=form.read_only.data, last_used=None, key=uuid4(), user=user, ) request.session.add(key) request.session.flush() request.success(_('Your changes were saved')) layout = layout or SettingsLayout(self, request, title) def current_api_keys_by_user() -> 'Iterator[ApiKeyWithDeleteLink]': for api_key in user.api_keys: api_key_delete_link = Link( text=Markup('<i class="fa fa-trash" aria-hidden="True"></i>'), url=layout.csrf_protected_url( request.link(api_key, name='+delete')), traits=( Confirm( _('Do you really want to delete this API key?'), _('This action cannot be undone.'), _('Delete'), _('Cancel'), ), Intercooler( request_method='DELETE', redirect_after=request.link(self, name='api-keys'), ), ), ) # delete_link is temporarily stored on the object itself api_key.delete_link = api_key_delete_link yield api_key return { 'api_keys_list': list(current_api_keys_by_user()), 'title': title, 'form': form, 'layout': layout, }
@OrgApp.view( model=ApiKey, name='delete', permission=Secret, request_method='DELETE', )
[docs] def delete_api_key(self: ApiKey, request: 'OrgRequest') -> None: request.assert_valid_csrf_token() request.session.delete(self) request.session.flush() request.message(_('ApiKey deleted.'), 'success')
@OrgApp.form( model=Organisation, name='data-retention-settings', template='form.pt', permission=Secret, form=DataRetentionPolicyForm, setting=_('Data Retention Policy'), icon='far fa-trash', order=-880, )
[docs] def handle_ticket_data_deletion_settings( self: Organisation, request: 'OrgRequest', form: DataRetentionPolicyForm ) -> 'RenderData | Response': request.message(_('Proceed with caution. Tickets and the data they ' 'contain may be irrevocable deleted.'), 'alert') return handle_generic_settings( self, request, form, _('Data Retention Policy'), SettingsLayout(self, request), )
@OrgApp.form( model=Organisation, name='chat-settings', template='form.pt', permission=Secret, form=Form, setting=_('Chat'), icon='fa-window-maximize', order=-810)
[docs] def handle_chat_settings( self: Organisation, request: 'OrgRequest', form: Form, layout: SettingsLayout | None = None ) -> 'RenderData | Response': layout = layout or SettingsLayout(self, request, _('Chat')) return handle_generic_settings(self, request, form, _('Chat'), layout)