def _print_occurrences(user, occurrences, _defaults={}, _overrides={}): if not _defaults or not _overrides: _defaults.update({RepeatFrequency.WEEK: rb_settings.get('notification_before_days_weekly'), RepeatFrequency.MONTH: rb_settings.get('notification_before_days_monthly'), RepeatFrequency.NEVER: rb_settings.get('notification_before_days'), RepeatFrequency.DAY: rb_settings.get('notification_before_days')}) _overrides.update({RepeatFrequency.WEEK: lambda r: r.notification_before_days_weekly, RepeatFrequency.MONTH: lambda r: r.notification_before_days_monthly, RepeatFrequency.NEVER: lambda r: r.notification_before_days, RepeatFrequency.DAY: lambda r: r.notification_before_days}) print cformat('%{grey!}*** {} ({}) ***').format(user.full_name, user.email) for occ in occurrences: default = _defaults[occ.reservation.repeat_frequency] override = _overrides[occ.reservation.repeat_frequency](occ.reservation.room) days = default if override is None else override days_until = (occ.start_dt.date() - date.today()).days print cformat(' * %{yellow}{}%{reset} %{green}{:5}%{reset} {} {} {} \t %{blue!}{}%{reset} {} ({})').format( occ.start_dt.date(), occ.reservation.repeat_frequency.name, days, default if override is not None and override != default else ' ', days_until, occ.reservation.id, occ.reservation.room.full_name, occ.reservation.room.id )
def _print_occurrences(user, occurrences, _defaults={}, _overrides={}): if not _defaults or not _overrides: _defaults.update({RepeatFrequency.WEEK: rb_settings.get('notification_before_days_weekly'), RepeatFrequency.MONTH: rb_settings.get('notification_before_days_monthly'), RepeatFrequency.NEVER: rb_settings.get('notification_before_days'), RepeatFrequency.DAY: rb_settings.get('notification_before_days')}) _overrides.update({RepeatFrequency.WEEK: lambda r: r.notification_before_days_weekly, RepeatFrequency.MONTH: lambda r: r.notification_before_days_monthly, RepeatFrequency.NEVER: lambda r: r.notification_before_days, RepeatFrequency.DAY: lambda r: r.notification_before_days}) print(cformat('%{grey!}*** {} ({}) ***').format(user.full_name, user.email)) for occ in occurrences: default = _defaults[occ.reservation.repeat_frequency] override = _overrides[occ.reservation.repeat_frequency](occ.reservation.room) days = default if override is None else override days_until = (occ.start_dt.date() - date.today()).days print(cformat(' * %{yellow}{}%{reset} %{green}{:5}%{reset} {} {} {} \t %{blue!}{}%{reset} {} ({})').format( occ.start_dt.date(), occ.reservation.repeat_frequency.name, days, default if override is not None and override != default else ' ', days_until, occ.reservation.id, occ.reservation.room.full_name, occ.reservation.room.id ))
def _make_occurrence_date_filter(): _default = rb_settings.get('notification_before_days') _default_weekly = rb_settings.get('notification_before_days_weekly') _default_monthly = rb_settings.get('notification_before_days_monthly') notification_before_days_room = db.case({RepeatFrequency.WEEK.value: Room.notification_before_days_weekly, RepeatFrequency.MONTH.value: Room.notification_before_days_monthly}, else_=Room.notification_before_days, value=Reservation.repeat_frequency) notification_before_days_default = db.case({RepeatFrequency.WEEK.value: _default_weekly, RepeatFrequency.MONTH.value: _default_monthly}, else_=_default, value=Reservation.repeat_frequency) notification_before_days = db.func.coalesce(notification_before_days_room, notification_before_days_default) days_until_occurrence = db.cast(ReservationOccurrence.start_dt, db.Date) - date.today() return days_until_occurrence == notification_before_days
def roombooking_end_notifications(): if not config.ENABLE_ROOMBOOKING: logger.info('Notifications not sent because room booking is disabled') return if not rb_settings.get('end_notifications_enabled'): logger.info( 'Notifications not sent because they are globally disabled') return defaults = { 'default': rb_settings.get('end_notification_daily'), 'weekly': rb_settings.get('end_notification_weekly'), 'monthly': rb_settings.get('end_notification_monthly') } room_columns = { 'default': Room.end_notification_daily, 'weekly': Room.end_notification_weekly, 'monthly': Room.end_notification_monthly } cte = (db.session.query( Reservation.id, Reservation.repeat_frequency).add_columns( db.func.max(ReservationOccurrence.start_dt).label( 'last_valid_end_dt')).join(Reservation.room).join( Reservation.occurrences).filter( ReservationOccurrence.is_valid, ReservationOccurrence.end_dt >= datetime.now(), Reservation.is_accepted, Reservation.repeat_frequency != RepeatFrequency.NEVER, Room.end_notifications_enabled, ~Reservation.end_notification_sent, ~Room.is_deleted).group_by(Reservation.id).cte()) reservations = (Reservation.query.options(noload('created_by_user')).join( cte, cte.c.id == Reservation.id).join(Reservation.room).filter( _make_occurrence_date_filter(cte.c.last_valid_end_dt, defaults, room_columns, cte.c.repeat_frequency)).order_by( 'booked_for_id', 'start_dt', 'room_id').all()) for user, user_reservations in groupby(reservations, key=attrgetter('booked_for_user')): user_reservations = list(user_reservations) notify_about_finishing_bookings(user, list(user_reservations)) for user_reservation in user_reservations: user_reservation.end_notification_sent = True db.session.commit()
def roombooking_occurrences(debug=False): if not config.ENABLE_ROOMBOOKING: logger.info('Notifications not sent because room booking is disabled') return if not rb_settings.get('notifications_enabled'): logger.info('Notifications not sent because they are globally disabled') return occurrences = (ReservationOccurrence.query .join(ReservationOccurrence.reservation) .join(Reservation.room) .filter(Room.is_active, Room.notifications_enabled, Reservation.is_accepted, Reservation.booked_for_id.isnot(None), ReservationOccurrence.is_valid, ReservationOccurrence.start_dt >= datetime.now(), ~ReservationOccurrence.notification_sent, _make_occurrence_date_filter()) .order_by(Reservation.booked_for_id, ReservationOccurrence.start_dt, Room.id) .options(contains_eager('reservation').contains_eager('room')) .all()) for user, user_occurrences in groupby(occurrences, key=attrgetter('reservation.booked_for_user')): user_occurrences = list(user_occurrences) if debug: _print_occurrences(user, user_occurrences) else: _notify_occurrences(user, user_occurrences) if not debug: db.session.commit()
def _process(self): args = self.args user_id = args.pop('user_id', None) booked_for = User.get_one(user_id, is_deleted=False) if user_id else session.user # Check that the booking is not longer than allowed booking_limit_days = self.room.booking_limit_days or rb_settings.get('booking_limit') if not self._validate_room_booking_limit(args['start_dt'], args['end_dt'], booking_limit_days): msg = (_('Bookings for the room "{}" may not be longer than {} days') .format(self.room.name, booking_limit_days)) raise ExpectedError(msg) try: resv = Reservation.create_from_data(self.room, dict(args, booked_for_user=booked_for), session.user, prebook=self.prebook) if args.get('link_type') is not None and args.get('link_id') is not None: self._link_booking(resv, args['link_type'], args['link_id'], args['link_back']) db.session.flush() except NoReportError as e: db.session.rollback() raise ExpectedError(unicode(e)) serialized_occurrences = serialize_occurrences(group_by_occurrence_date(resv.occurrences.all())) if self.prebook: data = {'pre_bookings': serialized_occurrences} else: data = {'bookings': serialized_occurrences} return jsonify(room_id=self.room.id, booking=reservation_details_schema.dump(resv).data, calendar_data=data)
def _process(self): args = self.args args.setdefault('booked_for_user', session.user) if not is_booking_start_within_grace_period(args['start_dt'], session.user, args['admin_override_enabled']): raise ExpectedError(_('You cannot create a booking which starts in the past')) # Check that the booking is not longer than allowed booking_limit_days = self.room.booking_limit_days or rb_settings.get('booking_limit') if not self._validate_room_booking_limit(args['start_dt'], args['end_dt'], booking_limit_days): msg = (_('Bookings for the room "{}" may not be longer than {} days') .format(self.room.name, booking_limit_days)) raise ExpectedError(msg) try: resv = Reservation.create_from_data(self.room, args, session.user, prebook=self.prebook) if args.get('link_type') is not None and args.get('link_id') is not None: self._link_booking(resv, args['link_type'], args['link_id'], args['link_back']) db.session.flush() except NoReportError as e: db.session.rollback() raise ExpectedError(unicode(e)) serialized_occurrences = serialize_occurrences(group_by_occurrence_date(resv.occurrences.all())) if self.prebook: data = {'pre_bookings': serialized_occurrences} else: data = {'bookings': serialized_occurrences} return jsonify(room_id=self.room.id, booking=reservation_details_schema.dump(resv), calendar_data=data)
def _process(self): if not request.is_xhr: return redirect( url_for_index( _anchor='create-event:{}'.format(self.event_type.name))) form_cls = LectureCreationForm if self.event_type == EventType.lecture else EventCreationForm form = form_cls(obj=self._get_form_defaults(), prefix='event-creation-') if form.validate_on_submit(): if self.event_type == EventType.lecture: events = self._create_series(form.data) event = events[0] if len(events) > 1: flash( Markup( render_template('events/series_created_msg.html', events=events)), 'info') notify_event_creation(event, occurrences=events) else: event = self._create_event(form.data) notify_event_creation(event) return jsonify_data(flash=False, redirect=url_for('event_management.settings', event)) check_room_availability = rb_check_user_access( session.user) and config.ENABLE_ROOMBOOKING rb_excluded_categories = rb_settings.get('excluded_categories') return jsonify_template( 'events/forms/event_creation_form.html', form=form, fields=form._field_order, event_type=self.event_type.name, single_category=self.single_category, check_room_availability=check_room_availability, rb_excluded_categories=rb_excluded_categories)
def _process_select_room(self): # Step 1: Room(s), dates, repetition selection form = self._make_select_room_form() if form.validate_on_submit(): flexible_days = form.flexible_dates_range.data day_start_dt = datetime.combine(form.start_dt.data.date(), time()) day_end_dt = datetime.combine(form.end_dt.data.date(), time(23, 59)) selected_rooms = [r for r in self._rooms if r.id in form.room_ids.data] selected_period_days = (day_end_dt - day_start_dt).days for room in selected_rooms: booking_limit_days = room.booking_limit_days or rb_settings.get('booking_limit') if selected_period_days > booking_limit_days: flash(_(u'Bookings for the room "{}" may not be longer than {} days') .format(room.name, booking_limit_days), 'error') return self._redirect(url_for('rooms.book')) occurrences, candidates = self._get_all_occurrences(form.room_ids.data, form, flexible_days) period_form_defaults = FormDefaults(repeat_interval=form.repeat_interval.data, repeat_frequency=form.repeat_frequency.data) period_form = self._make_select_period_form(period_form_defaults) # Show step 2 page return self._get_view('select_period', rooms=selected_rooms, occurrences=occurrences, candidates=candidates, start_dt=day_start_dt, end_dt=day_end_dt, period_form=period_form, form=form, repeat_frequency=form.repeat_frequency.data, repeat_interval=form.repeat_interval.data, flexible_days=flexible_days).display() # GET or form errors => show step 1 page return self._get_view('select_room', errors=form.error_list, rooms=self._rooms, form=form, my_rooms=[r.id for r in Room.get_owned_by(session.user)], max_room_capacity=Room.max_capacity, can_override=rb_is_admin(session.user), date_changed=not form.is_submitted() and self.date_changed, ).display()
def get_recurring_booking_suggestions(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, limit=None): data = [] booking_days = end_dt - start_dt booking_length = booking_days.days + 1 candidates = ReservationOccurrence.create_series(start_dt, end_dt, (repeat_frequency, repeat_interval)) blocked_rooms = group_blocked_rooms(get_rooms_blockings(rooms, start_dt.date(), end_dt.date())) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods(rooms, start_dt, end_dt) conflicts = get_rooms_conflicts(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, blocked_rooms, nonbookable_periods, unbookable_hours)[0] for room in rooms: if limit and len(data) == limit: break suggestions = {} booking_limit = room.booking_limit_days or rb_settings.get('booking_limit') limit_exceeded = booking_limit is not None and booking_limit < booking_length if limit_exceeded: excess_days = booking_length - booking_limit suggestions['shorten'] = excess_days if not limit_exceeded: number_of_conflicting_days = len(group_by_occurrence_date(conflicts.get(room.id, []))) if number_of_conflicting_days and number_of_conflicting_days < len(candidates): suggestions['skip'] = number_of_conflicting_days if suggestions: data.append({'room': room, 'suggestions': suggestions}) return data
def get_rooms_availability(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, flexibility): period_days = (end_dt - start_dt).days availability = {} candidates = ReservationOccurrence.create_series(start_dt, end_dt, (repeat_frequency, repeat_interval)) date_range = sorted(set(cand.start_dt.date() for cand in candidates)) for room in rooms: booking_limit_days = room.booking_limit_days or rb_settings.get('booking_limit') if period_days > booking_limit_days: continue start_dt = start_dt + timedelta(days=flexibility) end_dt = end_dt + timedelta(days=flexibility) occurrences = get_existing_room_occurrences(room, start_dt.replace(hour=0, minute=0), end_dt.replace(hour=23, minute=59)) conflicts, pre_conflicts = get_room_conflicts(room, start_dt.replace(tzinfo=None), end_dt.replace(tzinfo=None), repeat_frequency, repeat_interval) pre_bookings = [occ for occ in occurrences if not occ.reservation.is_accepted] existing_bookings = [occ for occ in occurrences if occ.reservation.is_accepted] availability[room.id] = {'room': room, 'candidates': group_by_occurrence_date(candidates), 'pre_bookings': group_by_occurrence_date(pre_bookings), 'bookings': group_by_occurrence_date(existing_bookings), 'conflicts': group_by_occurrence_date(conflicts), 'pre_conflicts': group_by_occurrence_date(pre_conflicts)} return date_range, availability
def _process(self, args): room = Room.get_one(args.pop('room_id')) user_id = args.pop('user_id', None) booked_for = User.get_one(user_id) if user_id else session.user is_prebooking = args.pop('is_prebooking') # Check that the booking is not longer than allowed booking_limit_days = room.booking_limit_days or rb_settings.get( 'booking_limit') if not self._validate_room_booking_limit( args['start_dt'], args['end_dt'], booking_limit_days): msg = ( _('Bookings for the room "{}" may not be longer than {} days' ).format(room.name, booking_limit_days)) return jsonify(success=False, msg=msg) try: Reservation.create_from_data(room, dict(args, booked_for_user=booked_for), session.user, prebook=is_prebooking) db.session.flush() except NoReportError as e: db.session.rollback() return jsonify(success=False, msg=unicode(e)) return jsonify(success=True, is_prebooking=is_prebooking)
def _process(self, args): room = Room.get_one(args.pop('room_id')) user_id = args.pop('user_id', None) booked_for = User.get_one(user_id) if user_id else session.user is_prebooking = args.pop('is_prebooking') # Check that the booking is not longer than allowed booking_limit_days = room.booking_limit_days or rb_settings.get('booking_limit') if not self._validate_room_booking_limit(args['start_dt'], args['end_dt'], booking_limit_days): msg = (_('Bookings for the room "{}" may not be longer than {} days') .format(room.name, booking_limit_days)) raise ExpectedError(msg) try: resv = Reservation.create_from_data(room, dict(args, booked_for_user=booked_for), session.user, prebook=is_prebooking) db.session.flush() except NoReportError as e: db.session.rollback() raise ExpectedError(unicode(e)) serialized_occurrences = serialize_occurrences(group_by_occurrence_date(resv.occurrences.all())) if is_prebooking: data = {'pre_bookings': serialized_occurrences} else: data = {'bookings': serialized_occurrences} return jsonify(room_id=room.id, booking=reservation_details_schema.dump(resv).data, calendar_data=data)
def get_rooms_availability(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, flexibility): period_days = (end_dt - start_dt).days availability = OrderedDict() candidates = ReservationOccurrence.create_series( start_dt, end_dt, (repeat_frequency, repeat_interval)) date_range = sorted(set(cand.start_dt.date() for cand in candidates)) occurrences = get_existing_rooms_occurrences( rooms, start_dt.replace(hour=0, minute=0), end_dt.replace(hour=23, minute=59), repeat_frequency, repeat_interval) blocked_rooms = get_rooms_blockings(rooms, start_dt.date(), end_dt.date()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods( rooms, start_dt, end_dt) conflicts, pre_conflicts = get_rooms_conflicts( rooms, start_dt.replace(tzinfo=None), end_dt.replace(tzinfo=None), repeat_frequency, repeat_interval, blocked_rooms, nonbookable_periods, unbookable_hours) dates = list(candidate.start_dt.date() for candidate in candidates) for room in rooms: booking_limit_days = room.booking_limit_days or rb_settings.get( 'booking_limit') if period_days > booking_limit_days: continue start_dt = start_dt + timedelta(days=flexibility) end_dt = end_dt + timedelta(days=flexibility) room_occurrences = occurrences.get(room.id, []) room_conflicts = conflicts.get(room.id, []) pre_room_conflicts = pre_conflicts.get(room.id, []) pre_bookings = [ occ for occ in room_occurrences if not occ.reservation.is_accepted ] existing_bookings = [ occ for occ in room_occurrences if occ.reservation.is_accepted ] room_blocked_rooms = blocked_rooms.get(room.id, []) room_nonbookable_periods = nonbookable_periods.get(room.id, []) room_unbookable_hours = unbookable_hours.get(room.id, []) availability[room.id] = { 'room': room, 'candidates': group_by_occurrence_date(candidates), 'pre_bookings': group_by_occurrence_date(pre_bookings), 'bookings': group_by_occurrence_date(existing_bookings), 'conflicts': group_by_occurrence_date(room_conflicts), 'pre_conflicts': group_by_occurrence_date(pre_room_conflicts), 'blockings': group_blockings(room_blocked_rooms, dates), 'nonbookable_periods': group_nonbookable_periods(room_nonbookable_periods, dates), 'unbookable_hours': room_unbookable_hours } return date_range, availability
def _process(self): room = self._reservation.room form = ModifyBookingForm(obj=self._reservation, old_start_dt=self._reservation.start_dt, old_end_dt=self._reservation.end_dt) if not room.notification_for_assistance and not self._reservation.needs_assistance: del form.needs_assistance invalid_form = form.is_submitted() and not form.validate() if invalid_form: occurrences = {} candidates = {} conflicts = {} pre_conflicts = {} else: occurrences, candidates = self._get_all_occurrences( [room.id], form, reservation_id=self._reservation.id) conflicts, pre_conflicts = self._get_all_conflicts( room, form, self._reservation.id) if form.validate_on_submit() and not form.submit_check.data: try: booking_limit_days = room.booking_limit_days or rb_settings.get( 'booking_limit') if not self._validate_room_booking_limit( form, booking_limit_days): msg = (_( u'Bookings for the room "{}" may not be longer than {} days' ).format(room.name, booking_limit_days)) return jsonify(success=False, url=url_for( 'rooms.roomBooking-modifyBookingForm', self._reservation), msg=msg) self._reservation.modify(form.data, session.user) flash(_(u'Booking updated'), 'success') except NoReportError as e: db.session.rollback() return jsonify(success=False, msg=unicode(e)) return jsonify(success=True, url=self._get_success_url()) elif invalid_form and not form.submit_check.data and request.is_xhr: return jsonify(success=False, msg='\n'.join(form.error_list)) return self._get_view(form=form, room=room, rooms=Room.find_all(), occurrences=occurrences, candidates=candidates, conflicts=conflicts, pre_conflicts=pre_conflicts, start_dt=form.start_dt.data, end_dt=form.end_dt.data, only_conflicts=False, repeat_frequency=form.repeat_frequency.data, repeat_interval=form.repeat_interval.data, reservation=self._reservation, can_override=room.can_override( session.user)).display()
def _process_select_room(self): # Step 1: Room(s), dates, repetition selection form = self._make_select_room_form() if form.validate_on_submit(): flexible_days = form.flexible_dates_range.data day_start_dt = datetime.combine(form.start_dt.data.date(), time()) day_end_dt = datetime.combine(form.end_dt.data.date(), time(23, 59)) selected_rooms = [r for r in self._rooms if r.id in form.room_ids.data] selected_period_days = (day_end_dt - day_start_dt).days for room in selected_rooms: booking_limit_days = room.booking_limit_days or rb_settings.get('booking_limit') if selected_period_days > booking_limit_days: flash(_(u'Bookings for the room "{}" may not be longer than {} days') .format(room.name, booking_limit_days), 'error') return redirect(url_for('rooms.book')) occurrences, candidates = self._get_all_occurrences(form.room_ids.data, form, flexible_days) period_form_defaults = FormDefaults(repeat_interval=form.repeat_interval.data, repeat_frequency=form.repeat_frequency.data) period_form = self._make_select_period_form(period_form_defaults) # Show step 2 page return self._get_view('select_period', rooms=selected_rooms, occurrences=occurrences, candidates=candidates, start_dt=day_start_dt, end_dt=day_end_dt, period_form=period_form, form=form, repeat_frequency=form.repeat_frequency.data, repeat_interval=form.repeat_interval.data, flexible_days=flexible_days).display() # GET or form errors => show step 1 page return self._get_view('select_room', errors=form.error_list, rooms=self._rooms, form=form, my_rooms=[r.id for r in Room.get_owned_by(session.user)], max_room_capacity=Room.max_capacity, can_override=rb_is_admin(session.user), date_changed=not form.is_submitted() and self.date_changed, ).display()
def roombooking_occurrences(debug=False): if not Config.getInstance().getIsRoomBookingActive(): logger.info('Notifications not sent because room booking is disabled') return if not rb_settings.get('notifications_enabled'): logger.info( 'Notifications not sent because they are globally disabled') return occurrences = (ReservationOccurrence.query.join( ReservationOccurrence.reservation).join(Reservation.room).filter( Room.is_active, Room.notifications_enabled, Reservation.is_accepted, Reservation.booked_for_id.isnot(None), ReservationOccurrence.is_valid, ReservationOccurrence.start_dt >= datetime.now(), ~ReservationOccurrence.notification_sent, _make_occurrence_date_filter()).order_by( Reservation.booked_for_id, ReservationOccurrence.start_dt, Room.id).options( contains_eager('reservation').contains_eager( 'room')).all()) try: for user, user_occurrences in groupby( occurrences, key=attrgetter('reservation.booked_for_user')): user_occurrences = list(user_occurrences) if debug: _print_occurrences(user, user_occurrences) else: _notify_occurrences(user, user_occurrences) finally: if not debug: db.session.commit()
def _process(self, args): room = Room.get_one(args.pop('room_id')) user_id = args.pop('user_id', None) booked_for = User.get_one(user_id) if user_id else session.user is_prebooking = args.pop('is_prebooking') # Check that the booking is not longer than allowed booking_limit_days = room.booking_limit_days or rb_settings.get('booking_limit') if not self._validate_room_booking_limit(args['start_dt'], args['end_dt'], booking_limit_days): msg = (_('Bookings for the room "{}" may not be longer than {} days') .format(room.name, booking_limit_days)) raise ExpectedError(msg) try: resv = Reservation.create_from_data(room, dict(args, booked_for_user=booked_for), session.user, prebook=is_prebooking) db.session.flush() except NoReportError as e: db.session.rollback() raise ExpectedError(unicode(e)) serialized_occurrences = serialize_occurrences(group_by_occurrence_date(resv.occurrences.all())) if is_prebooking: data = {'pre_bookings': serialized_occurrences} else: data = {'bookings': serialized_occurrences} return jsonify(room_id=room.id, **data)
def _getPageContent(self, params): reservation = params['reservation'] params['endpoints'] = self.endpoints params['assistance_emails'] = rb_settings.get('assistance_emails') params['repetition'] = RepeatMapping.get_message(*reservation.repetition) params['edit_logs'] = reservation.edit_logs.order_by(ReservationEditLog.timestamp.desc()).all() params['excluded_days'] = reservation.find_excluded_days().all() return WTemplated('RoomBookingDetails').getHTML(params)
def roombooking_occurrences(debug=False): if not config.ENABLE_ROOMBOOKING: logger.info('Notifications not sent because room booking is disabled') return if not rb_settings.get('notifications_enabled'): logger.info( 'Notifications not sent because they are globally disabled') return defaults = { 'default': rb_settings.get('notification_before_days'), 'weekly': rb_settings.get('notification_before_days_weekly'), 'monthly': rb_settings.get('notification_before_days_monthly') } room_columns = { 'default': Room.notification_before_days, 'weekly': Room.notification_before_days_weekly, 'monthly': Room.notification_before_days_monthly } occurrences = (ReservationOccurrence.query.join( ReservationOccurrence.reservation).join(Reservation.room).filter( ~Room.is_deleted, Room.notifications_enabled, Reservation.is_accepted, Reservation.booked_for_id.isnot(None), ReservationOccurrence.is_valid, ReservationOccurrence.start_dt >= datetime.now(), ~ReservationOccurrence.notification_sent, _make_occurrence_date_filter( ReservationOccurrence.start_dt, defaults, room_columns)).order_by( Reservation.booked_for_id, ReservationOccurrence.start_dt, Room.id).options( contains_eager('reservation').contains_eager( 'room')).all()) for user, user_occurrences in groupby( occurrences, key=attrgetter('reservation.booked_for_user')): user_occurrences = list(user_occurrences) if debug: _print_occurrences(user, user_occurrences) else: _notify_occurrences(user, user_occurrences) if not debug: db.session.commit()
def compose_email_to_vc_support(self, **mail_params): from indico.modules.rb import rb_settings if self.reservation.is_accepted and self.reservation.uses_vc: to_list = rb_settings.get('vc_support_emails') if to_list: subject = self._get_email_subject(**mail_params) body = self._make_body(mail_params, reservation=self.reservation) return make_email(to_list=to_list, subject=subject, body=body)
def _getPageContent(self, params): params['endpoints'] = self.endpoints calendar = RoomBookingCalendarWidget(params['occurrences'], params['start_dt'], params['end_dt'], candidates=params['candidates'], specific_room=params['room'], repeat_frequency=params['repeat_frequency'], repeat_interval=params['repeat_interval']) params['calendar'] = calendar.render(show_navbar=False, details_in_new_tab=True) params['serializable_room'] = Room.get(params['room'].id).to_serializable('__public_exhaustive__') params['booking_limit'] = rb_settings.get('booking_limit') return WTemplated('RoomBookingBookingForm').getHTML(params)
def compose_email_to_assistance(self, **mail_params): from indico.modules.rb import rb_settings if self.reservation.room.notification_for_assistance: if self.reservation.needs_assistance or mail_params.get('assistance_cancelled'): to_list = rb_settings.get('assistance_emails') if to_list: subject = self._get_email_subject(**mail_params) body = self._make_body(mail_params, reservation=self.reservation) return make_email(to_list=to_list, subject=subject, body=body)
def _getBody(self, params): api_key = rb_settings.get('google_maps_api_key') cache_key = str(sorted(dict(request.args, lang=session.lang).items())) + str(crc32(api_key)) html = self.cache.get(cache_key) if html is None: params.update(self._get_widget_params()) params['api_key'] = api_key html = WTemplated('RoomBookingMapOfRoomsWidget').getHTML(params) self.cache.set(cache_key, html, 3600) return html
def search_for_rooms(filters, only_available=False): query = (Room.query .outerjoin(favorite_room_table, db.and_(favorite_room_table.c.user_id == session.user.id, favorite_room_table.c.room_id == Room.id)) .reset_joinpoint() # otherwise filter_by() would apply to the favorite table .options(raiseload('owner')) .filter(Room.is_active) .order_by(favorite_room_table.c.user_id.is_(None), db.func.indico.natsort(Room.full_name))) criteria = {} if 'capacity' in filters: query = query.filter(db.or_(Room.capacity >= (filters['capacity'] * 0.8), Room.capacity.is_(None))) if 'building' in filters: criteria['building'] = filters['building'] if 'floor' in filters: criteria['floor'] = filters['floor'] query = query.filter_by(**criteria) if 'text' in filters: query = query.filter(_make_room_text_filter(filters['text'])) if filters.get('equipment'): subquery = (db.session.query(RoomEquipmentAssociation) .with_entities(db.func.count(RoomEquipmentAssociation.c.room_id)) .filter( RoomEquipmentAssociation.c.room_id == Room.id, EquipmentType.name.in_(filters['equipment']) ) .join(EquipmentType, RoomEquipmentAssociation.c.equipment_id == EquipmentType.id) .correlate(Room) .as_scalar()) query = query.filter(subquery == len(filters['equipment'])) if filters.get('favorite'): query = query.filter(favorite_room_table.c.user_id.isnot(None)) if filters.get('mine'): ids = get_managed_room_ids(session.user) if ids: query = query.filter(Room.id.in_(ids)) query = _filter_coordinates(query, filters) if not only_available: return query start_dt, end_dt = filters['start_dt'], filters['end_dt'] repeatability = (filters['repeat_frequency'], filters['repeat_interval']) query = query.filter(Room.filter_available(start_dt, end_dt, repeatability, include_pre_bookings=True, include_pending_blockings=True)) if not rb_is_admin(session.user): selected_period_days = (filters['end_dt'] - filters['start_dt']).days booking_limit_days = db.func.coalesce(Room.booking_limit_days, rb_settings.get('booking_limit')) own_rooms = [r.id for r in Room.get_owned_by(session.user)] query = query.filter(db.or_(Room.id.in_(own_rooms) if own_rooms else False, db.and_(Room.filter_bookable_hours(start_dt.time(), end_dt.time()), db.or_(booking_limit_days.is_(None), selected_period_days <= booking_limit_days)))) return query
def _process(self): tos_url = legal_settings.get('tos_url') tos_html = sanitize_html(legal_settings.get('tos')) or None privacy_policy_url = legal_settings.get('privacy_policy_url') privacy_policy_html = sanitize_html(legal_settings.get('privacy_policy')) or None if tos_url: tos_html = None if privacy_policy_url: privacy_policy_html = None return jsonify(rooms_sprite_token=unicode(_cache.get('rooms-sprite-token', '')), languages=get_all_locales(), tileserver_url=rb_settings.get('tileserver_url'), grace_period=rb_settings.get('grace_period'), managers_edit_rooms=rb_settings.get('managers_edit_rooms'), help_url=config.HELP_URL, contact_email=config.PUBLIC_SUPPORT_EMAIL, has_tos=bool(tos_url or tos_html), tos_html=tos_html, has_privacy_policy=bool(privacy_policy_url or privacy_policy_html), privacy_policy_html=privacy_policy_html)
def _process(self): room = self._room rooms = Room.find_all() form = self._make_form() if form.is_submitted() and not form.validate(): occurrences = {} candidates = {} conflicts = {} pre_conflicts = {} only_conflicts = False else: occurrences, candidates = self._get_all_occurrences( [self._room.id], form) conflicts, pre_conflicts = self._get_all_conflicts( self._room, form) candidate_days = { occ.date for candidate in candidates.itervalues() for occ in candidate } conflicting_days = {occ.date for occ in conflicts.iterkeys()} only_conflicts = candidate_days <= conflicting_days if form.validate_on_submit() and not form.submit_check.data: booking_limit_days = room.booking_limit_days or rb_settings.get( 'booking_limit') if not self._validate_room_booking_limit(form, booking_limit_days): msg = (_( u'Bookings for the room "{}" may not be longer than {} days' ).format(room.name, booking_limit_days)) return jsonify(success=False, url=url_for('rooms.room_book', room), msg=msg) return self._create_booking_response(form, room) can_override = room.can_override(session.user) return self._get_view(form=form, room=room, rooms=rooms, occurrences=occurrences, candidates=candidates, conflicts=conflicts, only_conflicts=only_conflicts, pre_conflicts=pre_conflicts, start_dt=form.start_dt.data, end_dt=form.end_dt.data, repeat_frequency=form.repeat_frequency.data, repeat_interval=form.repeat_interval.data, can_override=can_override, past_date=not form.is_submitted() and self.past_date, date_changed=not form.is_submitted() and self.date_changed).display()
def get_room_events(room, start_dt, end_dt, repeat_frequency, repeat_interval): occurrences = ReservationOccurrence.create_series(start_dt, end_dt, (repeat_frequency, repeat_interval)) excluded_categories = rb_settings.get('excluded_categories') return (Event.query .filter(~Event.is_deleted, Event.own_room == room, db.or_(Event.happens_between(as_utc(occ.start_dt), as_utc(occ.end_dt)) for occ in occurrences), Event.timezone == config.DEFAULT_TIMEZONE, db.and_(Event.category_id != cat['id'] for cat in excluded_categories), Event.acl_entries.any(db.and_(EventPrincipal.type == PrincipalType.user, EventPrincipal.user_id == session.user.id, EventPrincipal.full_access))) .all())
def roombooking_end_notifications(): if not config.ENABLE_ROOMBOOKING: logger.info('Notifications not sent because room booking is disabled') return if not rb_settings.get('end_notifications_enabled'): logger.info( 'Notifications not sent because they are globally disabled') return defaults = { 'default': rb_settings.get('end_notification_daily'), 'weekly': rb_settings.get('end_notification_weekly'), 'monthly': rb_settings.get('end_notification_monthly') } room_columns = { 'default': Room.end_notification_daily, 'weekly': Room.end_notification_weekly, 'monthly': Room.end_notification_monthly } reservations = (Reservation.query.join(Reservation.room).filter( ~Room.is_deleted, Room.end_notifications_enabled, Reservation.is_accepted, Reservation.end_dt >= datetime.now(), Reservation.repeat_frequency != RepeatFrequency.NEVER, ~Reservation.end_notification_sent, _make_occurrence_date_filter(Reservation.end_dt, defaults, room_columns)).order_by( Reservation.booked_for_id, Reservation.start_dt, Room.id).all()) for user, user_reservations in groupby(reservations, key=attrgetter('booked_for_user')): user_reservations = list(user_reservations) notify_about_finishing_bookings(user, list(user_reservations)) for user_reservation in user_reservations: user_reservation.end_notification_sent = True db.session.commit()
def _make_occurrence_date_filter(): _default = rb_settings.get('notification_before_days') _default_weekly = rb_settings.get('notification_before_days_weekly') _default_monthly = rb_settings.get('notification_before_days_monthly') notification_before_days_room = db.case( { RepeatFrequency.WEEK.value: Room.notification_before_days_weekly, RepeatFrequency.MONTH.value: Room.notification_before_days_monthly }, else_=Room.notification_before_days, value=Reservation.repeat_frequency) notification_before_days_default = db.case( { RepeatFrequency.WEEK.value: _default_weekly, RepeatFrequency.MONTH.value: _default_monthly }, else_=_default, value=Reservation.repeat_frequency) notification_before_days = db.func.coalesce( notification_before_days_room, notification_before_days_default) days_until_occurrence = db.cast(ReservationOccurrence.start_dt, db.Date) - date.today() return days_until_occurrence == notification_before_days
def get_room_events(room, start_dt, end_dt, repeat_frequency, repeat_interval): occurrences = ReservationOccurrence.create_series( start_dt, end_dt, (repeat_frequency, repeat_interval)) excluded_categories = rb_settings.get('excluded_categories') return (Event.query.filter( ~Event.is_deleted, Event.own_room == room, db.or_( Event.happens_between(as_utc(occ.start_dt), as_utc(occ.end_dt)) for occ in occurrences), Event.timezone == config.DEFAULT_TIMEZONE, db.and_(Event.category_id != cat['id'] for cat in excluded_categories), Event.acl_entries.any( db.and_(EventPrincipal.type == PrincipalType.user, EventPrincipal.user_id == session.user.id, EventPrincipal.full_access))).all())
def is_booking_start_within_grace_period(start_dt, user, allow_admin=False): if allow_admin and rb_is_admin(user): return True default_tz = pytz.timezone(config.DEFAULT_TIMEZONE) start_dt_localized = default_tz.localize(start_dt) grace_period = rb_settings.get('grace_period') if grace_period is None: today = server_to_utc(datetime.now()).astimezone(default_tz).date() return start_dt_localized.date() >= today start_dt_utc = start_dt_localized.astimezone(pytz.utc) grace_period = timedelta(hours=grace_period) return start_dt_utc >= now_utc() - grace_period
def is_booking_start_within_grace_period(start_dt, user, allow_admin=False): from indico.modules.rb import rb_settings if allow_admin and rb_is_admin(user): return True default_tz = pytz.timezone(config.DEFAULT_TIMEZONE) start_dt_localized = default_tz.localize(start_dt) grace_period = rb_settings.get('grace_period') if grace_period is None: today = server_to_utc(datetime.now()).astimezone(default_tz).date() return start_dt_localized.date() >= today start_dt_utc = start_dt_localized.astimezone(pytz.utc) grace_period = timedelta(hours=grace_period) return start_dt_utc >= now_utc() - grace_period
def get_matching_events(start_dt, end_dt, repeat_frequency, repeat_interval): """Get events suitable for booking linking. This finds events that overlap with an occurrence of a booking with the given dates where the user is a manager. """ occurrences = ReservationOccurrence.create_series(start_dt, end_dt, (repeat_frequency, repeat_interval)) excluded_categories = rb_settings.get('excluded_categories') return (Event.query .filter(~Event.is_deleted, ~Event.room_reservation_links.any(ReservationLink.reservation.has(Reservation.is_accepted)), db.or_(Event.happens_between(as_utc(occ.start_dt), as_utc(occ.end_dt)) for occ in occurrences), Event.timezone == config.DEFAULT_TIMEZONE, db.and_(Event.category_id != cat.id for cat in excluded_categories), Event.acl_entries.any(db.and_(EventPrincipal.type == PrincipalType.user, EventPrincipal.user_id == session.user.id, EventPrincipal.full_access))) .all())
def _process(self): room = self._reservation.room form = ModifyBookingForm(obj=self._reservation, old_start_dt=self._reservation.start_dt, old_end_dt=self._reservation.end_dt) form.used_equipment.query = room.find_available_vc_equipment() if not room.notification_for_assistance and not self._reservation.needs_assistance: del form.needs_assistance invalid_form = form.is_submitted() and not form.validate() if invalid_form: occurrences = {} candidates = {} conflicts = {} pre_conflicts = {} else: occurrences, candidates = self._get_all_occurrences([room.id], form, reservation_id=self._reservation.id) conflicts, pre_conflicts = self._get_all_conflicts(room, form, self._reservation.id) if form.validate_on_submit() and not form.submit_check.data: try: booking_limit_days = room.booking_limit_days or rb_settings.get('booking_limit') if not self._validate_room_booking_limit(form, booking_limit_days): msg = (_(u'Bookings for the room "{}" may not be longer than {} days') .format(room.name, booking_limit_days)) return jsonify(success=False, url=url_for('rooms.roomBooking-modifyBookingForm', self._reservation), msg=msg) self._reservation.modify(form.data, session.user) flash(_(u'Booking updated'), 'success') except NoReportError as e: db.session.rollback() return jsonify(success=False, msg=unicode(e)) return jsonify(success=True, url=self._get_success_url()) elif invalid_form and not form.submit_check.data and request.is_xhr: return jsonify(success=False, msg='\n'.join(form.error_list)) return self._get_view(form=form, room=room, rooms=Room.find_all(), occurrences=occurrences, candidates=candidates, conflicts=conflicts, pre_conflicts=pre_conflicts, start_dt=form.start_dt.data, end_dt=form.end_dt.data, only_conflicts=False, repeat_frequency=form.repeat_frequency.data, repeat_interval=form.repeat_interval.data, reservation=self._reservation, can_override=room.can_be_overridden(session.user)).display()
def _process(self): room = self._room rooms = Room.find_all() form = self._make_form() if form.is_submitted() and not form.validate(): occurrences = {} candidates = {} conflicts = {} pre_conflicts = {} only_conflicts = False else: occurrences, candidates = self._get_all_occurrences([self._room.id], form) conflicts, pre_conflicts = self._get_all_conflicts(self._room, form) candidate_days = {occ.date for candidate in candidates.itervalues() for occ in candidate} conflicting_days = {occ.date for occ in conflicts.iterkeys()} only_conflicts = candidate_days <= conflicting_days if form.validate_on_submit() and not form.submit_check.data: booking_limit_days = room.booking_limit_days or rb_settings.get('booking_limit') if not self._validate_room_booking_limit(form, booking_limit_days): msg = (_(u'Bookings for the room "{}" may not be longer than {} days') .format(room.name, booking_limit_days)) return jsonify(success=False, url=url_for('rooms.room_book', room), msg=msg) return self._create_booking_response(form, room) can_override = room.can_be_overridden(session.user) return self._get_view(form=form, room=room, rooms=rooms, occurrences=occurrences, candidates=candidates, conflicts=conflicts, only_conflicts=only_conflicts, pre_conflicts=pre_conflicts, start_dt=form.start_dt.data, end_dt=form.end_dt.data, repeat_frequency=form.repeat_frequency.data, repeat_interval=form.repeat_interval.data, can_override=can_override, past_date=not form.is_submitted() and self.past_date, date_changed=not form.is_submitted() and self.date_changed).display()
def _process(self): if not request.is_xhr: return redirect(url_for_index(_anchor='create-event:{}'.format(self.event_type.name))) form_cls = LectureCreationForm if self.event_type == EventType.lecture else EventCreationForm form = form_cls(obj=self._get_form_defaults(), prefix='event-creation-') if form.validate_on_submit(): if self.event_type == EventType.lecture: events = self._create_series(form.data) event = events[0] if len(events) > 1: flash(Markup(render_template('events/series_created_msg.html', events=events)), 'info') notify_event_creation(event, occurrences=events) else: event = self._create_event(form.data) notify_event_creation(event) return jsonify_data(flash=False, redirect=url_for('event_management.settings', event)) check_room_availability = rb_check_user_access(session.user) and config.ENABLE_ROOMBOOKING rb_excluded_categories = [c.id for c in rb_settings.get('excluded_categories')] return jsonify_template('events/forms/event_creation_form.html', form=form, fields=form._field_order, event_type=self.event_type.name, single_category=self.single_category, check_room_availability=check_room_availability, rb_excluded_categories=rb_excluded_categories)
def search_for_rooms(filters, allow_admin=False, availability=None): """Search for a room, using the provided filters. :param filters: The filters, provided as a dictionary :param allow_admin: A boolean specifying whether admins have override privileges :param availability: A boolean specifying whether (un)available rooms should be provided, or `None` in case all rooms should be returned. """ query = ( Room.query.outerjoin( favorite_room_table, db.and_( favorite_room_table.c.user_id == session.user.id, favorite_room_table.c.room_id == Room.id)).reset_joinpoint( ) # otherwise filter_by() would apply to the favorite table .options(joinedload('owner').load_only('id')).filter( ~Room.is_deleted).order_by(favorite_room_table.c.user_id.is_(None), db.func.indico.natsort(Room.full_name))) criteria = {} if 'capacity' in filters: query = query.filter(Room.capacity >= filters['capacity']) if 'building' in filters: criteria['building'] = filters['building'] if 'division' in filters: criteria['division'] = filters['division'] query = query.filter_by(**criteria) if 'text' in filters: text = ' '.join(filters['text'].strip().split()) if text.startswith('#') and text[1:].isdigit(): query = query.filter(Room.id == int(text[1:])) else: query = query.filter(_make_room_text_filter(text)) if filters.get('equipment'): subquery = (db.session.query(RoomEquipmentAssociation).with_entities( db.func.count(RoomEquipmentAssociation.c.room_id)).filter( RoomEquipmentAssociation.c.room_id == Room.id, EquipmentType.name.in_(filters['equipment'])).join( EquipmentType, RoomEquipmentAssociation.c.equipment_id == EquipmentType.id).correlate(Room).as_scalar()) query = query.filter(subquery == len(filters['equipment'])) if filters.get('features'): for feature in filters['features']: query = query.filter( Room.available_equipment.any( EquipmentType.features.any(RoomFeature.name == feature))) if filters.get('favorite'): query = query.filter(favorite_room_table.c.user_id.isnot(None)) if filters.get('mine'): ids = get_managed_room_ids(session.user) query = query.filter(Room.id.in_(ids)) query = _filter_coordinates(query, filters) if availability is None: return query start_dt, end_dt = filters['start_dt'], filters['end_dt'] repeatability = (filters['repeat_frequency'], filters['repeat_interval']) availability_filters = [ Room.filter_available(start_dt, end_dt, repeatability, include_blockings=False, include_pre_bookings=False) ] if not (allow_admin and rb_is_admin(session.user)): selected_period_days = (filters['end_dt'] - filters['start_dt']).days booking_limit_days = db.func.coalesce(Room.booking_limit_days, rb_settings.get('booking_limit')) criterion = db.and_( Room.filter_bookable_hours(start_dt.time(), end_dt.time()), Room.filter_nonbookable_periods(start_dt, end_dt), db.or_(booking_limit_days.is_(None), selected_period_days <= booking_limit_days)) unbookable_ids = [ room.id for room in query.filter(db.and_( *availability_filters), ~criterion) if not room.can_override(session.user, allow_admin=False) ] availability_filters.append(~Room.id.in_(unbookable_ids)) availability_criterion = db.and_(*availability_filters) if availability is False: availability_criterion = ~availability_criterion return query.filter(availability_criterion)
def _process(self): return jsonify(rooms_sprite_token=unicode(_cache.get('rooms-sprite-token', '')), languages=get_all_locales(), tileserver_url=rb_settings.get('tileserver_url'))
def _skip_admin_check(self): # GET on this endpoint does not expose anything sensitive, so # we allow any room manager to use it if they can edit rooms return request.method == 'GET' and rb_settings.get( 'managers_edit_rooms') and has_managed_rooms(session.user)
def search_for_rooms(filters, allow_admin=False, availability=None): """Search for a room, using the provided filters. :param filters: The filters, provided as a dictionary :param allow_admin: A boolean specifying whether admins have override privileges :param availability: A boolean specifying whether (un)available rooms should be provided, or `None` in case all rooms should be returned. """ query = (Room.query .outerjoin(favorite_room_table, db.and_(favorite_room_table.c.user_id == session.user.id, favorite_room_table.c.room_id == Room.id)) .reset_joinpoint() # otherwise filter_by() would apply to the favorite table .options(joinedload('owner').load_only('id')) .filter(~Room.is_deleted) .order_by(favorite_room_table.c.user_id.is_(None), db.func.indico.natsort(Room.full_name))) criteria = {} if 'capacity' in filters: query = query.filter(Room.capacity >= filters['capacity']) if 'building' in filters: criteria['building'] = filters['building'] if 'division' in filters: criteria['division'] = filters['division'] query = query.filter_by(**criteria) if 'text' in filters: text = ' '.join(filters['text'].strip().split()) query = query.filter(_make_room_text_filter(text)) if filters.get('equipment'): subquery = (db.session.query(RoomEquipmentAssociation) .with_entities(db.func.count(RoomEquipmentAssociation.c.room_id)) .filter( RoomEquipmentAssociation.c.room_id == Room.id, EquipmentType.name.in_(filters['equipment']) ) .join(EquipmentType, RoomEquipmentAssociation.c.equipment_id == EquipmentType.id) .correlate(Room) .as_scalar()) query = query.filter(subquery == len(filters['equipment'])) if filters.get('features'): for feature in filters['features']: query = query.filter(Room.available_equipment.any(EquipmentType.features.any(RoomFeature.name == feature))) if filters.get('favorite'): query = query.filter(favorite_room_table.c.user_id.isnot(None)) if filters.get('mine'): ids = get_managed_room_ids(session.user) query = query.filter(Room.id.in_(ids)) query = _filter_coordinates(query, filters) if availability is None: return query start_dt, end_dt = filters['start_dt'], filters['end_dt'] repeatability = (filters['repeat_frequency'], filters['repeat_interval']) availability_filters = [Room.filter_available(start_dt, end_dt, repeatability, include_blockings=False, include_pre_bookings=True)] if not (allow_admin and rb_is_admin(session.user)): selected_period_days = (filters['end_dt'] - filters['start_dt']).days booking_limit_days = db.func.coalesce(Room.booking_limit_days, rb_settings.get('booking_limit')) criterion = db.and_(Room.filter_bookable_hours(start_dt.time(), end_dt.time()), Room.filter_nonbookable_periods(start_dt, end_dt), db.or_(booking_limit_days.is_(None), selected_period_days <= booking_limit_days)) unbookable_ids = [room.id for room in query.filter(db.and_(*availability_filters), ~criterion) if not room.can_override(session.user, allow_admin=False)] availability_filters.append(~Room.id.in_(unbookable_ids)) availability_criterion = db.and_(*availability_filters) if availability is False: availability_criterion = ~availability_criterion return query.filter(availability_criterion)
def search_for_rooms(filters, availability=None): """Search for a room, using the provided filters. :param filters: The filters, provided as a dictionary :param availability: A boolean specifying whether (un)available rooms should be provided, or `None` in case all rooms should be returned. """ query = (Room.query .outerjoin(favorite_room_table, db.and_(favorite_room_table.c.user_id == session.user.id, favorite_room_table.c.room_id == Room.id)) .reset_joinpoint() # otherwise filter_by() would apply to the favorite table .options(raiseload('owner')) .filter(Room.is_active) .order_by(favorite_room_table.c.user_id.is_(None), db.func.indico.natsort(Room.full_name))) criteria = {} if 'capacity' in filters: query = query.filter(Room.capacity >= filters['capacity']) if 'building' in filters: criteria['building'] = filters['building'] if 'floor' in filters: criteria['floor'] = filters['floor'] if 'division' in filters: criteria['division'] = filters['division'] query = query.filter_by(**criteria) if 'text' in filters: query = query.filter(_make_room_text_filter(filters['text'])) if filters.get('equipment'): subquery = (db.session.query(RoomEquipmentAssociation) .with_entities(db.func.count(RoomEquipmentAssociation.c.room_id)) .filter( RoomEquipmentAssociation.c.room_id == Room.id, EquipmentType.name.in_(filters['equipment']) ) .join(EquipmentType, RoomEquipmentAssociation.c.equipment_id == EquipmentType.id) .correlate(Room) .as_scalar()) query = query.filter(subquery == len(filters['equipment'])) if filters.get('favorite'): query = query.filter(favorite_room_table.c.user_id.isnot(None)) if filters.get('mine'): ids = get_managed_room_ids(session.user) if ids: query = query.filter(Room.id.in_(ids)) query = _filter_coordinates(query, filters) if availability is None: return query start_dt, end_dt = filters['start_dt'], filters['end_dt'] repeatability = (filters['repeat_frequency'], filters['repeat_interval']) availability_query = Room.filter_available(start_dt, end_dt, repeatability, include_pre_bookings=True, include_pending_blockings=True) if availability is False: availability_query = ~availability_query query = query.filter(availability_query) if not rb_is_admin(session.user): selected_period_days = (filters['end_dt'] - filters['start_dt']).days booking_limit_days = db.func.coalesce(Room.booking_limit_days, rb_settings.get('booking_limit')) own_rooms = [r.id for r in Room.get_owned_by(session.user)] query = query.filter(db.or_(Room.id.in_(own_rooms) if own_rooms else False, db.and_(Room.filter_bookable_hours(start_dt.time(), end_dt.time()), Room.filter_nonbookable_periods(start_dt, end_dt), db.or_(booking_limit_days.is_(None), selected_period_days <= booking_limit_days)))) return query
def _skip_admin_check(self): return rb_settings.get('managers_edit_rooms') and self.room.can_manage( session.user)
def _getPageContent(self, params): params['serializable_rooms'] = _get_serializable_rooms([r.id for r in params['rooms']]) params['booking_limit'] = rb_settings.get('booking_limit') return WTemplated('RoomBookingNewBookingSelectRoom').getHTML(params)