Example #1
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')
    }
Example #2
0
def handle_delete_resource(self, request):

    if not self.deletable(request.app.libres_context):
        raise exc.HTTPMethodNotAllowed()

    collection = ResourceCollection(request.app.libres_context)
    collection.delete(self, including_reservations=False)
Example #3
0
def get_resource(app, name, date=None, highlights=tuple()):

    resource = ResourceCollection(app.libres_context).by_name(name)
    resource.date = date
    resource.highlights = highlights

    return resource
Example #4
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'])
Example #5
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'])
Example #6
0
def add_resources(libres_context):
    resource = ResourceCollection(libres_context)
    resource.add(
        "SBB-Tageskarte",
        'Europe/Zurich',
        type='daypass',
        name='sbb-tageskarte'
    )
Example #7
0
def get_allocation(app, resource, id):
    scheduler = ResourceCollection(
        app.libres_context).scheduler_by_id(resource)

    if scheduler:
        allocation = scheduler.allocations_by_ids((id, )).first()

        # always get the master, even if another id is requested
        return allocation and allocation.get_master()
Example #8
0
def get_reservation(app, resource, id):
    scheduler = ResourceCollection(
        app.libres_context).scheduler_by_id(resource)

    if scheduler:
        query = scheduler.managed_reservations()
        query = query.filter(Reservation.id == id)

        return query.first()
Example #9
0
    def handle_root(self, request):
        collection = ResourceCollection(request.app.libres_context)

        resource = collection.add("Test", "Europe/Zurich")
        scheduler = resource.get_scheduler(request.app.libres_context)
        scheduler.allocate((datetime(2015, 7, 30, 11), datetime(2015, 7, 30, 12)))

        # this will fail and then abort everything
        request.app.session().add(Document(id=1))
        request.app.session().add(Document(id=1))
Example #10
0
def test_resource_form_definition(libres_context):
    collection = ResourceCollection(libres_context)

    resource = collection.add(title='Executive Lounge',
                              timezone='Europe/Zurich',
                              definition='Mail *= @@@')
    assert resource.form_class().mail is not None

    resource.definition = None
    assert resource.form_class is None
Example #11
0
def handle_delete_allocation(self, request):
    """ Deletes the given resource (throwing an error if there are existing
    reservations associated with it).

    """
    request.assert_valid_csrf_token()

    resources = ResourceCollection(request.app.libres_context)
    scheduler = resources.scheduler_by_id(self.resource)
    scheduler.remove_allocation(id=self.id)
Example #12
0
    def handle_root(self, request):
        collection = ResourceCollection(request.app.libres_context)

        resource = collection.add('Test', 'Europe/Zurich')
        scheduler = resource.get_scheduler(request.app.libres_context)
        scheduler.allocate(
            (datetime(2015, 7, 30, 11), datetime(2015, 7, 30, 12))
        )

        # this will fail and then abort everything
        request.app.session().add(Document(id=1))
        request.app.session().add(Document(id=1))
Example #13
0
def test_resource_form_definition(libres_context):
    collection = ResourceCollection(libres_context)

    resource = collection.add(
        title='Executive Lounge',
        timezone='Europe/Zurich',
        definition='Mail *= @@@'
    )
    assert resource.form_class().mail is not None

    resource.definition = None
    assert resource.form_class is None
Example #14
0
def finalize_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)
    scheduler = resource.get_scheduler(request.app.libres_context)
    session_id = get_libres_session_id(request)

    try:
        scheduler.queries.confirm_reservations_for_session(session_id)
        scheduler.approve_reservations(self.token)
    except LibresError as e:
        utils.show_libres_error(e, request)

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

        return {
            'title': _("The reservation could not be completed"),
            'layout': layout,
        }
    else:
        forms = FormCollection(request.app.session())
        submission = forms.submissions.by_id(self.token)

        if submission:
            forms.submissions.complete_submission(submission)

        with forms.session.no_autoflush:
            ticket = TicketCollection(request.app.session()).open_ticket(
                handler_code='RSV', handler_id=self.token.hex
            )

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

        request.success(_("Thank you for your reservation!"))
        request.app.update_ticket_count()

        return morepath.redirect(request.link(ticket, 'status'))
Example #15
0
def handle_edit_reservation(self, request, form):

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

    if form.submitted(request):
        scheduler = resource.get_scheduler(request.app.libres_context)
        try:
            if self.email != form.email.data:
                scheduler.change_email(self.token, form.email.data)

            start, end = form.get_date_range()
            scheduler.change_reservation(
                self.token, self.id, start, end, quota=form.data.get('quota')
            )
        except LibresError as e:
            utils.show_libres_error(e, request)
        else:
            forms = FormCollection(request.app.session())
            submission = forms.submissions.by_id(self.token)
            confirm_link = request.link(self, 'bestaetigung')

            if submission is None:
                return morepath.redirect(confirm_link)
            else:
                return morepath.redirect(
                    get_submission_link(request, submission, confirm_link)
                )

    form.apply_model(self)

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

    title = _("Change reservation for ${title}", mapping={
        'title': resource.title,
    })

    return {
        'layout': layout,
        'title': title,
        'form': form,
        'allocation': self,
        'button_text': _("Continue")
    }
Example #16
0
def test_resource_highlight_allocations(libres_context):
    collection = ResourceCollection(libres_context)
    resource = collection.add('Executive Lounge', 'Europe/Zurich')

    assert resource.date is None
    assert resource.highlights_min is None
    assert resource.highlights_max is None

    scheduler = resource.get_scheduler(libres_context)
    dates = (datetime(2015, 8, 5, 12), datetime(2015, 8, 5, 18))
    allocations = scheduler.allocate(dates)

    resource.highlight_allocations(allocations)

    assert resource.date == date(2015, 8, 5)
    assert resource.highlights_min == allocations[0].id
    assert resource.highlights_min == allocations[-1].id
Example #17
0
def test_resource_collection(libres_context):

    collection = ResourceCollection(libres_context)
    assert collection.query().count() == 0

    resource = collection.add('Executive Lounge', 'Europe/Zurich')
    assert resource.name == 'executive-lounge'
    assert resource.timezone == 'Europe/Zurich'
    assert resource.get_scheduler(libres_context).resource == resource.id

    assert collection.query().count() == 1
    assert collection.by_id(resource.id)
    assert collection.by_name('executive-lounge')

    collection.delete(collection.by_id(resource.id))

    assert collection.query().count() == 0
Example #18
0
def test_resource_highlight_allocations(libres_context):
    collection = ResourceCollection(libres_context)
    resource = collection.add('Executive Lounge', 'Europe/Zurich')

    assert resource.date is None
    assert resource.highlights_min is None
    assert resource.highlights_max is None

    scheduler = resource.get_scheduler(libres_context)
    dates = (datetime(2015, 8, 5, 12), datetime(2015, 8, 5, 18))
    allocations = scheduler.allocate(dates)

    resource.highlight_allocations(allocations)

    assert resource.date == date(2015, 8, 5)
    assert resource.highlights_min == allocations[0].id
    assert resource.highlights_min == allocations[-1].id
Example #19
0
def test_transaction_integration(postgres_dsn):
    Base = declarative_base()

    class App(Framework, LibresIntegration):
        pass

    class Document(Base):
        __tablename__ = 'documents'
        id = Column(Integer, primary_key=True)

    @App.path(path='/')
    class Root(object):
        pass

    @App.json(model=Root)
    def handle_root(self, request):
        collection = ResourceCollection(request.app.libres_context)

        resource = collection.add('Test', 'Europe/Zurich')
        scheduler = resource.get_scheduler(request.app.libres_context)
        scheduler.allocate(
            (datetime(2015, 7, 30, 11), datetime(2015, 7, 30, 12))
        )

        # this will fail and then abort everything
        request.app.session().add(Document(id=1))
        request.app.session().add(Document(id=1))

    # this is required for the transactions to actually work, usually this
    # would be onegov.server's job
    scan_morepath_modules(App)
    morepath.commit(App)

    app = App()
    app.configure_application(dsn=postgres_dsn, base=Base)
    app.namespace = 'libres'
    app.set_application_id('libres/foo')

    c = Client(app)
    try:
        c.get('/', expect_errors=True)
    except:
        pass

    collection = ResourceCollection(app.libres_context)
    assert collection.query().count() == 0
Example #20
0
def test_transaction_integration(postgres_dsn):
    Base = declarative_base()

    class App(Framework, LibresIntegration):
        pass

    class Document(Base):
        __tablename__ = "documents"
        id = Column(Integer, primary_key=True)

    @App.path(path="/")
    class Root(object):
        pass

    @App.json(model=Root)
    def handle_root(self, request):
        collection = ResourceCollection(request.app.libres_context)

        resource = collection.add("Test", "Europe/Zurich")
        scheduler = resource.get_scheduler(request.app.libres_context)
        scheduler.allocate((datetime(2015, 7, 30, 11), datetime(2015, 7, 30, 12)))

        # this will fail and then abort everything
        request.app.session().add(Document(id=1))
        request.app.session().add(Document(id=1))

    # this is required for the transactions to actually work, usually this
    # would be onegov.server's job
    scan_morepath_modules(App)
    morepath.commit(App)

    app = App()
    app.configure_application(dsn=postgres_dsn, base=Base)
    app.namespace = "libres"
    app.set_application_id("libres/foo")

    c = Client(app)
    try:
        c.get("/", expect_errors=True)
    except:
        pass

    collection = ResourceCollection(app.libres_context)
    assert collection.query().count() == 0
Example #21
0
def handle_edit_allocation(self, request, form):
    """ Handles edit allocation for differing form classes. """

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

    if form.submitted(request):
        scheduler = resource.get_scheduler(request.app.libres_context)

        new_start, new_end = form.dates

        try:
            scheduler.move_allocation(
                master_id=self.id,
                new_start=new_start,
                new_end=new_end,
                new_quota=form.quota,
                quota_limit=form.quota_limit
            )
        except LibresError as e:
            utils.show_libres_error(e, request)
        else:
            request.success(_("Your changes were saved"))
            resource.highlight_allocations([self])
            return morepath.redirect(request.link(resource))
    elif not request.POST:
        form.apply_model(self)

        start, end = utils.parse_fullcalendar_request(request, self.timezone)
        if start and end:
            form.apply_dates(start, end)

    return {
        'layout': AllocationEditFormLayout(self, request),
        'title': _("Edit allocation"),
        'form': form
    }
Example #22
0
def test_resource_save_delete(libres_context):
    collection = ResourceCollection(libres_context)

    resource = collection.add('Executive Lounge', 'Europe/Zurich')
    assert resource.name == 'executive-lounge'
    assert resource.timezone == 'Europe/Zurich'
    scheduler = resource.get_scheduler(libres_context)

    dates = (datetime(2015, 8, 5, 12), datetime(2015, 8, 5, 18))

    scheduler.allocate(dates)
    scheduler.reserve('*****@*****.**', dates)

    with pytest.raises(AssertionError):
        collection.delete(resource)

    collection.delete(resource, including_reservations=True)

    assert collection.query().count() == 0
    assert scheduler.managed_reservations().count() == 0
    assert scheduler.managed_reserved_slots().count() == 0
    assert scheduler.managed_allocations().count() == 0
Example #23
0
def test_resource_save_delete(libres_context):
    collection = ResourceCollection(libres_context)

    resource = collection.add('Executive Lounge', 'Europe/Zurich')
    assert resource.name == 'executive-lounge'
    assert resource.timezone == 'Europe/Zurich'
    scheduler = resource.get_scheduler(libres_context)

    dates = (datetime(2015, 8, 5, 12), datetime(2015, 8, 5, 18))

    scheduler.allocate(dates)
    scheduler.reserve('*****@*****.**', dates)

    with pytest.raises(AssertionError):
        collection.delete(resource)

    collection.delete(resource, including_reservations=True)

    assert collection.query().count() == 0
    assert scheduler.managed_reservations().count() == 0
    assert scheduler.managed_reserved_slots().count() == 0
    assert scheduler.managed_allocations().count() == 0
Example #24
0
def test_resource_collection(libres_context):

    collection = ResourceCollection(libres_context)
    assert collection.query().count() == 0

    resource = collection.add('Executive Lounge', 'Europe/Zurich')
    assert resource.name == 'executive-lounge'
    assert resource.timezone == 'Europe/Zurich'
    assert resource.get_scheduler(libres_context).resource == resource.id

    assert collection.query().count() == 1
    assert collection.by_id(resource.id)
    assert collection.by_name('executive-lounge')

    collection.delete(collection.by_id(resource.id))

    assert collection.query().count() == 0
Example #25
0
def handle_reserve_allocation(self, request, form):
    """ Creates a new reservation for the given allocation.
    """

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

    if form.submitted(request):
        start, end = form.get_date_range()

        try:
            scheduler = resource.get_scheduler(request.app.libres_context)
            token = scheduler.reserve(
                email=form.data['email'],
                dates=(start, end),
                quota=int(form.data.get('quota', 1)),
                session_id=get_libres_session_id(request)
            )
        except LibresError as e:
            utils.show_libres_error(e, request)
        else:
            # while we re at it, remove all expired sessions
            resource.remove_expired_reservation_sessions(
                request.app.libres_context)

            # though it's possible for a token to have multiple reservations,
            # it is not something that can happen here -> therefore one!
            reservation = scheduler.reservations_by_token(token).one()
            confirm_link = request.link(reservation, 'bestaetigung')

            if not resource.definition:
                return morepath.redirect(confirm_link)

            # if extra form data is required, this is the first step.
            # together with the unconfirmed, session-bound reservation,
            # we create a new external submission without any data in it.
            # the user is then redirected to the reservation data edit form
            # where the reservation is finalized and a ticket is opened.
            forms = FormCollection(request.app.session())
            submission = forms.submissions.add_external(
                form=resource.form_class(),
                state='pending',
                id=reservation.token
            )

            return morepath.redirect(
                get_submission_link(request, submission, confirm_link)
            )

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

    title = _("New reservation for ${title}", mapping={
        'title': resource.title,
    })

    return {
        'layout': layout,
        'title': title,
        'form': form,
        'allocation': self,
        'button_text': _("Continue")
    }