Beispiel #1
0
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
        )
Beispiel #2
0
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
        ))
Beispiel #3
0
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
Beispiel #4
0
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()
Beispiel #5
0
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()
Beispiel #6
0
    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)
Beispiel #7
0
    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)
Beispiel #8
0
 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)
Beispiel #9
0
    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()
Beispiel #10
0
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
Beispiel #11
0
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
Beispiel #12
0
    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)
Beispiel #13
0
    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)
Beispiel #14
0
    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)
Beispiel #15
0
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
Beispiel #16
0
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
Beispiel #17
0
    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()
Beispiel #18
0
    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()
Beispiel #19
0
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()
Beispiel #20
0
    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)
Beispiel #21
0
 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)
Beispiel #22
0
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()
Beispiel #23
0
    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)
Beispiel #24
0
 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)
Beispiel #25
0
    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)
Beispiel #26
0
 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
Beispiel #27
0
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
Beispiel #28
0
 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)
Beispiel #29
0
    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()
Beispiel #30
0
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())
Beispiel #31
0
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()
Beispiel #32
0
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
Beispiel #33
0
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())
Beispiel #34
0
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
Beispiel #35
0
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
Beispiel #36
0
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())
Beispiel #37
0
    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()
Beispiel #38
0
    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()
Beispiel #39
0
 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)
Beispiel #40
0
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)
Beispiel #41
0
 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'))
Beispiel #42
0
 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)
Beispiel #43
0
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)
Beispiel #44
0
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
Beispiel #45
0
 def _skip_admin_check(self):
     return rb_settings.get('managers_edit_rooms') and self.room.can_manage(
         session.user)
Beispiel #46
0
 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)