Beispiel #1
0
def reopen_ticket(self, request):
    user = UserCollection(request.app.session()).by_username(
        request.identity.userid)

    try:
        self.reopen_ticket(user)
    except InvalidStateChange:
        request.alert(
            _("The ticket cannot be re-opened because it's not closed.")
        )
    else:
        request.success(_("You have reopened ticket ${number}", mapping={
            'number': self.number
        }))

    email = self.snapshot.get('email') or self.handler.email

    send_html_mail(
        request=request,
        template='mail_ticket_reopened.pt',
        subject=_("Your ticket has been reopened"),
        receivers=(email, ),
        content={
            'model': self
        }
    )

    request.app.update_ticket_count()

    return morepath.redirect(request.link(self))
Beispiel #2
0
def view_tickets(self, request):

    def get_filters():
        states = (
            ('open', _("Open")),
            ('pending', _("Pending")),
            ('closed', _("Closed"))
        )

        for id, text in states:
            yield Link(
                text=text,
                url=request.link(self.for_state(id)),
                active=self.state == id
            )

    if self.state == 'open':
        tickets_title = _("Open Tickets")
    elif self.state == 'pending':
        tickets_title = _("Pending Tickets")
    elif self.state == 'closed':
        tickets_title = _("Closed Tickets")
    else:
        raise NotImplementedError

    return {
        'title': _("Tickets"),
        'layout': TicketsLayout(self, request),
        'tickets': self.batch,
        'filters': tuple(get_filters()),
        'tickets_title': tickets_title,
    }
Beispiel #3
0
    def bottom_links(self):

        request = self.request

        if request.current_role == 'editor':
            return [
                Link(_('Logout'), self.logout_url),
                Link(_('User Profile'), request.link(
                    self.town, 'benutzerprofil'
                )),
                Link(_('Files'), request.link(FileCollection(self.app))),
                Link(_('Images'), request.link(ImageCollection(self.app))),
                Link('OneGov Cloud', 'http://www.onegovcloud.ch'),
                Link('Seantis GmbH', 'https://www.seantis.ch')
            ]
        elif request.current_role == 'admin':
            return [
                Link(_('Logout'), self.logout_url),
                Link(_('User Profile'), request.link(
                    self.town, 'benutzerprofil'
                )),
                Link(_('Files'), request.link(FileCollection(self.app))),
                Link(_('Images'), request.link(ImageCollection(self.app))),
                Link(_('Settings'), request.link(self.town, 'einstellungen')),
                Link('OneGov Cloud', 'http://www.onegovcloud.ch'),
                Link('Seantis GmbH', 'https://www.seantis.ch')
            ]
        else:
            return [
                Link(_('Login'), self.login_url),
                Link('OneGov Cloud', 'http://www.onegovcloud.ch'),
                Link('Seantis GmbH', 'https://www.seantis.ch')
            ]
Beispiel #4
0
    def editbar_links(self):
        if self.request.is_logged_in:

            # only show the model related links when the ticket is pending
            if self.model.state == 'pending':
                links = self.model.handler.get_links(self.request)
            else:
                links = []

            if self.model.state == 'open':
                links.append(Link(
                    text=_("Accept ticket"),
                    url=self.request.link(self.model, 'accept'),
                    classes=('ticket-action', 'ticket-accept'),
                ))

            elif self.model.state == 'pending':
                links.append(Link(
                    text=_("Close ticket"),
                    url=self.request.link(self.model, 'close'),
                    classes=('ticket-action', 'ticket-close'),
                ))

            elif self.model.state == 'closed':
                links.append(Link(
                    text=_("Reopen ticket"),
                    url=self.request.link(self.model, 'reopen'),
                    classes=('ticket-action', 'ticket-reopen'),
                ))

            return links
Beispiel #5
0
def handle_login(self, request, form):
    """ Handles the login requests. """

    if form.submitted(request):
        response = self.login_to(request=request, **form.login_data)

        if response:
            request.success(_("You have been logged in."))
            return response

        request.alert(_("Wrong e-mail address, password or yubikey."))

    layout = DefaultLayout(self, request)
    layout.breadcrumbs = [
        Link(_("Homepage"), layout.homepage_url),
        Link(_("Login"), request.link(self, name='login'))
    ]

    return {
        'layout': layout,
        'password_reset_link': request.link(
            request.app.town, name='request-password'),
        'title': _('Login to ${town}', mapping={
            'town': request.app.town.name
        }),
        'form': form
    }
Beispiel #6
0
def close_ticket(self, request):

    try:
        self.close_ticket()
    except InvalidStateChange:
        request.alert(
            _("The ticket cannot be closed because it's not pending")
        )
    else:
        request.success(_("You have closed ticket ${number}", mapping={
            'number': self.number
        }))

    email = self.snapshot.get('email') or self.handler.email

    send_html_mail(
        request=request,
        template='mail_ticket_closed.pt',
        subject=_("Your ticket has been closed"),
        receivers=(email, ),
        content={
            'model': self
        }
    )

    request.app.update_ticket_count()

    return morepath.redirect(
        request.link(TicketCollection(request.app.session())))
Beispiel #7
0
def reject_reservation(self, request):
    collection = ResourceCollection(request.app.libres_context)
    resource = collection.by_id(self.resource)
    scheduler = resource.get_scheduler(request.app.libres_context)
    reservations = scheduler.reservations_by_token(self.token.hex)
    forms = FormCollection(request.app.session())
    submission = forms.submissions.by_id(self.token.hex)

    send_html_mail(
        request=request,
        template='mail_reservation_rejected.pt',
        subject=_("Your reservation was rejected"),
        receivers=(self.email, ),
        content={
            'model': self,
            'resource': resource,
            'reservations': reservations
        }
    )

    # create a snapshot of the ticket to keep the useful information
    tickets = TicketCollection(request.app.session())
    ticket = tickets.by_handler_id(self.token.hex)
    ticket.create_snapshot(request)

    scheduler.remove_reservation(self.token.hex)

    if submission:
        forms.submissions.delete(submission)

    request.success(_("The reservation was rejected"))

    # return none on intercooler js requests
    if not request.headers.get('X-IC-Request'):
        return morepath.redirect(request.params['return-to'])
Beispiel #8
0
    def validate(self):
        """ Make sure a valid RRULE can be generated with the given fields.

        Might be better to group weekly and end_date in an enclosure,
        see See http://wtforms.readthedocs.org/en/latest/fields.html
        #field-enclosures.

        """
        result = super().validate()

        if self.start_date.data and self.end_date.data:
            if self.start_date.data > self.end_date.data:
                message = _("The end date must be later than the start date.")
                self.end_date.errors.append(message)
                result = False

        if self.weekly.data and self.start_date.data:
            weekday = WEEKDAYS[self.start_date.data.weekday()][0]
            if weekday not in self.weekly.data:
                message = _("The weekday of the start date must be selected.")
                self.weekly.errors.append(message)
                result = False

        if self.weekly.data and not self.end_date.data:
            message = _("Please set and end date if the event is recurring.")
            self.end_date.errors.append(message)
            result = False

        if self.end_date.data and not self.weekly.data:
            message = _("Please select a weekday if the event is recurring.")
            self.weekly.errors.append(message)
            result = False

        return result
Beispiel #9
0
    def event_title(self):
        if self.allocation.partly_available:
            available = self.translate(_("${percent}% Available", mapping={
                'percent': int(self.availability)
            }))
        else:
            quota = self.allocation.quota
            quota_left = int(quota * self.availability / 100)

            if quota == 1:
                if quota_left:
                    available = self.translate(_("Available"))
                else:
                    available = self.translate(_("Unavailable"))
            else:
                available = self.translate(
                    _("${num}/${max} Available", mapping={
                        'num': quota_left,
                        'max': quota
                    })
                )

        # add an extra space at the end of the event time, so we can hide
        # the <br> tag on the output without having the time and the
        # availability seemingly joined together without space.
        return '\n'.join((self.event_time + ' ', available))
Beispiel #10
0
def confirm_reservation(self, request):

    # this view is public, but only for a limited time
    assert_anonymous_access_only_temporary(self, request)

    collection = ResourceCollection(request.app.libres_context)
    resource = collection.by_id(self.resource)

    forms = FormCollection(request.app.session())
    submission = forms.submissions.by_id(self.token)

    if submission:
        form = request.get_form(submission.form_class, data=submission.data)
    else:
        form = None

    layout = ReservationLayout(resource, request)
    layout.breadcrumbs.append(Link(_("Confirm"), '#'))

    return {
        'title': _("Confirm your reservation"),
        'layout': layout,
        'form': form,
        'resource': resource,
        'allocation': self._target_allocations().first(),
        'reservation': self,
        'finalize_link': request.link(self, 'abschluss'),
        'edit_link': request.link(self, 'bearbeiten')
    }
Beispiel #11
0
def handle_password_reset(self, request, form):
    request.include("common")
    request.include("check_password")

    if form.submitted(request):
        identity = form.get_identity(request)
        if identity is not None:
            response = morepath.redirect(request.link(self))
            morepath.remember_identity(response, request, identity)
            request.success(_("Password changed."))
            return response
        else:
            request.alert(_("Wrong username or password reset link not valid any more."))
            log.info("Failed password reset attempt by {}".format(request.client_addr))

    if "token" in request.params:
        form.token.data = request.params["token"]

    layout = DefaultLayout(self, request)
    layout.breadcrumbs = [
        Link(_("Homepage"), layout.homepage_url),
        Link(_("Reset password"), request.link(self, name="request-password")),
    ]

    return {"layout": layout, "title": _(u"Reset password"), "form": form, "form_width": "small"}
Beispiel #12
0
def handle_password_reset_request(self, request, form):
    """ Handles the GET and POST password reset requests. """
    if form.submitted(request):
        user, token = form.get_token(request)
        if user is not None and token is not None:
            url = "{0}?token={1}".format(request.link(self, name="reset-password"), token)
            send_html_mail(
                request=request,
                template="mail_password_reset.pt",
                subject=_("Password reset"),
                receivers=(user.username,),
                content={"model": None, "url": url},
            )
        else:
            log.info("Failed password reset attempt by {}".format(request.client_addr))

        response = morepath.redirect(request.link(self))
        request.success(
            _(
                (
                    u"A password reset link has been sent to ${email}, provided an "
                    u"account exists for this email address."
                ),
                mapping={"email": form.email.data},
            )
        )
        return response

    layout = DefaultLayout(self, request)
    layout.breadcrumbs = [
        Link(_("Homepage"), layout.homepage_url),
        Link(_("Reset password"), request.link(self, name="request-password")),
    ]

    return {"layout": layout, "title": _(u"Reset password"), "form": form, "form_width": "small"}
Beispiel #13
0
def view_occurrences(self, request):
    """ View all occurrences of all events. """

    request.include('common')
    request.include('events')

    layout = OccurrencesLayout(self, request)

    tags = (
        Link(
            text=request.translate(_(tag)),
            url=request.link(self.for_filter(tag=tag)),
            active=tag in self.tags and 'active' or ''
        ) for tag in self.used_tags
    )

    return {
        'active_tags': self.tags,
        'add_link': request.link(self, name='neu'),
        'date_placeholder': date.today().isoformat(),
        'end': self.end.isoformat() if self.end else '',
        'layout': layout,
        'number_of_occurrences': self.subset_count,
        'occurrences': self.batch,
        'start': self.start.isoformat() if self.start else '',
        'tags': tags,
        'title': _('Events'),
    }
Beispiel #14
0
def handle_new_definition(self, request, form):

    if form.submitted(request):

        model = Bunch(
            title=None, definition=None, type='custom', meta={}, content={}
        )
        form.update_model(model)

        # forms added online are always custom forms
        new_form = self.definitions.add(
            title=model.title,
            definition=model.definition,
            type='custom',
            meta=model.meta,
            content=model.content
        )

        request.success(_("Added a new form"))
        return morepath.redirect(request.link(new_form))

    layout = FormEditorLayout(self, request)
    layout.breadcrumbs = [
        Link(_("Homepage"), layout.homepage_url),
        Link(_("Forms"), request.link(self)),
        Link(_("New Form"), request.link(self, name='neu'))
    ]

    return {
        'layout': layout,
        'title': _("New Form"),
        'form': form,
        'form_width': 'large',
    }
Beispiel #15
0
 def editbar_links(self):
     if self.request.is_logged_in:
         return [
             LinkGroup(
                 title=_("Add"),
                 links=[
                     Link(
                         text=_("Room"),
                         url=self.request.link(
                             self.model,
                             name='neuer-raum'
                         ),
                         classes=('new-room', )
                     ),
                     Link(
                         text=_("Daypass"),
                         url=self.request.link(
                             self.model,
                             name='neue-tageskarte'
                         ),
                         classes=('new-daypass', )
                     )
                 ]
             ),
         ]
Beispiel #16
0
def search(self, request):

    layout = DefaultLayout(self, request)
    layout.breadcrumbs.append(Link(_("Search"), "#"))

    try:
        request.app.es_client.ping()
    except TransportError:
        log.warn("Elasticsearch cluster is offline")
        return {"title": _("Search Unavailable"), "layout": layout, "connection": False}

    if "lucky" in request.GET:
        url = self.feeling_lucky()

        if url:
            return morepath.redirect(url)

    return {
        "title": _("Search"),
        "model": self,
        "layout": layout,
        "hide_search_header": True,
        "searchlabel": _("Search through ${count} indexed documents", mapping={"count": self.available_documents}),
        "resultslabel": _("${count} Results", mapping={"count": self.subset_count}),
        "connection": True,
    }
Beispiel #17
0
def handle_edit_definition(self, request, form):

    if form.submitted(request):
        self.title = form.title.data

        if self.type == 'custom':
            self.definition = form.definition.data

        form.update_model(self)

        request.success(_("Your changes were saved"))
        return morepath.redirect(request.link(self))
    else:
        form.title.data = self.title
        form.definition.data = self.definition
        form.apply_model(self)

    collection = FormCollection(request.app.session())

    layout = FormEditorLayout(self, request)
    layout.breadcrumbs = [
        Link(_("Homepage"), layout.homepage_url),
        Link(_("Forms"), request.link(collection)),
        Link(self.title, request.link(self)),
        Link(_("Edit"), request.link(self, name='bearbeiten'))
    ]

    return {
        'layout': layout,
        'title': self.title,
        'form': form,
        'form_width': 'large',
    }
Beispiel #18
0
    def get_edit_links(self, request):
        """ Yields the edit links shown on the private view of this trait. """

        if self.editable:
            yield Link(
                _("Edit"),
                request.link(Editor('edit', self)),
                classes=('edit-link', )
            )

        if self.deletable:
            trait_messages = self.trait_messages[self.trait]

            if self.children:
                extra_warning = _(
                    "Please note that this page has subpages "
                    "which will also be deleted!"
                )
            else:
                extra_warning = ""

            yield DeleteLink(
                _("Delete"), request.link(self),
                confirm=_(trait_messages['delete_question'], mapping={
                    'title': self.title
                }),
                yes_button_text=trait_messages['delete_button'],
                extra_information=extra_warning,
                redirect_after=request.link(self.parent)
            )
Beispiel #19
0
def publish_event(self, request):
    """ Publish an event. """

    self.publish()

    request.success(_("You have accepted the event ${title}", mapping={
        'title': self.title
    }))

    if self.meta.get('submitter_email'):

        session = request.app.session()
        ticket = TicketCollection(session).by_handler_id(self.id.hex)

        send_html_mail(
            request=request,
            template='mail_event_accepted.pt',
            subject=_("Your event was accepted"),
            receivers=(self.meta.get('submitter_email'), ),
            content={
                'model': self,
                'ticket': ticket
            }
        )

    if 'return-to' in request.GET:
        return morepath.redirect(request.GET['return-to'])

    return morepath.redirect(request.link(self))
Beispiel #20
0
def accept_reservation(self, request):
    if not self.data or not self.data.get('accepted'):
        collection = ResourceCollection(request.app.libres_context)
        resource = collection.by_id(self.resource)
        scheduler = resource.get_scheduler(request.app.libres_context)
        reservations = scheduler.reservations_by_token(self.token)

        send_html_mail(
            request=request,
            template='mail_reservation_accepted.pt',
            subject=_("Your reservation was accepted"),
            receivers=(self.email, ),
            content={
                'model': self,
                'resource': resource,
                'reservations': reservations
            }
        )

        for reservation in reservations:
            reservation.data = reservation.data or {}
            reservation.data['accepted'] = True

            # libres does not automatically detect changes yet
            flag_modified(reservation, 'data')

        request.success(_("The reservation was accepted"))
    else:
        request.warning(_("The reservation has already been accepted"))

    return morepath.redirect(request.params['return-to'])
Beispiel #21
0
def handle_user_profile(self, request, form):
    """ Handles the GET and POST login requests. """

    layout = DefaultLayout(self, request)

    collection = UserCollection(request.app.session())
    user = collection.by_username(request.identity.userid)

    if form.submitted(request):
        form.update_model(user)
        request.success(_("Your changes were saved"))
    else:
        form.apply_model(user)

    layout.breadcrumbs = [
        Link(_("Homepage"), layout.homepage_url),
        Link(_("User Profile"), request.link(self))
    ]

    return {
        'layout': layout,
        'title': _("User Profile"),
        'form': form,
        'username': user.username,
        'role': user.role
    }
Beispiel #22
0
def get_site_collection(self, request):
    """ Returns a list of internal links to be used by the redactor.

    See `<http://imperavi.com/redactor/plugins/predefined-links/>`_

    """

    objects = self.get()

    groups = [
        ('topics', request.translate(_("Topics"))),
        ('news', request.translate(_("Latest news"))),
        ('forms', request.translate(_("Forms"))),
        ('resources', request.translate(_("Resources"))),
    ]

    links = []

    for id, label in groups:
        for obj in objects[id]:
            # in addition to the default url/name pairings we use a group
            # label which will be used as optgroup label
            links.append({
                'group': label,
                'name': obj.title,
                'url': request.link(obj)
            })

    return links
Beispiel #23
0
def handle_cleanup_allocations(self, request, form):
    """ Removes all unused allocations between the given dates. """

    if form.submitted(request):
        start, end = form.data['start'], form.data['end']

        scheduler = self.get_scheduler(request.app.libres_context)
        count = scheduler.remove_unused_allocations(start, end)

        request.success(
            _("Successfully removed ${count} unused allocations", mapping={
                'count': count
            })
        )

        return morepath.redirect(request.link(self))

    layout = ResourceLayout(self, request)
    layout.breadcrumbs.append(Link(_("Clean up"), '#'))
    layout.editbar_links = None

    return {
        'layout': layout,
        'title': _("Clean up"),
        'form': form
    }
Beispiel #24
0
def handle_settings(self, request, form):
    """ Handles the GET and POST login requests. """

    layout = DefaultLayout(self, request)
    layout.include_editor()

    request.include('check_contrast')

    if form.submitted(request):
        with request.app.update_town() as town:
            town.name = form.name.data
            town.logo_url = form.logo_url.data
            town.theme_options = form.theme_options
            town.meta = {
                'contact': form.contact.data,
                'contact_html': linkify(
                    form.contact.data).replace('\n', '<br>'),
                'contact_url': form.contact_url.data,
                'opening_hours': form.opening_hours.data,
                'opening_hours_html': linkify(
                    form.opening_hours.data).replace('\n', '<br>'),
                'opening_hours_url': form.opening_hours_url.data,
                'reply_to': form.reply_to.data,
                'facebook_url': form.facebook_url.data,
                'twitter_url': form.twitter_url.data,
                'analytics_code': form.analytics_code.data,
                'online_counter_label': form.online_counter_label.data,
                'reservations_label': form.reservations_label.data,
                'sbb_daypass_label': form.sbb_daypass_label.data,
            }

        request.success(_("Your changes were saved"))
    else:
        form.name.data = self.name
        form.logo_url.data = self.logo_url
        form.theme_options = self.theme_options
        form.contact.data = self.meta.get('contact')
        form.contact_url.data = self.meta.get('contact_url')
        form.opening_hours.data = self.meta.get('opening_hours')
        form.opening_hours_url.data = self.meta.get('opening_hours_url')
        form.reply_to.data = self.meta.get('reply_to')
        form.facebook_url.data = self.meta.get('facebook_url')
        form.twitter_url.data = self.meta.get('twitter_url')
        form.analytics_code.data = self.meta.get('analytics_code')
        form.online_counter_label.data = self.meta.get('online_counter_label')
        form.reservations_label.data = self.meta.get('reservations_label')
        form.sbb_daypass_label.data = self.meta.get('sbb_daypass_label')

    layout.breadcrumbs = [
        Link(_("Homepage"), layout.homepage_url),
        Link(_("Settings"), request.link(self))
    ]

    return {
        'layout': layout,
        'title': _('Settings'),
        'form': form,
        'form_width': 'large'
    }
Beispiel #25
0
    def breadcrumbs(self):
        collection = FormCollection(self.request.app.session())

        return [
            Link(_("Homepage"), self.homepage_url),
            Link(_("Forms"), self.request.link(collection)),
            Link(self.title, '#')
        ]
Beispiel #26
0
def view_get_image_collection(self, request):
    request.include("dropzone")

    images = [Img(src=request.link(image.thumbnail), url=request.link(image)) for image in self.files]

    layout = DefaultLayout(self, request)
    layout.breadcrumbs = [Link(_("Homepage"), layout.homepage_url), Link(_("Images"), request.link(self))]

    return {"layout": layout, "title": _(u"Images"), "images": images}
Beispiel #27
0
def view_get_file_collection(self, request):
    request.include("dropzone")

    files = [Link(text=file_.original_name, url=request.link(file_)) for file_ in self.files]

    layout = DefaultLayout(self, request)
    layout.breadcrumbs = [Link(_("Homepage"), layout.homepage_url), Link(_("Files"), request.link(self))]

    return {"layout": layout, "title": _("Files"), "files": files}
Beispiel #28
0
    def event_actions(self):

        if self.availability == 0:
            yield Link(
                _("Unavailable"),
                '#',
                classes=('new-reservation', 'disabled')
            )
        else:
            yield Link(
                _("Reserve"),
                self.request.link(self.allocation, name='reservieren'),
                classes=('new-reservation', )
            )

        if self.request.is_logged_in:
            yield Link(
                _("Edit"),
                self.request.link(self.allocation, name='bearbeiten'),
                classes=('edit-link', )
            )

            yield Link(
                _("Tickets"),
                self.request.link(TicketCollection(
                    session=self.request.app.session,
                    handler='RSV',
                    state='all',
                    extra_parameters={
                        'allocation_id': str(self.allocation.id)
                    }
                )),
                classes=('RSV-link', )
            )

            if self.availability == 100.0:
                yield DeleteLink(
                    _("Delete"),
                    self.request.link(self.allocation),
                    confirm=_("Do you really want to delete this allocation?"),
                    extra_information=self.event_identification,
                    yes_button_text=_("Delete allocation")
                )
            else:
                yield DeleteLink(
                    _("Delete"),
                    self.request.link(self.allocation),
                    confirm=_(
                        "This allocation can't be deleted because there are "
                        "existing reservations associated with it."
                    ),
                    extra_information=_(
                        "To delete this allocation, all existing reservations "
                        "need to be cancelled first."
                    )
                )
Beispiel #29
0
def atoz(self, request):

    layout = DefaultLayout(self, request)
    layout.breadcrumbs.append(Link(_("Topics A-Z"), '#'))

    return {
        'title': _("Topics A-Z"),
        'model': self,
        'layout': layout
    }
Beispiel #30
0
def view_tickets(self, request):

    def get_filters():
        states = (
            ('open', _("Open")),
            ('pending', _("Pending")),
            ('closed', _("Closed")),
            ('all', _("All"))
        )

        for id, text in states:
            yield Link(
                text=text,
                url=request.link(self.for_state(id)),
                active=self.state == id,
                classes=('ticket-filter-' + id, )
            )

    def get_handlers():
        handlers = (
            ('ALL', _("All")),
            ('EVN', _("Events")),
            ('FRM', _("Form Submissions")),
            ('RSV', _("Reservations")),
        )

        for id, text in handlers:
            yield Link(
                text=text,
                url=request.link(self.for_handler(id)),
                active=self.handler == id,
                classes=(id + '-link', )
            )

    if self.state == 'open':
        tickets_title = _("Open Tickets")
    elif self.state == 'pending':
        tickets_title = _("Pending Tickets")
    elif self.state == 'closed':
        tickets_title = _("Closed Tickets")
    elif self.state == 'all':
        tickets_title = _("All Tickets")
    else:
        raise NotImplementedError

    return {
        'title': _("Tickets"),
        'layout': TicketsLayout(self, request),
        'tickets': self.batch,
        'filters': tuple(get_filters()),
        'handlers': tuple(get_handlers()),
        'tickets_title': tickets_title,
        'tickets_state': self.state,
        'has_handler_filter': self.handler != 'ALL'
    }