from __future__ import annotations
from collections import defaultdict
from onegov.core.security import Private
from onegov.form import CompleteFormSubmission
from onegov.form import FormDefinition
from onegov.form import FormRegistrationWindow
from onegov.form import FormSubmission
from onegov.org import OrgApp, _
from onegov.org.cli import close_ticket
from onegov.org.forms import FormRegistrationWindowForm
from onegov.org.forms.form_registration import FormRegistrationMessageForm
from onegov.org.layout import FormSubmissionLayout
from onegov.core.elements import Link, LinkGroup, Confirm, Intercooler, Block
from onegov.org.models import TicketNote
from onegov.org.views.form_submission import handle_submission_action
from onegov.org.mail import send_transactional_html_mail
from onegov.org.views.ticket import accept_ticket, send_email_if_enabled
from onegov.ticket import TicketCollection, Ticket
from typing import Any, Literal, TYPE_CHECKING
if TYPE_CHECKING:
from email.headerregistry import Address
from onegov.core.types import RenderData, SequenceOrScalar
from onegov.org.request import OrgRequest
from webob import Response
@OrgApp.form(
model=FormDefinition,
name='new-registration-window',
permission=Private,
form=FormRegistrationWindowForm,
template='form.pt'
)
[docs]
def ticket_linkable(
request: OrgRequest,
ticket: Ticket | None
) -> Ticket | None:
if ticket is None:
return None
if not request.link(ticket):
return None
return ticket
@OrgApp.form(
model=FormRegistrationWindow,
permission=Private,
name='send-message',
template='form.pt',
form=FormRegistrationMessageForm
)
@OrgApp.html(
model=FormRegistrationWindow,
permission=Private,
template='registration_window.pt'
)
[docs]
def view_registration_window(
self: FormRegistrationWindow,
request: OrgRequest,
layout: FormSubmissionLayout | None = None
) -> RenderData:
layout = layout or FormSubmissionLayout(self.form, request)
title = layout.format_date_range(self.start, self.end)
layout.breadcrumbs.append(Link(title, '#'))
registrations = defaultdict(list)
q = request.session.query(FormSubmission)
q = q.filter_by(registration_window_id=self.id)
q = q.filter_by(state='complete')
# ogc-1345 order after family name first
q = q.order_by(
FormSubmission.data['nachname'],
FormSubmission.data['name'],
FormSubmission.data['vorname'],
)
has_pending_or_confirmed = False
for submission in q:
if not submission.registration_state:
continue
registrations[submission.registration_state].append(submission)
if submission.registration_state != 'cancelled':
has_pending_or_confirmed = True
editbar_links: list[Link | LinkGroup] = [
Link(
text=_('Edit'),
url=request.link(self, 'edit'),
attrs={'class': 'edit-link'}
)
]
if registrations:
editbar_links.append(
Link(
text=_('Email attendees'),
url=request.link(self, name='send-message'),
attrs={'class': 'manage-recipients'}
)
)
editbar_links.append(
Link(
text=_('Cancel Registration Window'),
url=layout.csrf_protected_url(
request.link(self, name='cancel')),
attrs={'class': 'cancel'},
traits=(
Confirm(
_('You really want to cancel all confirmed and '
'deny all open submissions for this '
'registration window?'),
_('Each attendee will receive a ticket email '
'unless ticket messages are not muted.'),
_('Cancel Registration Window'),
_('Cancel'),
),
Intercooler(
request_method='POST',
redirect_after=request.link(self)
)
)
),
)
editbar_links.append(
Link(
text=_('Delete'),
url=layout.csrf_protected_url(request.link(self)),
attrs={'class': 'delete-link'},
traits=(
Confirm(
_(
'Do you really want to delete '
'this registration window?'
),
_('Existing submissions will be disassociated.'),
_('Delete registration window'),
_('Cancel')
),
Intercooler(
request_method='DELETE',
redirect_after=request.link(self.form)
)
) if not has_pending_or_confirmed else (
Block(
_("This registration window can't be deleted."),
_('There are confirmed or open submissions associated '
'with it. Cancel the registration window first.'),
_('Cancel')
)
)
)
)
layout.editbar_links = editbar_links
tickets = TicketCollection(request.session)
def ticket_link(subm: FormSubmission) -> str | None:
ticket = tickets.by_handler_id(subm.id.hex)
return ticket and request.link(ticket) or None
return {
'layout': layout,
'title': title,
'model': self,
'registrations': registrations,
'groups': (
(_('Open'), 'open'),
(_('Confirmed'), 'confirmed'),
(_('Cancelled'), 'cancelled'),
),
'ticket_link': ticket_link
}
@OrgApp.form(
model=FormRegistrationWindow,
permission=Private,
form=FormRegistrationWindowForm,
template='form.pt',
name='edit'
)
@OrgApp.view(
model=FormRegistrationWindow,
permission=Private,
name='cancel',
request_method='POST'
)
[docs]
def view_cancel_submissions_for_registration_window(
self: FormRegistrationWindow,
request: OrgRequest
) -> None:
""" Cancels a bunch of submissions either open ones or already accepted
ones. If there is a corresponding ticket, it is accepted before denying
the submission. """
request.assert_valid_csrf_token()
count = 0
action: Literal['cancelled', 'denied']
for submission in self.submissions:
if submission.registration_state == 'confirmed':
action = 'cancelled'
elif submission.registration_state == 'open':
action = 'denied'
else:
continue
ticket = TicketCollection(request.session).by_handler_id(
submission.id.hex)
if ticket and ticket.state == 'open':
accept_ticket(ticket, request)
if ticket:
# if there is a ticket then the submission is complete
assert isinstance(submission, CompleteFormSubmission)
handle_submission_action(
submission, request, action, ignore_csrf=True, raises=True,
no_messages=True, force_email=ticket.muted
)
assert request.current_user is not None
close_ticket(ticket, request.current_user, request)
# same behaviour as when closing ticket normally
# to disable mail on ticket close, there is a ticket-setting
send_email_if_enabled(
ticket=ticket,
request=request,
template='mail_ticket_closed.pt',
subject=_('Your request has been closed.')
)
count += 1
if count:
request.success(
_('${count} submissions cancelled / denied over the ticket system',
mapping={'count': count}))
@OrgApp.view(
model=FormRegistrationWindow,
permission=Private,
request_method='DELETE'
)
[docs]
def delete_registration_window(
self: FormRegistrationWindow,
request: OrgRequest
) -> None:
request.assert_valid_csrf_token()
self.disassociate()
request.session.delete(self)
request.success(_('The registration window was deleted'))