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') }
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)
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
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'])
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'])
def add_resources(libres_context): resource = ResourceCollection(libres_context) resource.add( "SBB-Tageskarte", 'Europe/Zurich', type='daypass', name='sbb-tageskarte' )
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()
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()
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))
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
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)
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))
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
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'))
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") }
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
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
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
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
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 }
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
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") }