Source code for feriennet.layout

from __future__ import annotations

from functools import cached_property

from onegov.activity import Activity, BookingPeriodCollection, Occasion
from onegov.activity import BookingCollection
from onegov.core.elements import Link, Confirm, Intercooler, Block
from onegov.core.elements import LinkGroup
from onegov.core.utils import linkify, paragraphify
from onegov.feriennet import _
from onegov.feriennet import security
from onegov.feriennet.collections import BillingCollection
from onegov.feriennet.collections import NotificationTemplateCollection
from onegov.feriennet.collections import OccasionAttendeeCollection
from onegov.feriennet.collections import VacationActivityCollection
from onegov.feriennet.const import OWNER_EDITABLE_STATES
from onegov.feriennet.models import InvoiceAction, VacationActivity
from onegov.town6.layout import DefaultLayout as BaseLayout
from onegov.town6.layout import UserLayout as TownUserLayout
from onegov.pay import PaymentProviderCollection
from onegov.ticket import TicketCollection


from typing import Any, NamedTuple, TYPE_CHECKING

from onegov.user.collections.user import UserCollection

if TYPE_CHECKING:
    from collections.abc import Iterator, Sequence
    from markupsafe import Markup
    from onegov.activity.models import (
        Attendee, Booking, BookingPeriod, PublicationRequest)
    from onegov.activity.collections import (
        BookingPeriodInvoiceCollection, VolunteerCollection)
    from onegov.core.elements import Trait
    from onegov.feriennet.app import FeriennetApp
    from onegov.feriennet.models import NotificationTemplate
    from onegov.feriennet.request import FeriennetRequest
    from onegov.org.models import Organisation
    from onegov.ticket import Ticket
    from onegov.user import User


[docs] class DefaultLayout(BaseLayout):
[docs] app: FeriennetApp
[docs] request: FeriennetRequest
@property
[docs] def is_owner(self) -> bool: if not self.request.current_username: return False return security.is_owner(self.request.current_username, self.model)
@property
[docs] def is_editable(self) -> bool: if self.request.is_admin: return True if not self.request.is_organiser: return False if isinstance(self.model, Activity): return self.model.state in OWNER_EDITABLE_STATES if isinstance(self.model, Occasion): return self.model.activity.state in OWNER_EDITABLE_STATES return True
[docs] def linkify(self, text: str | None) -> Markup: # type:ignore[override] return linkify(text)
[docs] def paragraphify(self, text: str) -> Markup: return paragraphify(text)
[docs] class VacationActivityCollectionLayout(DefaultLayout):
[docs] model: VacationActivityCollection
if TYPE_CHECKING: def __init__( self, model: VacationActivityCollection, request: FeriennetRequest ) -> None: ... @cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link(_('Activities'), self.request.class_link( VacationActivityCollection)), ]
@property @property @cached_property
[docs] class BookingCollectionLayout(DefaultLayout):
[docs] model: BookingCollection
def __init__( self, model: BookingCollection, request: FeriennetRequest, user: User | None = None ) -> None: super().__init__(model, request) if user is None: user = request.current_user assert user is not None
[docs] self.user = user
@cached_property
[docs] def title(self) -> str: wishlist_phase = (self.app.active_period and self.app.active_period.wishlist_phase) if self.user.username == self.request.current_username: return wishlist_phase and _('Wishlist') or _('Bookings') elif wishlist_phase: return _('Wishlist of ${user}', mapping={ 'user': self.user.title }) else: return _('Bookings of ${user}', mapping={ 'user': self.user.title })
@cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link(self.title, self.request.link(self.model)) ]
[docs] class GroupInviteLayout(DefaultLayout): @cached_property
[docs] def breadcrumbs(self) -> list[Link]: wishlist_phase = (self.app.active_period and self.app.active_period.wishlist_phase) if self.request.is_logged_in: return [ Link(_('Homepage'), self.homepage_url), Link( wishlist_phase and _('Wishlist') or _('Bookings'), self.request.class_link(BookingCollection) ), Link(_('Group'), '#') ] else: return [ Link(_('Homepage'), self.homepage_url), Link(_('Group'), '#') ]
[docs] class VacationActivityFormLayout(DefaultLayout):
[docs] model: VacationActivity | VacationActivityCollection
def __init__( self, model: VacationActivity | VacationActivityCollection, request: FeriennetRequest, title: str ) -> None: super().__init__(model, request) self.include_editor()
[docs] self.title = title
@cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), # FIXME: This breadcrumb seems wrong for VacationActivity Link(_('Activities'), self.request.link(self.model)), Link(self.title, '#') ]
@cached_property
[docs] class OccasionFormLayout(DefaultLayout):
[docs] model: Activity
def __init__( self, model: Activity, request: FeriennetRequest, title: str ) -> None: assert isinstance(model, Activity) super().__init__(model, request)
[docs] self.title = title
@cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link(_('Activities'), self.request.class_link( VacationActivityCollection)), Link(self.model.title, self.request.link(self.model)), Link(self.title, '#') ]
[docs] class VacationActivityLayout(DefaultLayout):
[docs] model: VacationActivity
if TYPE_CHECKING: def __init__( self, model: VacationActivity, request: FeriennetRequest ) -> None: ... @cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link(_('Activities'), self.request.class_link( VacationActivityCollection)), Link(self.model.title, self.request.link(self.model)) ]
@cached_property
[docs] def latest_request(self) -> PublicationRequest | None: return self.model.latest_request
@cached_property
[docs] def ticket(self) -> Ticket | None: if self.latest_request: tickets = TicketCollection(self.request.session) return tickets.by_handler_id(self.latest_request.id.hex) return None
@cached_property
[docs] def attendees(self) -> OccasionAttendeeCollection | None: if self.request.app.default_period: return OccasionAttendeeCollection( self.request.session, self.request.app.default_period, self.model ) return None
@cached_property
[docs] class PeriodCollectionLayout(DefaultLayout): @cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link( _('Activities'), self.request.class_link(VacationActivityCollection) ), Link(_('Manage Periods'), '#') ]
@cached_property
[docs] class PeriodFormLayout(DefaultLayout):
[docs] model: BookingPeriod | BookingPeriodCollection
def __init__( self, model: BookingPeriod | BookingPeriodCollection, request: FeriennetRequest, title: str ) -> None: super().__init__(model, request)
[docs] self.title = title
@cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link( _('Activities'), self.request.class_link(VacationActivityCollection) ), Link( _('Manage Periods'), self.request.class_link(BookingPeriodCollection) ), Link(self.title, '#') ]
@cached_property
[docs] class MatchCollectionLayout(DefaultLayout): @cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link( _('Activities'), self.request.class_link(VacationActivityCollection) ), Link(_('Matches'), '#') ]
[docs] class BillingCollectionLayout(DefaultLayout):
[docs] model: BillingCollection
if TYPE_CHECKING: def __init__( self, model: BillingCollection, request: FeriennetRequest ) -> None: ...
[docs] class FamilyRow(NamedTuple):
[docs] text: str
[docs] item: str
[docs] count: int # type:ignore[assignment]
[docs] has_online_payments: bool
@property
[docs] def families(self) -> Iterator[FamilyRow]: yield from self.app.session().execute(""" SELECT text || ' (' || replace(avg(unit * quantity)::money::text, '$', '') || ' CHF)' AS text , MIN(id::text) AS item, COUNT(*) AS count, family IN ( SELECT DISTINCT(family) FROM invoice_items WHERE source IS NOT NULL and source != 'xml' ) AS has_online_payments FROM invoice_items WHERE family IS NOT NULL GROUP BY family, text ORDER BY text """)
@property @cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link( _('Activities'), self.request.class_link(VacationActivityCollection) ), Link(_('Billing'), '#') ]
@cached_property
[docs] class OnlinePaymentsLayout(DefaultLayout): def __init__( self, model: Any, request: FeriennetRequest, title: str ) -> None:
[docs] self.title = title
super().__init__(model, request) @cached_property @cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link( _('Activities'), self.request.class_link(VacationActivityCollection) ), Link( _('Billing'), self.request.class_link(BillingCollection) ), Link(self.title, '#') ]
[docs] class BillingCollectionImportLayout(DefaultLayout): @cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link( _('Activities'), self.request.class_link(VacationActivityCollection) ), Link(_('Billing'), self.request.link(self.model)), Link(_('Import Bank Statement'), '#') ]
[docs] class BillingCollectionManualBookingLayout(DefaultLayout): @cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link( _('Activities'), self.request.class_link(VacationActivityCollection) ), Link(_('Billing'), self.request.link(self.model)), Link(_('Manual Booking'), '#') ]
[docs] class BillingCollectionPaymentWithDateLayout(DefaultLayout): @cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link( _('Activities'), self.request.class_link(VacationActivityCollection) ), Link(_('Billing'), self.request.link(self.model)), Link(_('Payment with date'), '#') ]
[docs] class InvoiceLayout(DefaultLayout): def __init__( self, model: Any, request: FeriennetRequest, title: str ) -> None: super().__init__(model, request)
[docs] self.title = title
@cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link(self.title, '#') ]
[docs] class DonationLayout(DefaultLayout): def __init__( self, model: BookingPeriodInvoiceCollection, request: FeriennetRequest, title: str ) -> None: super().__init__(model, request)
[docs] self.title = title
@cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link(_('Invoices'), self.request.link(self.model)), Link(_('Donation'), self.title) ]
[docs] class OccasionAttendeeLayout(DefaultLayout): @cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link( _('Activities'), self.request.class_link(VacationActivityCollection) ), Link( self.model.activity.title, self.request.link(self.model.activity) ), Link(_('Attendees'), '#') ]
[docs] class NotificationTemplateCollectionLayout(DefaultLayout):
[docs] model: NotificationTemplateCollection
def __init__( self, model: NotificationTemplateCollection, request: FeriennetRequest, subtitle: str | None = None ) -> None: super().__init__(model, request)
[docs] self.subtitle = subtitle
self.include_editor() @cached_property
[docs] def breadcrumbs(self) -> list[Link]: links = [ Link(_('Homepage'), self.homepage_url), Link( _('Activities'), self.request.class_link(VacationActivityCollection) ), Link( _('Notification Templates'), self.request.class_link(NotificationTemplateCollection) ) ] if self.subtitle: links.append(Link(self.subtitle, '#')) return links
@cached_property
[docs] class NotificationTemplateLayout(DefaultLayout):
[docs] model: NotificationTemplate
def __init__( self, model: NotificationTemplate, request: FeriennetRequest, subtitle: str | None = None ) -> None: super().__init__(model, request)
[docs] self.subtitle = subtitle
self.include_editor() @cached_property
[docs] def breadcrumbs(self) -> list[Link]: links = [ Link(_('Homepage'), self.homepage_url), Link( _('Activities'), self.request.class_link(VacationActivityCollection) ), Link( _('Notification Templates'), self.request.class_link(NotificationTemplateCollection) ), Link( self.model.subject, self.request.link(self.model) ) ] if self.subtitle: links.append(Link(self.subtitle, '#')) return links
[docs] class VolunteerLayout(DefaultLayout):
[docs] model: VolunteerCollection
if TYPE_CHECKING: def __init__( self, model: VolunteerCollection, request: FeriennetRequest ) -> None: ... @cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link(_('Volunteers'), self.request.link(self.model)) ]
[docs] class VolunteerFormLayout(DefaultLayout): @cached_property
[docs] def breadcrumbs(self) -> list[Link]: return [ Link(_('Homepage'), self.homepage_url), Link( _('Join as a Volunteer'), self.request.class_link( VacationActivityCollection, name='volunteer' ) ), Link( _('Register as Volunteer'), '#' ) ]
[docs] class HomepageLayout(DefaultLayout):
[docs] model: Organisation
if TYPE_CHECKING: def __init__( self, model: Organisation, request: FeriennetRequest ) -> None: ... @property
[docs] class UserLayout(TownUserLayout):
[docs] model: User
if TYPE_CHECKING: def __init__( self, model: User, request: FeriennetRequest ) -> None: ... @cached_property