Source code for gazette.forms.notice
from datetime import date
from datetime import datetime
from markupsafe import Markup
from onegov.form import Form
from onegov.form.fields import ChosenSelectField
from onegov.form.fields import PhoneNumberField
from onegov.gazette import _
from onegov.gazette.fields import MultiCheckboxField
from onegov.gazette.layout import Layout
from onegov.gazette.models import Category
from onegov.gazette.models import Issue
from onegov.gazette.models import Organization
from onegov.quill.fields import QuillField
from onegov.quill.validators import HtmlDataRequired
from sedate import as_datetime
from sedate import standardize_date
from sedate import utcnow
from wtforms.fields import BooleanField
from wtforms.fields import DateField
from wtforms.fields import RadioField
from wtforms.fields import StringField
from wtforms.fields import TextAreaField
from wtforms.validators import DataRequired
from wtforms.validators import InputRequired
from wtforms.validators import Length
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from onegov.gazette.models import GazetteNotice
from onegov.gazette.request import GazetteRequest
[docs]
class NoticeForm(Form):
""" Edit an official notice.
The issues are limited according to the deadline (or the issue date in the
for publishers) and the categories and organizations are limited to the
active one.
"""
[docs]
title = StringField(
label=_('Title (maximum 60 characters)'),
validators=[
InputRequired(),
DataRequired(),
Length(max=60)
],
render_kw={'maxlength': 60},
)
[docs]
organization = ChosenSelectField(
label=_('Organization'),
choices=[],
validators=[
InputRequired()
]
)
[docs]
category = ChosenSelectField(
label=_('Category'),
choices=[],
validators=[
InputRequired()
]
)
[docs]
at_cost = RadioField(
label=_('Liable to pay costs'),
default='no',
choices=[
('no', _('No')),
('yes', _('Yes'))
]
)
[docs]
billing_address = TextAreaField(
label=_('Billing address'),
render_kw={'rows': 3},
depends_on=('at_cost', 'yes'),
validators=[
InputRequired(),
DataRequired(),
]
)
[docs]
issues = MultiCheckboxField(
label=_('Issue(s)'),
choices=[],
validators=[
InputRequired()
]
)
[docs]
text = QuillField(
label=_('Text'),
tags=('strong', 'ol', 'ul'),
validators=[
InputRequired(),
HtmlDataRequired(),
]
)
[docs]
author_place = StringField(
label=_('Place'),
validators=[
InputRequired(),
DataRequired(),
]
)
[docs]
author_date = DateField(
label=_('Date (usually the date of the issue)'),
validators=[
InputRequired()
]
)
[docs]
phone_number = PhoneNumberField(
label=_('Phone number for enquiry'),
description='+41791112233',
)
[docs]
author_name = TextAreaField(
label=_('Author'),
validators=[
InputRequired(),
DataRequired(),
],
render_kw={'rows': 4},
)
@property
[docs]
def author_date_utc(self) -> datetime | None:
if self.author_date.data:
return standardize_date(as_datetime(self.author_date.data), 'UTC')
return None
[docs]
def on_request(self) -> None:
session = self.request.session
# populate organization (active root elements with no children or
# active children (but not their parents))
self.organization.choices = []
self.organization.choices.append(
('', self.request.translate(_('Select one')))
)
query = session.query(Organization)
query = query.filter(Organization.active.is_(True))
query = query.filter(Organization.parent_id.is_(None))
query = query.order_by(Organization.order)
for root in query:
if root.children:
for child in root.children:
if child.active:
self.organization.choices.append(
(child.name, child.title)
)
else:
self.organization.choices.append((root.name, root.title))
# populate categories
category_query = session.query(Category.name, Category.title)
category_query = category_query.filter(Category.active.is_(True))
category_query = category_query.order_by(Category.order)
self.category.choices = category_query.all()
# populate issues
now = utcnow()
layout = Layout(None, self.request)
self.issues.choices = []
issues_q = session.query(Issue)
issues_q = issues_q.order_by(Issue.date)
if self.request.is_private(self.model):
issues_q = issues_q.filter(date.today() < Issue.date) # publisher
else:
issues_q = issues_q.filter(now < Issue.deadline) # editor
for issue in issues_q:
self.issues.choices.append((
issue.name,
layout.format_issue(issue, date_format='date_with_weekday')
))
if issue.deadline is not None and now >= issue.deadline:
self.issues.render_kw['data-hot-issue'] = issue.name
# Remove the print only option if not publisher
if not self.request.is_private(self.model):
self.delete_field('print_only')
[docs]
def update_model(self, model: 'GazetteNotice') -> None:
assert self.title.data is not None
model.title = self.title.data
model.organization_id = self.organization.data
model.category_id = self.category.data
model.text = self.text.data
model.author_place = self.author_place.data
model.author_date = self.author_date_utc
model.author_name = self.author_name.data
model.at_cost = self.at_cost.data == 'yes'
model.billing_address = self.billing_address.data
# FIXME: asymmetric property
model.issues = self.issues.data # type:ignore[assignment]
if self.print_only:
model.print_only = self.print_only.data
if self.phone_number.data and model.user:
model.user.phone_number = self.phone_number.formatted_data
model.apply_meta(self.request.session)
[docs]
def apply_model(self, model: 'GazetteNotice') -> None:
self.title.data = model.title
self.organization.data = model.organization_id
self.category.data = model.category_id
self.text.data = model.text or Markup('')
self.author_place.data = model.author_place
self.author_date.data = model.author_date
self.author_name.data = model.author_name
self.at_cost.data = 'yes' if model.at_cost else 'no'
self.billing_address.data = model.billing_address or ''
self.issues.data = list(model.issues.keys())
if model.user:
self.phone_number.data = model.user.phone_number
if self.print_only:
self.print_only.data = True if model.print_only else False
[docs]
class UnrestrictedNoticeForm(NoticeForm):
""" Edit an official notice without limitations on the issues, categories
and organiaztions.
Optionally disables the issues (e.g. if the notice is already published).
"""
[docs]
def on_request(self) -> None:
session = self.request.session
layout = Layout(None, self.request)
def title(item: Organization | Category) -> str:
return item.title if item.active else f'({item.title})'
# populate organization (root elements with no children or children
# (but not their parents))
self.organization.choices = []
self.organization.choices.append(
('', self.request.translate(_('Select one')))
)
query = session.query(Organization)
query = query.filter(Organization.parent_id.is_(None))
query = query.order_by(Organization.order)
for root in query:
if root.children:
for child in root.children:
self.organization.choices.append(
(child.name, title(child))
)
else:
self.organization.choices.append((root.name, title(root)))
# populate categories
self.category.choices = []
categories_query = session.query(Category)
categories_query = categories_query.order_by(Category.order)
for category in categories_query:
self.category.choices.append((category.name, title(category)))
# populate issues
del self.issues.render_kw['data-limit']
self.issues.choices = []
issues_query = session.query(Issue)
issues_query = issues_query.order_by(Issue.date)
for issue in issues_query:
self.issues.choices.append((
issue.name,
layout.format_issue(issue, date_format='date_with_weekday')
))
[docs]
def disable_issues(self) -> None:
self.issues.validators = []
self.issues.render_kw['disabled'] = True
[docs]
def update_model(self, model: 'GazetteNotice') -> None:
assert self.title.data is not None
model.title = self.title.data
model.organization_id = self.organization.data
model.category_id = self.category.data
model.text = self.text.data
model.author_place = self.author_place.data
model.author_date = self.author_date_utc
model.author_name = self.author_name.data
model.at_cost = self.at_cost.data == 'yes'
model.billing_address = self.billing_address.data
model.note = self.note.data
model.print_only = self.print_only.data
if model.state != 'published':
model.issues = self.issues.data # type:ignore[assignment]
if self.phone_number.data and model.user:
model.user.phone_number = self.phone_number.formatted_data
model.apply_meta(self.request.session)
[docs]
def apply_model(self, model: 'GazetteNotice') -> None:
super().apply_model(model)
self.note.data = model.note