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'))