Exemple #1
0
    def _filter_list_entries(self, query, filters):
        if not (filters.get('fields') or filters.get('items')):
            return query
        field_types = {str(f.id): f.field_impl for f in self.regform.form_items
                       if f.is_field and not f.is_deleted and (f.parent_id is None or not f.parent.is_deleted)}
        field_filters = {field_id: data_list
                         for field_id, data_list in filters['fields'].iteritems()
                         if field_id in field_types}
        if not field_filters and not filters['items']:
            return query
        criteria = [db.and_(RegistrationFormFieldData.field_id == field_id,
                            field_types[field_id].create_sql_filter(data_list))
                    for field_id, data_list in field_filters.iteritems()]
        items_criteria = []
        if 'checked_in' in filters['items']:
            checked_in_values = filters['items']['checked_in']
            # If both values 'true' and 'false' are selected, there's no point in filtering
            if len(checked_in_values) == 1:
                items_criteria.append(Registration.checked_in == bool(int(checked_in_values[0])))

        if 'state' in filters['items']:
            states = [RegistrationState(int(state)) for state in filters['items']['state']]
            items_criteria.append(Registration.state.in_(states))

        if field_filters:
                subquery = (RegistrationData.query
                            .with_entities(db.func.count(RegistrationData.registration_id))
                            .join(RegistrationData.field_data)
                            .filter(RegistrationData.registration_id == Registration.id)
                            .filter(db.or_(*criteria))
                            .correlate(Registration)
                            .as_scalar())
                query = query.filter(subquery == len(field_filters))
        return query.filter(db.or_(*items_criteria))
Exemple #2
0
    def filter_report_entries(self, query, filters):
        if not filters.get('items'):
            return query
        criteria = []
        if 'status' in filters['items']:
            filtered_statuses = filters['items']['status']
            status_criteria = []
            if 'scheduled' in filtered_statuses:
                status_criteria.append(Contribution.is_scheduled)
            if 'unscheduled' in filtered_statuses:
                status_criteria.append(~Contribution.is_scheduled)
            if status_criteria:
                criteria.append(db.or_(*status_criteria))

        filter_cols = {'session': Contribution.session_id,
                       'track': Contribution.track_id,
                       'type': Contribution.type_id}
        for key, column in filter_cols.iteritems():
            ids = set(filters['items'].get(key, ()))
            if not ids:
                continue
            column_criteria = []
            if None in ids:
                column_criteria.append(column.is_(None))
            if ids - {None}:
                column_criteria.append(column.in_(ids - {None}))
            criteria.append(db.or_(*column_criteria))
        return query.filter(*criteria)
Exemple #3
0
    def _process(self):
        page = int(request.args.get('page', 1))
        filters = request.args.getlist('filters')
        text = request.args.get('q')

        if not filters:
            return jsonify(current_page=1, pages=[], entries=[], total_page_count=0)

        query = self.event.log_entries.order_by(EventLogEntry.logged_dt.desc())
        realms = {EventLogRealm.get(f) for f in filters if EventLogRealm.get(f)}
        if realms:
            query = query.filter(EventLogEntry.realm.in_(realms))

        if text:
            query = query.filter(
                db.or_(_contains(EventLogEntry.module, text),
                       _contains(EventLogEntry.type, text),
                       _contains(EventLogEntry.summary, text),
                       _contains(db.m.User.first_name + " " + db.m.User.last_name, text),
                       _contains(EventLogEntry.data['body'].astext, text),
                       _contains(EventLogEntry.data['subject'].astext, text),
                       _contains(EventLogEntry.data['from'].astext, text),
                       _contains(EventLogEntry.data['to'].astext, text),
                       _contains(EventLogEntry.data['cc'].astext, text))
            ).outerjoin(db.m.User)

        query = query.paginate(page, LOG_PAGE_SIZE)
        entries = [dict(serialize_log_entry(entry), index=index, html=entry.render())
                   for index, entry in enumerate(query.items)]
        return jsonify(current_page=page, pages=list(query.iter_pages()), total_page_count=query.pages, entries=entries)
Exemple #4
0
def _bookings_query(filters):
    reservation_strategy = contains_eager('reservation')
    reservation_strategy.noload('room')
    reservation_strategy.noload('booked_for_user')
    reservation_strategy.noload('created_by_user')

    query = (ReservationOccurrence.query
             .join(Reservation)
             .join(Room)
             .filter(~Room.is_deleted)
             .options(reservation_strategy))

    if filters.get('room_ids'):
        query = query.filter(Room.id.in_(filters['room_ids']))
    if filters.get('start_dt'):
        query = query.filter(ReservationOccurrence.start_dt >= filters['start_dt'])
    if filters.get('end_dt'):
        query = query.filter(ReservationOccurrence.end_dt <= filters['end_dt'])

    booked_for_user = filters.get('booked_for_user')
    if booked_for_user:
        query = query.filter(db.or_(Reservation.booked_for_user == booked_for_user,
                                    Reservation.created_by_user == booked_for_user))

    if not filters.get('include_inactive'):
        query = query.filter(ReservationOccurrence.is_valid)

    return query
Exemple #5
0
 def __init__(self, *args, **kwargs):
     self.event = kwargs.pop('event')
     self.abstract = kwargs.pop('abstract', None)
     management = kwargs.pop('management', False)
     description_settings = abstracts_settings.get(self.event, 'description_settings')
     description_validators = self._get_description_validators(description_settings)
     if description_validators:
         inject_validators(self, 'description', description_validators)
     if abstracts_settings.get(self.event, 'contrib_type_required'):
         inject_validators(self, 'submitted_contrib_type', [DataRequired()])
     super(AbstractForm, self).__init__(*args, **kwargs)
     if management:
         self.submitted_contrib_type.query = (self.event.contribution_types
                                              .order_by(db.func.lower(ContributionType.name)))
     else:
         criteria = [~ContributionType.is_private]
         if self.abstract and self.abstract.submitted_contrib_type:
             criteria.append(ContributionType.id == self.abstract.submitted_contrib_type.id)
         self.submitted_contrib_type.query = (self.event.contribution_types
                                              .filter(db.or_(*criteria))
                                              .order_by(db.func.lower(ContributionType.name)))
     if not self.submitted_contrib_type.query.count():
         del self.submitted_contrib_type
     if not self.event.cfa.allow_attachments:
         del self.attachments
     if not description_settings['is_active']:
         del self.description
     self.person_links.require_speaker_author = abstracts_settings.get(self.event, 'speakers_required')
     self.person_links.allow_speakers = abstracts_settings.get(self.event, 'allow_speakers')
Exemple #6
0
def get_user_abstracts(event, user):
    """Get the list of abstracts where the user is a reviewer/convener"""
    return (Abstract.query.with_parent(event)
            .options(joinedload('reviews'),
                     joinedload('person_links'))
            .filter(db.or_(Abstract.submitter == user,
                           Abstract.person_links.any(AbstractPersonLink.person.has(user=user))))
            .order_by(Abstract.friendly_id)
            .all())
Exemple #7
0
def get_not_deletable_templates(obj):
    """Get all non-deletable templates for an event/category"""

    not_deletable_criteria = [
        DesignerTemplate.is_system_template,
        DesignerTemplate.backside_template_of != None,  # noqa
        DesignerTemplate.ticket_for_regforms.any(RegistrationForm.event.has(Event.ends_after(now_utc())))
    ]
    return set(DesignerTemplate.query.filter(DesignerTemplate.owner == obj, db.or_(*not_deletable_criteria)))
Exemple #8
0
    def _filter_list_entries(self, query, filters):
        if not filters.get('items'):
            return query
        criteria = []
        if 'state' in filters['items']:
            filtered_states = filters['items']['state']
            state_criteria = []
            for filter_state in filtered_states:
                if filter_state is None:
                    state_criteria.append(~Contribution._paper_last_revision.has())
                else:
                    state_criteria.append(Contribution._paper_last_revision
                                          .has(PaperRevision.state == int(filter_state)))
            if state_criteria:
                criteria.append(db.or_(*state_criteria))

        if 'unassigned' in filters['items']:
            role_map = {
                PaperReviewingRole.judge.value: Contribution.paper_judges,
                PaperReviewingRole.content_reviewer.value: Contribution.paper_content_reviewers,
                PaperReviewingRole.layout_reviewer.value: Contribution.paper_layout_reviewers,
            }
            filtered_roles = map(PaperReviewingRole, map(int, filters['items']['unassigned']))
            unassigned_criteria = [~role_map[role.value].any() for role in filtered_roles
                                   if (role == PaperReviewingRole.judge or
                                       self.event.cfp.get_reviewing_state(role.review_type))]
            if unassigned_criteria:
                criteria.append(db.or_(*unassigned_criteria))

        filter_cols = {'track': Contribution.track_id,
                       'session': Contribution.session_id,
                       'type': Contribution.type_id}
        for key, column in filter_cols.iteritems():
            ids = set(filters['items'].get(key, ()))
            if not ids:
                continue
            column_criteria = []
            if None in ids:
                column_criteria.append(column.is_(None))
            if ids - {None}:
                column_criteria.append(column.in_(ids - {None}))
            criteria.append(db.or_(*column_criteria))

        return query.filter(*criteria)
Exemple #9
0
 def _process(self):
     q = (ReservationOccurrence.query
          .filter(ReservationOccurrence.start_dt > utc_to_server(now_utc()),
                  db.or_(
                      Reservation.booked_for_user == session.user,
                      Reservation.created_by_user == session.user))
          .join(Reservation)
          .order_by(ReservationOccurrence.start_dt.asc())
          .limit(5))
     return jsonify(reservation_occurrences_schema.dump(q).data)
Exemple #10
0
    def _filter_list_entries(self, query, filters):
        criteria = []
        field_filters = filters.get('fields')
        item_filters = filters.get('items')
        extra_filters = filters.get('extra')

        if not (field_filters or item_filters or extra_filters):
            return query

        if field_filters:
            for contribution_type_id, field_values in field_filters.iteritems():
                criteria.append(Abstract.field_values.any(db.and_(
                    AbstractFieldValue.contribution_field_id == contribution_type_id,
                    AbstractFieldValue.data.op('#>>')('{}').in_(field_values)
                )))

        if item_filters:
            static_filters = {
                'accepted_track': Abstract.accepted_track_id,
                'accepted_contrib_type': Abstract.accepted_contrib_type_id,
                'submitted_contrib_type': Abstract.submitted_contrib_type_id,
                'submitted_for_tracks': Abstract.submitted_for_tracks,
                'reviewed_for_tracks': Abstract.reviewed_for_tracks
            }
            for key, column in static_filters.iteritems():
                ids = set(item_filters.get(key, ()))
                if not ids:
                    continue
                column_criteria = []
                if '_for_tracks' in key:
                    if None in ids:
                        column_criteria.append(~column.any())
                        ids.discard(None)
                    if ids:
                        column_criteria.append(column.any(Track.id.in_(ids)))
                else:
                    if None in ids:
                        column_criteria.append(column.is_(None))
                        ids.discard(None)
                    if ids:
                        column_criteria.append(column.in_(ids))
                criteria.append(db.or_(*column_criteria))
            if 'state' in item_filters:
                states = [AbstractState(int(state)) for state in item_filters['state']]
                criteria.append(Abstract.state.in_(states))
        if extra_filters:
            if extra_filters.get('multiple_tracks'):
                submitted_for_count = (db.select([db.func.count()])
                                       .as_scalar()
                                       .where(Abstract.submitted_for_tracks.prop.primaryjoin))
                criteria.append(submitted_for_count > 1)
            if extra_filters.get('comments'):
                criteria.append(Abstract.submission_comment != '')
        return query.filter(db.and_(*criteria))
Exemple #11
0
    def _filter_by_sessions(self, session_ids, added_since):
        sid_query = Contribution.session_id.in_(set(session_ids))
        session_query = db.and_(AttachmentFolder.link_type == LinkType.session,
                                AttachmentFolder.session.has(Session.id.in_(session_ids) & ~Session.is_deleted))
        contrib_query = db.and_(AttachmentFolder.link_type == LinkType.contribution,
                                AttachmentFolder.contribution.has(sid_query & ~Contribution.is_deleted))
        subcontrib_query = db.and_(AttachmentFolder.link_type == LinkType.subcontribution,
                                   AttachmentFolder.subcontribution.has(
                                       sid_query & ~SubContribution.is_deleted & ~Contribution.is_deleted))

        return self._build_base_query(added_since).filter(db.or_(session_query, contrib_query, subcontrib_query)).all()
Exemple #12
0
 def visible_categories_cte(self):
     """
     Get a sqlalchemy select for the visible categories within
     this category, including the category itself.
     """
     cte_query = (select([Category.id, literal(0).label('level')])
                  .where((Category.id == self.id) & (Category.visibility.is_(None) | (Category.visibility > 0)))
                  .cte('visibility_chain', recursive=True))
     parent_query = (select([Category.id, cte_query.c.level + 1])
                     .where(db.and_(Category.parent_id == cte_query.c.id,
                                    db.or_(Category.visibility.is_(None),
                                           Category.visibility > cte_query.c.level + 1))))
     return cte_query.union_all(parent_query)
Exemple #13
0
def _query_managed_rooms(user):
    # We can get a list of all groups for the user
    iterator = chain.from_iterable(multipass.identity_providers[x.provider].get_identity_groups(x.identifier)
                                   for x in user.identities)
    groups = {(g.provider.name, g.name) for g in iterator}
    # XXX: refactor this once we have a proper ACL for rooms
    if multipass.default_group_provider:
        groups = {name for provider, name in groups if provider == multipass.default_group_provider.name}
    else:
        groups = {unicode(group.id) for group in user.local_groups}
    attrs = [db.cast(x, JSONB) for x in groups]
    is_manager = Room.attributes.any(db.cast(RoomAttributeAssociation.value, JSONB).in_(attrs))
    return Room.query.filter(Room.is_active, db.or_(Room.owner == user, is_manager))
Exemple #14
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())
Exemple #15
0
 def _process(self):
     regforms = self.event_new.registration_forms.filter(~RegistrationForm.is_deleted)
     if session.user:
         criteria = db.or_(
             RegistrationForm.is_scheduled,
             RegistrationForm.registrations.any((Registration.user == session.user) & Registration.is_active),
         )
     else:
         criteria = RegistrationForm.is_scheduled
     regforms = regforms.filter(criteria).order_by(db.func.lower(RegistrationForm.title)).all()
     if len(regforms) == 1:
         return redirect(url_for('.display_regform', regforms[0]))
     return self.view_class.render_template('display/regform_list.html', self.event, event=self.event,
                                            regforms=regforms)
Exemple #16
0
def _query_managed_rooms(user):
    criteria = [db.and_(RoomPrincipal.type == PrincipalType.user,
                        RoomPrincipal.user_id == user.id,
                        RoomPrincipal.has_management_permission())]
    for group in user.local_groups:
        criteria.append(db.and_(RoomPrincipal.type == PrincipalType.local_group,
                                RoomPrincipal.local_group_id == group.id,
                                RoomPrincipal.has_management_permission()))
    for group in user.iter_all_multipass_groups():
        criteria.append(db.and_(RoomPrincipal.type == PrincipalType.multipass_group,
                                RoomPrincipal.multipass_group_provider == group.provider.name,
                                db.func.lower(RoomPrincipal.multipass_group_name) == group.name.lower(),
                                RoomPrincipal.has_management_permission()))
    return Room.query.filter(~Room.is_deleted, Room.acl_entries.any(db.or_(*criteria)))
Exemple #17
0
def _filter_registration(regform, query, filters):
    if not filters["fields"] and not filters["items"]:
        return query

    field_types = {
        f.id: f.field_impl
        for f in regform.form_items
        if f.is_field and not f.is_deleted and (f.parent_id is None or not f.parent.is_deleted)
    }
    criteria = [
        db.and_(RegistrationFormFieldData.field_id == field_id, field_types[field_id].create_sql_filter(data_list))
        for field_id, data_list in filters["fields"].iteritems()
    ]

    items_criteria = []
    if "checked_in" in filters["items"]:
        checked_in_values = filters["items"]["checked_in"]
        # If both values 'true' and 'false' are selected, there's no point in filtering
        if len(checked_in_values) == 1:
            items_criteria.append(Registration.checked_in == bool(int(checked_in_values[0])))

    if "state" in filters["items"]:
        states = [RegistrationState(int(state)) for state in filters["items"]["state"]]
        items_criteria.append(Registration.state.in_(states))

    if filters["fields"]:
        subquery = (
            RegistrationData.query.with_entities(db.func.count(RegistrationData.registration_id))
            .join(RegistrationData.field_data)
            .filter(RegistrationData.registration_id == Registration.id)
            .filter(db.or_(*criteria))
            .correlate(Registration)
            .as_scalar()
        )
        query = query.filter(subquery == len(filters["fields"]))
    return query.filter(db.or_(*items_criteria))
Exemple #18
0
def get_active_bookings(limit, start_dt, last_reservation_id=None, **filters):
    criteria = [ReservationOccurrence.start_dt > start_dt]
    if last_reservation_id is not None:
        criteria.append(db.and_(db.cast(ReservationOccurrence.start_dt, db.Date) >= start_dt,
                                ReservationOccurrence.reservation_id > last_reservation_id))

    query = (_bookings_query(filters)
             .filter(db.or_(*criteria))
             .order_by(ReservationOccurrence.start_dt,
                       ReservationOccurrence.reservation_id,
                       db.func.indico.natsort(Room.full_name))
             .limit(limit))

    bookings, total = with_total_rows(query)
    rows_left = total - limit if total > limit else total
    return group_by_occurrence_date(query, sort_by=lambda obj: (obj.start_dt, obj.reservation_id)), rows_left
 def get_visible_categories_cte(category_id):
     """
     Get a sqlalchemy select for the visible categories within
     the given category, including the category itself.
     """
     cte_query = (select([
         Category.id, literal(0).label('level')
     ]).where((Category.id == category_id)
              & (Category.visibility.is_(None)
                 | (Category.visibility > 0))).cte(recursive=True))
     parent_query = (select([Category.id, cte_query.c.level + 1]).where(
         db.and_(
             Category.parent_id == cte_query.c.id,
             db.or_(Category.visibility.is_(None),
                    Category.visibility > cte_query.c.level + 1))))
     return cte_query.union_all(parent_query)
Exemple #20
0
    def has_conflict(self):
        """Check if there are other valid registrations for the same user.

        This is intended for cases where this registration is currenly invalid
        (rejected or withdrawn) to determine whether it would be acceptable to
        restore it.
        """
        conflict_criteria = [Registration.email == self.email]
        if self.user_id is not None:
            conflict_criteria.append(Registration.user_id == self.user_id)
        return (Registration.query.with_parent(self.registration_form).filter(
            Registration.id != self.id, ~Registration.is_deleted,
            db.or_(*conflict_criteria),
            Registration.state.notin_(
                [RegistrationState.rejected,
                 RegistrationState.withdrawn])).has_rows())
Exemple #21
0
def _process_cascaded_event_contents(records, additional_events=None):
    """
    Flatten a series of records into its most basic elements (subcontribution level).

    Yields results.

    :param records: queue records to process
    :param additional_events: events whose content will be included in addition to those
                              found in records
    """
    changed_events = additional_events or set()
    changed_contributions = set()
    changed_subcontributions = set()

    session_records = {rec.session_id for rec in records if rec.type == EntryType.session}
    contribution_records = {rec.contrib_id for rec in records if rec.type == EntryType.contribution}
    subcontribution_records = {rec.subcontrib_id for rec in records if rec.type == EntryType.subcontribution}
    event_records = {rec.event_id for rec in records if rec.type == EntryType.event}

    if event_records:
        changed_events.update(Event.find(Event.id.in_(event_records)))

    for event in changed_events:
        yield event

    # Sessions are added (explicitly changed only, since they don't need to be sent anywhere)
    if session_records:
        changed_contributions.update(Contribution
                                     .find(Contribution.session_id.in_(session_records), ~Contribution.is_deleted))

    # Contributions are added (implictly + explicitly changed)
    changed_event_ids = {ev.id for ev in changed_events}

    condition = Contribution.event_id.in_(changed_event_ids) & ~Contribution.is_deleted
    if contribution_records:
        condition = db.or_(condition, Contribution.id.in_(contribution_records))
    contrib_query = Contribution.find(condition).options(joinedload('subcontributions'))

    for contribution in contrib_query:
        yield contribution
        changed_subcontributions.update(contribution.subcontributions)

    # Same for subcontributions
    if subcontribution_records:
        changed_subcontributions.update(SubContribution.find(SubContribution.id.in_(subcontribution_records)))
    for subcontrib in changed_subcontributions:
        yield subcontrib
Exemple #22
0
    def export_room_vc_list(self, user):
        query = (db.session.query(
            ReservationOccurrence, VCRoomEventAssociation, Event).filter(
                Reservation.room == self.room, ReservationOccurrence.is_valid,
                Reservation.is_accepted,
                db.or_(Event.id.is_(None), ~Event.is_deleted)).options(
                    joinedload('reservation')).join(Reservation).outerjoin(
                        ReservationLink).outerjoin(
                            Event,
                            ReservationLink.event_id == Event.id).outerjoin(
                                VCRoomEventAssociation,
                                Event.id == VCRoomEventAssociation.
                                linked_event_id).outerjoin(VCRoom))

        if self._fromDT is not None:
            query = query.filter(
                ReservationOccurrence.date >= self._fromDT.date())

        if self._toDT is not None:
            query = query.filter(
                ReservationOccurrence.date <= self._toDT.date())

        for occurrence, assoc, event in query:
            vc_data = assoc.vc_room.data if assoc else None
            reservation = occurrence.reservation
            yield {
                'event': {
                    'id': event.id,
                    'title': event.title,
                    'start_dt': event.start_dt.astimezone(self._tz),
                    'end_dt': event.end_dt.astimezone(self._tz),
                    'url': event.external_url
                } if event else None,
                'booking': {
                    'id': reservation.id,
                    'start_dt': occurrence.start_dt,
                    'end_dt': occurrence.end_dt,
                    'url': reservation.external_details_url,
                    'creator': reservation.created_by_user.full_name
                },
                'vc_room': {
                    'url': vc_data['url'],
                    'vidyo_id': vc_data['vidyo_id'],
                    'description': vc_data['description'],
                    'extension': assoc.vc_room.vidyo_extension.extension
                } if vc_data else None
            }
Exemple #23
0
    def _process(self):
        page = int(request.args.get('page', 1))
        filters = request.args.getlist('filters')
        metadata_query = _get_metadata_query()
        text = request.args.get('q')

        if not filters and not metadata_query:
            return jsonify(current_page=1,
                           pages=[],
                           entries=[],
                           total_page_count=0)

        query = self.event.log_entries.order_by(EventLogEntry.logged_dt.desc())
        realms = {
            EventLogRealm.get(f)
            for f in filters if EventLogRealm.get(f)
        }
        if realms:
            query = query.filter(EventLogEntry.realm.in_(realms))

        if text:
            query = query.filter(
                db.or_(
                    _contains(EventLogEntry.module, text),
                    _contains(EventLogEntry.type, text),
                    _contains(EventLogEntry.summary, text),
                    _contains(db.m.User.first_name + " " + db.m.User.last_name,
                              text),
                    _contains(EventLogEntry.data['body'].astext, text),
                    _contains(EventLogEntry.data['subject'].astext, text),
                    _contains(EventLogEntry.data['from'].astext, text),
                    _contains(EventLogEntry.data['to'].astext, text),
                    _contains(EventLogEntry.data['cc'].astext,
                              text))).outerjoin(db.m.User)

        if metadata_query:
            query = query.filter(EventLogEntry.meta.contains(metadata_query))

        query = query.paginate(page, LOG_PAGE_SIZE)
        entries = [
            dict(serialize_log_entry(entry), index=index, html=entry.render())
            for index, entry in enumerate(query.items)
        ]
        return jsonify(current_page=page,
                       pages=list(query.iter_pages()),
                       total_page_count=query.pages,
                       entries=entries)
Exemple #24
0
def get_events_with_paper_roles(user, dt=None):
    """
    Get the IDs and PR roles of events where the user has any kind
    of paper reviewing privileges.

    :param user: A `User`
    :param dt: Only include events taking place on/after that date
    :return: A dict mapping event IDs to a set of roles
    """
    paper_roles = {'paper_manager', 'paper_judge', 'paper_content_reviewer', 'paper_layout_reviewer'}
    role_criteria = [EventPrincipal.has_management_role(role, explicit=True) for role in paper_roles]
    query = (user.in_event_acls
             .join(Event)
             .options(noload('user'), noload('local_group'), load_only('event_id', 'roles'))
             .filter(~Event.is_deleted, Event.ends_after(dt))
             .filter(db.or_(*role_criteria)))
    return {principal.event_id: set(principal.roles) & paper_roles for principal in query}
Exemple #25
0
def get_events_with_paper_roles(user, dt=None):
    """
    Get the IDs and PR roles of events where the user has any kind
    of paper reviewing privileges.

    :param user: A `User`
    :param dt: Only include events taking place on/after that date
    :return: A dict mapping event IDs to a set of roles
    """
    paper_roles = {'paper_manager', 'paper_judge', 'paper_content_reviewer', 'paper_layout_reviewer'}
    role_criteria = [EventPrincipal.has_management_role(role, explicit=True) for role in paper_roles]
    query = (user.in_event_acls
             .join(Event)
             .options(noload('user'), noload('local_group'), load_only('event_id', 'roles'))
             .filter(~Event.is_deleted, Event.ends_after(dt))
             .filter(db.or_(*role_criteria)))
    return {principal.event_id: set(principal.roles) & paper_roles for principal in query}
Exemple #26
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())
Exemple #27
0
    def _filter_by_sessions(self, session_ids, added_since):
        sid_query = Contribution.session_id.in_(set(session_ids))
        session_query = db.and_(
            AttachmentFolder.link_type == LinkType.session,
            AttachmentFolder.session.has(
                Session.id.in_(session_ids) & ~Session.is_deleted))
        contrib_query = db.and_(
            AttachmentFolder.link_type == LinkType.contribution,
            AttachmentFolder.contribution.has(sid_query
                                              & ~Contribution.is_deleted))
        subcontrib_query = db.and_(
            AttachmentFolder.link_type == LinkType.subcontribution,
            AttachmentFolder.subcontribution.has(sid_query
                                                 & ~SubContribution.is_deleted
                                                 & ~Contribution.is_deleted))

        return self._build_base_query(added_since).filter(
            db.or_(session_query, contrib_query, subcontrib_query)).all()
Exemple #28
0
def _query_managed_rooms(user):
    # We can get a list of all groups for the user
    iterator = chain.from_iterable(multipass.identity_providers[
        x.provider].get_identity_groups(x.identifier) for x in user.identities)
    groups = {(g.provider.name, g.name) for g in iterator}
    # XXX: refactor this once we have a proper ACL for rooms
    if multipass.default_group_provider:
        groups = {
            name
            for provider, name in groups
            if provider == multipass.default_group_provider.name
        }
    else:
        groups = {unicode(group.id) for group in user.local_groups}
    attrs = [db.cast(x, JSONB) for x in groups]
    is_manager = Room.attributes.any(
        db.cast(RoomAttributeAssociation.value, JSONB).in_(attrs))
    return Room.query.filter(Room.is_active,
                             db.or_(Room.owner == user, is_manager))
Exemple #29
0
 def __init__(self, *args, **kwargs):
     self.event = kwargs.pop('event')
     self.abstract = kwargs.pop('abstract', None)
     is_invited = kwargs.pop('invited', False)
     management = kwargs.pop('management', False)
     description_settings = abstracts_settings.get(self.event,
                                                   'description_settings')
     description_validators = self._get_description_validators(
         description_settings, invited=is_invited)
     if description_validators:
         inject_validators(self, 'description', description_validators)
     if not is_invited:
         inject_validators(self, 'person_links', [DataRequired()])
     if abstracts_settings.get(self.event, 'contrib_type_required'):
         inject_validators(self, 'submitted_contrib_type', [DataRequired()])
     super(AbstractForm, self).__init__(*args, **kwargs)
     if management:
         self.submitted_contrib_type.query = (
             self.event.contribution_types.order_by(
                 db.func.lower(ContributionType.name)))
     else:
         criteria = [~ContributionType.is_private]
         if self.abstract and self.abstract.submitted_contrib_type:
             criteria.append(ContributionType.id ==
                             self.abstract.submitted_contrib_type.id)
         self.submitted_contrib_type.query = (
             self.event.contribution_types.filter(db.or_(
                 *criteria)).order_by(db.func.lower(ContributionType.name)))
     if not self.submitted_contrib_type.query.count():
         del self.submitted_contrib_type
     if not self.event.cfa.allow_attachments:
         del self.attachments
     if not description_settings['is_active']:
         del self.description
     if not is_invited:
         self.person_links.require_speaker_author = abstracts_settings.get(
             self.event, 'speakers_required')
         self.person_links.allow_speakers = abstracts_settings.get(
             self.event, 'allow_speakers')
         self.person_links.disable_user_search = session.user is None
     else:
         self.person_links.require_primary_author = False
Exemple #30
0
    def run_export_files(self,
                         batch=1000,
                         force=False,
                         max_size=None,
                         verbose=True,
                         initial=False):
        from indico_citadel.plugin import CitadelPlugin

        if max_size is None:
            max_size = CitadelPlugin.settings.get('max_file_size')

        attachments = (CitadelIdMap.query.join(Attachment).join(
            AttachmentFile, Attachment.file_id == AttachmentFile.id
        ).filter(Attachment.type == AttachmentType.file).filter(
            AttachmentFile.size > 0,
            AttachmentFile.size <= max_size * 1024 * 1024).filter(
                db.func.lower(AttachmentFile.extension).in_([
                    s.lower()
                    for s in CitadelPlugin.settings.get('file_extensions')
                ])).options(
                    contains_eager(CitadelIdMap.attachment).contains_eager(
                        Attachment.file)))
        if not force:
            attachments = attachments.filter(
                db.or_(CitadelIdMap.attachment_file_id.is_(None),
                       CitadelIdMap.attachment_file_id != Attachment.file_id))
        uploader = self.uploader(self)
        attachments = attachments.yield_per(batch)
        total = attachments.count()
        if verbose:
            attachments = verbose_iterator(
                attachments,
                total,
                attrgetter('id'),
                lambda obj: re.sub(r'\s+', ' ',
                                   strip_control_chars(obj.attachment.title)),
                print_total_time=True)
        else:
            self.plugin.logger.info(f'{total} files need to be uploaded')
        total, errors, aborted = uploader.upload_files(attachments,
                                                       initial=initial)
        return total, errors, aborted
Exemple #31
0
 def _process(self):
     regforms = self.event_new.registration_forms.filter(
         ~RegistrationForm.is_deleted)
     if session.user:
         criteria = db.or_(
             RegistrationForm.is_scheduled,
             RegistrationForm.registrations.any(
                 (Registration.user == session.user)
                 & Registration.is_active),
         )
     else:
         criteria = RegistrationForm.is_scheduled
     regforms = regforms.filter(criteria).order_by(
         db.func.lower(RegistrationForm.title)).all()
     if len(regforms) == 1:
         return redirect(url_for('.display_regform', regforms[0]))
     return self.view_class.render_template('display/regform_list.html',
                                            self.event,
                                            event=self.event,
                                            regforms=regforms)
Exemple #32
0
def _query_managed_rooms(user):
    criteria = [
        db.and_(RoomPrincipal.type == PrincipalType.user,
                RoomPrincipal.user_id == user.id,
                RoomPrincipal.has_management_permission())
    ]
    for group in user.local_groups:
        criteria.append(
            db.and_(RoomPrincipal.type == PrincipalType.local_group,
                    RoomPrincipal.local_group_id == group.id,
                    RoomPrincipal.has_management_permission()))
    for group in user.iter_all_multipass_groups():
        criteria.append(
            db.and_(
                RoomPrincipal.type == PrincipalType.multipass_group,
                RoomPrincipal.multipass_group_provider == group.provider.name,
                db.func.lower(
                    RoomPrincipal.multipass_group_name) == group.name.lower(),
                RoomPrincipal.has_management_permission()))
    return Room.query.filter(Room.is_active,
                             Room.acl_entries.any(db.or_(*criteria)))
Exemple #33
0
 def _process(self):
     show_booking_warning = False
     if (config.ENABLE_ROOMBOOKING and not self.event.has_ended and self.event.room
             and not self.event.room_reservation_links):
         # Check if any of the managers of the event already have a booking that overlaps with the event datetime
         manager_ids = [p.user.id for p in self.event.acl_entries if p.user]
         has_overlap = (ReservationOccurrence.query
                        .filter(ReservationOccurrence.is_valid,
                                db.or_(Reservation.booked_for_id.in_(manager_ids),
                                       Reservation.created_by_id.in_(manager_ids)),
                                db_dates_overlap(ReservationOccurrence,
                                                 'start_dt', self.event.start_dt_local,
                                                 'end_dt', self.event.end_dt_local),
                                Reservation.room_id == self.event.room.id,
                                ~Room.is_deleted)
                        .join(Reservation)
                        .join(Room)
                        .has_rows())
         show_booking_warning = not has_overlap
     return WPEventSettings.render_template('settings.html', self.event, 'settings',
                                            show_booking_warning=show_booking_warning)
Exemple #34
0
def get_room_blockings(start_dt=None,
                       end_dt=None,
                       created_by=None,
                       in_rooms_owned_by=None):
    query = Blocking.query
    if start_dt and not end_dt:
        query = query.filter(Blocking.is_active_at(start_dt))
    elif start_dt and end_dt:
        query = query.filter(
            db_dates_overlap(Blocking, 'start_date', start_dt, 'end_date',
                             end_dt))

    criteria = []
    if created_by:
        criteria.append(Blocking.created_by_user == created_by)
    if in_rooms_owned_by:
        criteria.append(Room.owner == in_rooms_owned_by)
        query = (query.join(Blocking.blocked_rooms).join(BlockedRoom.room))

    query = query.filter(db.or_(*criteria))
    return query.all()
Exemple #35
0
 def get_members(self):
     from indico.modules.users.models.users import User
     if self.group is None:
         warn(f'Tried to get members for invalid group {self}')
         return set()
     # We actually care about Users, not identities here!
     emails = set()
     identifiers = set()
     for identity_info in self.group:
         identifiers.add(identity_info.identifier)
         emails |= {x.lower() for x in identity_info.data.getlist('email') if x}
     if not identifiers and not emails:
         return set()
     return set(User.query.outerjoin(Identity).filter(
         ~User.is_deleted,
         db.or_(
             User.all_emails.in_(list(emails)),
             db.and_(
                 Identity.provider == self.provider,
                 Identity.identifier.in_(identifiers)
             )
         )))
Exemple #36
0
 def get_members(self):
     from indico.modules.users.models.users import User
     if self.group is None:
         warn('Tried to get members for invalid group {}'.format(self))
         return set()
     # We actually care about Users, not identities here!
     emails = set()
     identifiers = set()
     for identity_info in self.group:
         identifiers.add(identity_info.identifier)
         emails |= {x.lower() for x in identity_info.data.getlist('email') if x}
     if not identifiers and not emails:
         return set()
     return set(User.query.outerjoin(Identity).filter(
         ~User.is_deleted,
         db.or_(
             User.all_emails.contains(db.func.any(list(emails))),
             db.and_(
                 Identity.provider == self.provider,
                 Identity.identifier.in_(identifiers)
             )
         )))
Exemple #37
0
 def __init__(self, edit=False, *args, **kwargs):
     abstract = kwargs.pop('abstract')
     super(AbstractReviewForm, self).__init__(*args, **kwargs)
     self.event = abstract.event
     if not edit:
         self.proposed_action.none = _("Propose an action...")
     self.proposed_related_abstract.excluded_abstract_ids = {abstract.id}
     self.proposed_contribution_type.query = (ContributionType.query
                                              .with_parent(self.event)
                                              .order_by(ContributionType.name))
     if not self.proposed_contribution_type.query.count():
         del self.proposed_contribution_type
     reviewed_for_track_ids = {t.id for t in abstract.reviewed_for_tracks}
     existing_prop_track_cond = (Track.id.in_(t.id for t in self.proposed_tracks.object_data)
                                 if self.proposed_tracks.object_data else False)
     self.proposed_tracks.query = (Track.query
                                   .with_parent(self.event)
                                   .filter(db.or_(Track.id.notin_(reviewed_for_track_ids),
                                                  existing_prop_track_cond))
                                   .order_by(Track.position))
     if not self.proposed_tracks.query.count():
         del self.proposed_tracks
         self.proposed_action.skip.add(AbstractAction.change_tracks)
Exemple #38
0
 def __init__(self, edit=False, *args, **kwargs):
     abstract = kwargs.pop('abstract')
     super(AbstractReviewForm, self).__init__(*args, **kwargs)
     self.event = abstract.event
     if not edit:
         self.proposed_action.none = _("Propose an action...")
     self.proposed_related_abstract.excluded_abstract_ids = {abstract.id}
     self.proposed_contribution_type.query = (ContributionType.query
                                              .with_parent(self.event)
                                              .order_by(ContributionType.name))
     if not self.proposed_contribution_type.query.count():
         del self.proposed_contribution_type
     reviewed_for_track_ids = {t.id for t in abstract.reviewed_for_tracks}
     existing_prop_track_cond = (Track.id.in_(t.id for t in self.proposed_tracks.object_data)
                                 if self.proposed_tracks.object_data else False)
     self.proposed_tracks.query = (Track.query
                                   .with_parent(self.event)
                                   .filter(db.or_(Track.id.notin_(reviewed_for_track_ids),
                                                  existing_prop_track_cond))
                                   .order_by(Track.position))
     if not self.proposed_tracks.query.count():
         del self.proposed_tracks
         self.proposed_action.skip.add(AbstractAction.change_tracks)
Exemple #39
0
def _query_contributions_with_user_as_reviewer(event, user):
    query = Contribution.query.with_parent(event)
    query = query.filter(db.or_(Contribution.paper_content_reviewers.any(User.id == user.id),
                                Contribution.paper_layout_reviewers.any(User.id == user.id)),
                         Contribution._paper_revisions.any())
    return query
Exemple #40
0
def get_non_inheriting_objects(root):
    """Get a set of child objects that do not inherit protection

    :param root: An event object (`Event`, `Session`, `Contribution`
                 or `AttachmentFolder`) which may contain objects
                 with a different protection.
    """
    def _query_folders(obj, crit):
        return (db.m.AttachmentFolder.query.filter_by(
            event_new=obj.event_new,
            is_deleted=False).filter(crit).options(joinedload('attachments')))

    def _process_attachments(folders):
        for folder in folders:
            if not folder.is_inheriting:
                yield folder
            for attachment in folder.attachments:
                if not attachment.is_inheriting:
                    yield attachment

    if isinstance(root, db.m.Event):
        # For an event we check sessions, contributions and ALL attachments no matter where
        for sess in db.m.Session.query.with_parent(root).filter(
                ~db.m.Session.is_inheriting):
            yield _ProtectedObjectWrapper(sess)
        for contrib in db.m.Contribution.query.with_parent(root).filter(
                ~db.m.Contribution.is_inheriting):
            yield _ProtectedObjectWrapper(contrib)
        query = (root.all_attachment_folders.filter_by(
            is_deleted=False).options(joinedload('attachments')))
        for obj in _process_attachments(query):
            yield _ProtectedObjectWrapper(obj)

    elif isinstance(root, db.m.Session):
        # For a session we check contributions and attachments within the session
        crit = db.or_(
            # attached to the session
            db.m.AttachmentFolder.object == root,
            # attached to a contribution in the session
            db.and_(
                db.m.AttachmentFolder.link_type == LinkType.contribution,
                db.m.AttachmentFolder.contribution.has(
                    db.and_(db.m.Contribution.session == root,
                            ~db.m.Contribution.is_deleted))),
            # attached to a subcontribution in a contribution in the session
            db.and_(
                db.m.AttachmentFolder.link_type == LinkType.subcontribution,
                db.m.AttachmentFolder.subcontribution.has(
                    db.and_(
                        ~db.m.SubContribution.is_deleted,
                        db.m.SubContribution.contribution.has(
                            db.and_(db.m.Contribution.session == root,
                                    ~db.m.Contribution.is_deleted))))))
        for obj in _process_attachments(_query_folders(root, crit)):
            yield _ProtectedObjectWrapper(obj)
        for contrib in root.contributions:
            if not contrib.is_inheriting:
                yield _ProtectedObjectWrapper(contrib)

    elif isinstance(root, db.m.Contribution):
        # For a contribution we check attachments and subcontrib attachments
        crit = db.or_(
            # attached to the contribution
            db.m.AttachmentFolder.object == root,
            # attached to a subcontribution of the contribution
            db.and_(
                db.m.AttachmentFolder.link_type == LinkType.subcontribution,
                db.m.AttachmentFolder.subcontribution.has(
                    db.and_(db.m.SubContribution.contribution == root,
                            ~db.m.SubContribution.is_deleted))))
        for obj in _process_attachments(_query_folders(root, crit)):
            yield _ProtectedObjectWrapper(obj)

    elif isinstance(root, db.m.AttachmentFolder):
        # For an attachment folder we only check attachments in there
        for attachment in root.attachments:
            if not attachment.is_inheriting:
                yield _ProtectedObjectWrapper(attachment)

    else:
        raise TypeError('Unexpected object of type {}: {}'.format(
            type(root).__name__, root))
Exemple #41
0
def _query_contributions_with_user_paper_submission_rights(event, user):
    criteria = [Contribution.person_links.any(ContributionPersonLink.person.has(user=user)),
                Contribution.abstract.has(Abstract.submitter_id == user.id)]
    return Contribution.query.with_parent(event).filter(db.or_(*criteria))
Exemple #42
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)
Exemple #43
0
    def get_persons(self):
        abstract_strategy = joinedload('abstract_links')
        abstract_strategy.joinedload('abstract')
        abstract_strategy.joinedload('person').joinedload('user')
        contribution_strategy = joinedload('contribution_links')
        contribution_strategy.joinedload('contribution')
        contribution_strategy.joinedload('person').joinedload('user')
        subcontribution_strategy = joinedload('subcontribution_links')
        subcontribution_strategy.joinedload('subcontribution')
        subcontribution_strategy.joinedload('person').joinedload('user')
        session_block_strategy = joinedload('session_block_links')
        session_block_strategy.joinedload('session_block')
        session_block_strategy.joinedload('person').joinedload('user')
        event_strategy = joinedload('event_links')
        event_strategy.joinedload('person').joinedload('user')

        chairpersons = {link.person for link in self.event.person_links}
        persons = defaultdict(
            lambda: {
                'roles': {},
                'registrations': [],
                'has_event_person': True,
                'id_field_name': 'person_id'
            })

        _reg_person_join = db.or_(
            (EventPerson.user_id == Registration.user_id),
            db.and_(EventPerson.user_id.is_(None),
                    Registration.user_id.is_(None),
                    EventPerson.email == Registration.email))
        event_persons_query = (db.session.query(
            EventPerson, Registration).filter(
                EventPerson.event_id == self.event.id).outerjoin(
                    Registration, (Registration.event_id == self.event.id)
                    & _reg_person_join).options(abstract_strategy,
                                                event_strategy,
                                                contribution_strategy,
                                                subcontribution_strategy,
                                                session_block_strategy).all())

        event_user_roles = defaultdict(set)
        for event_role in self.event.roles:
            for user in event_role.members:
                event_user_roles[user].add(event_role)

        event_person_users = set()
        for event_person, registration in event_persons_query:
            data = persons[event_person.email or event_person.id]
            if registration:
                data['registrations'].append(registration)
            data['person'] = event_person
            if event_person in chairpersons:
                data['roles']['chairperson'] = BUILTIN_ROLES[
                    'chairperson'].copy()

            if self.event.type == 'lecture':
                continue

            if self.event.has_feature('abstracts'):
                abstracts = {
                    person_link.abstract_id:
                    self.generate_abstracts_data(person_link)
                    for person_link in event_person.abstract_links
                    if not person_link.abstract.is_deleted
                }

                if abstracts:
                    data['roles']['author'] = BUILTIN_ROLES['author'].copy()
                    data['roles']['author']['elements'] = abstracts

            session_blocks = {
                person_link.session_block_id:
                self.generate_sessions_data(person_link)
                for person_link in event_person.session_block_links
                if not person_link.session_block.session.is_deleted
            }

            if session_blocks:
                data['roles']['convener'] = BUILTIN_ROLES['convener'].copy()
                data['roles']['convener']['elements'] = session_blocks

            contributions = {
                person_link.contribution.id:
                self.generate_contributions_data(person_link)
                for person_link in event_person.contribution_links
                if person_link.is_speaker
                and not person_link.contribution.is_deleted
            }

            subcontributions = {
                person_link.subcontribution.id:
                self.generate_subcontributions_data(person_link)
                for person_link in event_person.subcontribution_links
                if not person_link.subcontribution.is_deleted
                and not person_link.subcontribution.contribution.is_deleted
            }

            if contributions or subcontributions:
                data['roles']['speaker'] = BUILTIN_ROLES['speaker'].copy()
                data['roles']['speaker']['elements'] = dict(
                    contributions, **subcontributions)

            event_user_roles_data = {}
            for role in event_user_roles[event_person.user]:
                event_user_roles_data[f'custom_{role.id}'] = {
                    'name': role.name,
                    'code': role.code,
                    'css': role.css
                }
            event_user_roles_data = dict(
                sorted(event_user_roles_data.items(),
                       key=lambda t: t[1]['code']))
            data['roles'] = data['roles'] | event_user_roles_data

            event_person_users.add(event_person.user)

        internal_role_users = defaultdict(
            lambda: {
                'roles': {},
                'person': [],
                'registrations': [],
                'has_event_person': False,
                'id_field_name': 'user_id'
            })
        for user, roles in event_user_roles.items():
            if user in event_person_users:
                continue
            for role in roles:
                user_metadata = internal_role_users[user.email]
                user_metadata['person'] = user
                user_metadata['roles'][f'custom_{role.id}'] = {
                    'name': role.name,
                    'code': role.code,
                    'css': role.css
                }
            user_metadata['roles'] = dict(
                sorted(user_metadata['roles'].items(),
                       key=lambda x: x[1]['code']))

        regs = (Registration.query.with_parent(self.event).filter(
            Registration.user_id.in_(
                data['person'].id
                for data in internal_role_users.values())).all())
        for reg in regs:
            internal_role_users[reg.user.email]['registrations'].append(reg)

        # Some EventPersons will have no roles since they were connected to deleted things
        persons = {
            email: data
            for email, data in persons.items() if any(data['roles'].values())
        }
        persons = dict(persons, **internal_role_users)
        return persons
Exemple #44
0
def _query_user_tracks(event, user):
    query = Track.query.with_parent(event)
    if user not in event.global_abstract_reviewers and user not in event.global_conveners:
        query = query.filter(db.or_(Track.conveners.any(User.id == user.id),
                                    Track.abstract_reviewers.any(User.id == user.id)))
    return query
Exemple #45
0
def get_user_submittable_contributions(event, user):
    criteria = [Contribution._paper_last_revision == None,  # noqa
                Contribution._paper_last_revision.has(PaperRevision.state == PaperRevisionState.to_be_corrected)]
    return (_query_contributions_with_user_paper_submission_rights(event, user)
            .filter(db.or_(*criteria))
            .all())
Exemple #46
0
def _build_name_search(name_list):
    text = remove_accents('%{}%'.format('%'.join(escape_like(name) for name in name_list)))
    return db.or_(db.func.indico.indico_unaccent(db.func.concat(User.first_name, ' ', User.last_name)).ilike(text),
                  db.func.indico.indico_unaccent(db.func.concat(User.last_name, ' ', User.first_name)).ilike(text))
Exemple #47
0
def get_non_inheriting_objects(root):
    """Get a set of child objects that do not inherit protection

    :param root: An event object (`Event`, `Session`, `Contribution`
                 or `AttachmentFolder`) which may contain objects
                 with a different protection.
    """
    def _query_folders(obj, crit):
        return (db.m.AttachmentFolder.query
                .filter_by(event_new=obj.event_new, is_deleted=False)
                .filter(crit)
                .options(joinedload('attachments')))

    def _process_attachments(folders):
        for folder in folders:
            if not folder.is_inheriting:
                yield folder
            for attachment in folder.attachments:
                if not attachment.is_inheriting:
                    yield attachment

    if isinstance(root, db.m.Event):
        # For an event we check sessions, contributions and ALL attachments no matter where
        for sess in db.m.Session.query.with_parent(root).filter(~db.m.Session.is_inheriting):
            yield _ProtectedObjectWrapper(sess)
        for contrib in db.m.Contribution.query.with_parent(root).filter(~db.m.Contribution.is_inheriting):
            yield _ProtectedObjectWrapper(contrib)
        query = (root.all_attachment_folders
                 .filter_by(is_deleted=False)
                 .options(joinedload('attachments')))
        for obj in _process_attachments(query):
            yield _ProtectedObjectWrapper(obj)

    elif isinstance(root, db.m.Session):
        # For a session we check contributions and attachments within the session
        crit = db.or_(
            # attached to the session
            db.m.AttachmentFolder.object == root,
            # attached to a contribution in the session
            db.and_(
                db.m.AttachmentFolder.link_type == LinkType.contribution,
                db.m.AttachmentFolder.contribution.has(
                    db.and_(
                        db.m.Contribution.session == root,
                        ~db.m.Contribution.is_deleted
                    )
                )
            ),
            # attached to a subcontribution in a contribution in the session
            db.and_(
                db.m.AttachmentFolder.link_type == LinkType.subcontribution,
                db.m.AttachmentFolder.subcontribution.has(
                    db.and_(
                        ~db.m.SubContribution.is_deleted,
                        db.m.SubContribution.contribution.has(
                            db.and_(
                                db.m.Contribution.session == root,
                                ~db.m.Contribution.is_deleted
                            )
                        )
                    )
                )
            )
        )
        for obj in _process_attachments(_query_folders(root, crit)):
            yield _ProtectedObjectWrapper(obj)
        for contrib in root.contributions:
            if not contrib.is_inheriting:
                yield _ProtectedObjectWrapper(contrib)

    elif isinstance(root, db.m.Contribution):
        # For a contribution we check attachments and subcontrib attachments
        crit = db.or_(
            # attached to the contribution
            db.m.AttachmentFolder.object == root,
            # attached to a subcontribution of the contribution
            db.and_(
                db.m.AttachmentFolder.link_type == LinkType.subcontribution,
                db.m.AttachmentFolder.subcontribution.has(
                    db.and_(
                        db.m.SubContribution.contribution == root,
                        ~db.m.SubContribution.is_deleted
                    )
                )
            )
        )
        for obj in _process_attachments(_query_folders(root, crit)):
            yield _ProtectedObjectWrapper(obj)

    elif isinstance(root, db.m.AttachmentFolder):
        # For an attachment folder we only check attachments in there
        for attachment in root.attachments:
            if not attachment.is_inheriting:
                yield _ProtectedObjectWrapper(attachment)

    else:
        raise TypeError('Unexpected object of type {}: {}'.format(type(root).__name__, root))
Exemple #48
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 '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
Exemple #49
0
def _make_room_text_filter(text):
    text = '%{}%'.format(escape_like(text))
    columns = ('site', 'division', 'building', 'floor', 'number', 'comments',
               'full_name')
    return db.or_(getattr(Room, col).ilike(text) for col in columns)
Exemple #50
0
def _query_user_tracks(event, user):
    query = Track.query.with_parent(event)
    if user not in event.global_abstract_reviewers and user not in event.global_conveners:
        query = query.filter(db.or_(Track.conveners.any(User.id == user.id),
                                    Track.abstract_reviewers.any(User.id == user.id)))
    return query
Exemple #51
0
    def _filter_list_entries(self, query, filters):
        criteria = []
        field_filters = filters.get('fields')
        item_filters = filters.get('items')
        extra_filters = filters.get('extra')

        if not (field_filters or item_filters or extra_filters):
            return query

        if field_filters:
            for contribution_type_id, field_values in field_filters.iteritems(
            ):
                criteria.append(
                    Abstract.field_values.any(
                        db.and_(
                            AbstractFieldValue.contribution_field_id ==
                            contribution_type_id,
                            AbstractFieldValue.data.op('#>>')('{}').in_(
                                field_values))))

        if item_filters:
            static_filters = {
                'accepted_track': Abstract.accepted_track_id,
                'accepted_contrib_type': Abstract.accepted_contrib_type_id,
                'submitted_contrib_type': Abstract.submitted_contrib_type_id,
                'submitted_for_tracks': Abstract.submitted_for_tracks,
                'reviewed_for_tracks': Abstract.reviewed_for_tracks
            }
            for key, column in static_filters.iteritems():
                ids = set(item_filters.get(key, ()))
                if not ids:
                    continue
                column_criteria = []
                if '_for_tracks' in key:
                    if None in ids:
                        column_criteria.append(~column.any())
                        ids.discard(None)
                    if ids:
                        column_criteria.append(column.any(Track.id.in_(ids)))
                else:
                    if None in ids:
                        column_criteria.append(column.is_(None))
                        ids.discard(None)
                    if ids:
                        column_criteria.append(column.in_(ids))
                criteria.append(db.or_(*column_criteria))
            if 'state' in item_filters:
                states = [
                    AbstractState(int(state))
                    for state in item_filters['state']
                ]
                criteria.append(Abstract.state.in_(states))
        if extra_filters:
            if extra_filters.get('multiple_tracks'):
                submitted_for_count = (db.select(
                    [db.func.count()]).as_scalar().where(
                        Abstract.submitted_for_tracks.prop.primaryjoin))
                criteria.append(submitted_for_count > 1)
            if extra_filters.get('comments'):
                criteria.append(Abstract.submission_comment != '')
        return query.filter(db.and_(*criteria))
Exemple #52
0
def _process_cascaded_event_contents(records,
                                     additional_events=None,
                                     *,
                                     include_deleted=False,
                                     skip_all_deleted=False):
    """
    Flatten a series of records into its most basic elements (subcontribution level).

    Yields results.

    :param records: queue records to process
    :param additional_events: events whose content will be included in addition to those
                              found in records
    :param include_deleted: whether to include soft-deleted objects as well
    :param skip_all_deleted: whether to skip soft-deleted objects even if explicitly queued
    """
    changed_events = additional_events or set()
    changed_sessions = set()
    changed_contributions = set()
    changed_subcontributions = set()
    changed_attachments = set()
    changed_notes = set()

    def _deleted_cond(cond):
        return True if include_deleted else cond

    def _check_deleted(rec):
        return not skip_all_deleted or not rec.object.is_deleted

    note_records = {
        rec.note_id
        for rec in records
        if rec.type == EntryType.note and _check_deleted(rec)
    }
    attachment_records = {
        rec.attachment_id
        for rec in records
        if rec.type == EntryType.attachment and _check_deleted(rec)
    }
    session_records = {
        rec.session_id
        for rec in records
        if rec.type == EntryType.session and _check_deleted(rec)
    }
    contribution_records = {
        rec.contrib_id
        for rec in records
        if rec.type == EntryType.contribution and _check_deleted(rec)
    }
    subcontribution_records = {
        rec.subcontrib_id
        for rec in records
        if rec.type == EntryType.subcontribution and _check_deleted(rec)
    }
    event_records = {
        rec.event_id
        for rec in records
        if rec.type == EntryType.event and _check_deleted(rec)
    }

    if attachment_records:
        changed_attachments.update(
            Attachment.query.filter(Attachment.id.in_(attachment_records)))

    if note_records:
        changed_notes.update(
            EventNote.query.filter(EventNote.id.in_(note_records)))

    if event_records:
        changed_events.update(Event.query.filter(Event.id.in_(event_records)))

    changed_event_ids = {ev.id for ev in changed_events}

    if changed_event_ids:
        changed_attachments.update(
            Attachment.query.filter(
                _deleted_cond(~Attachment.is_deleted),
                Attachment.folder.has(
                    db.and_(
                        AttachmentFolder.linked_event_id.in_(
                            changed_event_ids),
                        _deleted_cond(~AttachmentFolder.is_deleted)))))
        changed_notes.update(
            EventNote.query.filter(
                EventNote.linked_event_id.in_(changed_event_ids),
                _deleted_cond(~EventNote.is_deleted)))

    yield from changed_events

    # Sessions are added (implictly + explicitly changed)
    if changed_event_ids or session_records:
        condition = Session.event_id.in_(changed_event_ids) & _deleted_cond(
            ~Session.is_deleted)
        if session_records:
            condition = db.or_(condition, Session.id.in_(session_records))
        changed_sessions.update(
            Session.query.filter(Session.event_id.in_(changed_event_ids),
                                 _deleted_cond(~Session.is_deleted)))

    if changed_sessions:
        # XXX I kept this very similar to the structure of the code for contributions below,
        # but why aren't we just merging this into the block right above?!
        changed_session_ids = {s.id for s in changed_sessions}
        changed_contributions.update(
            Contribution.query.filter(
                Contribution.session_id.in_(changed_session_ids),
                _deleted_cond(~Contribution.is_deleted)))
        changed_attachments.update(
            Attachment.query.filter(
                _deleted_cond(~Attachment.is_deleted),
                Attachment.folder.has(
                    db.and_(
                        AttachmentFolder.session_id.in_(changed_session_ids),
                        _deleted_cond(~AttachmentFolder.is_deleted)))))
        changed_notes.update(
            EventNote.query.filter(
                EventNote.session_id.in_(changed_session_ids),
                _deleted_cond(~EventNote.is_deleted)))

    # Contributions are added (implictly + explicitly changed)
    if changed_event_ids or contribution_records:
        condition = Contribution.event_id.in_(
            changed_event_ids) & _deleted_cond(~Contribution.is_deleted)
        if contribution_records:
            condition = db.or_(condition,
                               Contribution.id.in_(contribution_records))
        changed_contributions.update(
            Contribution.query.filter(condition).options(
                joinedload('subcontributions')))

    for contribution in changed_contributions:
        yield contribution
        changed_subcontributions.update(contribution.subcontributions)

    if changed_contributions:
        changed_contribution_ids = {c.id for c in changed_contributions}
        changed_attachments.update(
            Attachment.query.filter(
                _deleted_cond(~Attachment.is_deleted),
                Attachment.folder.has(
                    db.and_(
                        AttachmentFolder.contribution_id.in_(
                            changed_contribution_ids),
                        _deleted_cond(~AttachmentFolder.is_deleted)))))
        changed_notes.update(
            EventNote.query.filter(
                EventNote.contribution_id.in_(changed_contribution_ids),
                _deleted_cond(~EventNote.is_deleted)))

    # Same for subcontributions
    if subcontribution_records:
        changed_subcontributions.update(
            SubContribution.query.filter(
                SubContribution.id.in_(subcontribution_records)))

    if changed_subcontributions:
        changed_subcontribution_ids = {
            sc.id
            for sc in changed_subcontributions
        }
        changed_attachments.update(
            Attachment.query.filter(
                _deleted_cond(~Attachment.is_deleted),
                Attachment.folder.has(
                    db.and_(
                        AttachmentFolder.subcontribution_id.in_(
                            changed_subcontribution_ids),
                        _deleted_cond(~AttachmentFolder.is_deleted)))))
        changed_notes.update(
            EventNote.query.filter(
                EventNote.subcontribution_id.in_(changed_subcontribution_ids),
                _deleted_cond(~EventNote.is_deleted)))

    yield from changed_subcontributions
    yield from changed_attachments
    yield from changed_notes
Exemple #53
0
def _query_contributions_with_user_paper_submission_rights(event, user):
    criteria = [Contribution.person_links.any(ContributionPersonLink.person.has(user=user)),
                Contribution.abstract.has(Abstract.submitter_id == user.id)]
    return Contribution.query.with_parent(event).filter(db.or_(*criteria))
Exemple #54
0
def _make_room_text_filter(text):
    text = '%{}%'.format(escape_like(text))
    columns = ('site', 'division', 'building', 'floor', 'number', 'comments', 'full_name')
    return db.or_(getattr(Room, col).ilike(text) for col in columns)
Exemple #55
0
    def search_notes(self, q, user, page, category_id, event_id,
                     admin_override_enabled):
        contrib_event = db.aliased(Event)
        contrib_session = db.aliased(Session)
        subcontrib_contrib = db.aliased(Contribution)
        subcontrib_session = db.aliased(Session)
        subcontrib_event = db.aliased(Event)
        session_event = db.aliased(Event)

        note_strategy = load_only('id', 'link_type', 'event_id',
                                  'linked_event_id', 'contribution_id',
                                  'subcontribution_id', 'session_id', 'html')
        # event
        event_strategy = note_strategy.contains_eager(EventNote.linked_event)
        event_strategy.undefer(Event.effective_protection_mode)
        _apply_event_access_strategy(event_strategy)
        _apply_acl_entry_strategy(
            event_strategy.selectinload(Event.acl_entries), EventPrincipal)
        # contribution
        contrib_strategy = note_strategy.contains_eager(EventNote.contribution)
        _apply_contrib_access_strategy(contrib_strategy)
        _apply_acl_entry_strategy(
            contrib_strategy.selectinload(Contribution.acl_entries),
            ContributionPrincipal)
        contrib_event_strategy = contrib_strategy.contains_eager(
            Contribution.event.of_type(contrib_event))
        _apply_event_access_strategy(contrib_event_strategy)
        _apply_acl_entry_strategy(
            contrib_event_strategy.selectinload(contrib_event.acl_entries),
            EventPrincipal)
        contrib_session_strategy = contrib_strategy.contains_eager(
            Contribution.session.of_type(contrib_session))
        contrib_session_strategy.load_only('id', 'event_id', 'protection_mode')
        _apply_acl_entry_strategy(
            contrib_session_strategy.selectinload(contrib_session.acl_entries),
            SessionPrincipal)
        # subcontribution
        subcontrib_strategy = note_strategy.contains_eager(
            EventNote.subcontribution)
        subcontrib_contrib_strategy = subcontrib_strategy.contains_eager(
            SubContribution.contribution.of_type(subcontrib_contrib))
        _apply_contrib_access_strategy(subcontrib_contrib_strategy)
        _apply_acl_entry_strategy(
            subcontrib_contrib_strategy.selectinload(
                subcontrib_contrib.acl_entries), ContributionPrincipal)
        subcontrib_event_strategy = subcontrib_contrib_strategy.contains_eager(
            subcontrib_contrib.event.of_type(subcontrib_event))
        _apply_event_access_strategy(subcontrib_event_strategy)
        _apply_acl_entry_strategy(
            subcontrib_event_strategy.selectinload(
                subcontrib_event.acl_entries), EventPrincipal)
        subcontrib_session_strategy = subcontrib_contrib_strategy.contains_eager(
            subcontrib_contrib.session.of_type(subcontrib_session))
        subcontrib_session_strategy.load_only('id', 'event_id',
                                              'protection_mode')
        _apply_acl_entry_strategy(
            subcontrib_session_strategy.selectinload(
                subcontrib_session.acl_entries), SessionPrincipal)
        # session
        session_strategy = note_strategy.contains_eager(EventNote.session)
        session_strategy.load_only('id', 'event_id', 'protection_mode')
        session_event_strategy = session_strategy.contains_eager(
            Session.event.of_type(session_event))
        _apply_event_access_strategy(session_event_strategy)
        session_event_strategy.selectinload(session_event.acl_entries)
        _apply_acl_entry_strategy(
            session_strategy.selectinload(Session.acl_entries),
            SessionPrincipal)

        note_filters = [
            EventNote.html_matches(q), ~EventNote.is_deleted,
            db.or_(EventNote.link_type != LinkType.event, ~Event.is_deleted),
            db.or_(EventNote.link_type != LinkType.contribution,
                   ~Contribution.is_deleted & ~contrib_event.is_deleted),
            db.or_(
                EventNote.link_type != LinkType.subcontribution,
                db.and_(~SubContribution.is_deleted,
                        ~subcontrib_contrib.is_deleted,
                        ~subcontrib_event.is_deleted)),
            db.or_(EventNote.link_type != LinkType.session,
                   ~Session.is_deleted & ~session_event.is_deleted)
        ]

        if category_id is not None:
            note_filters.append(
                EventNote.event.has(
                    Event.category_chain_overlaps(category_id)))
        if event_id is not None:
            note_filters.append(EventNote.event_id == event_id)

        query = (
            EventNote.query.filter(
                *note_filters).options(note_strategy).outerjoin(
                    EventNote.linked_event).outerjoin(
                        EventNote.contribution).outerjoin(
                            Contribution.event.of_type(contrib_event)).
            outerjoin(Contribution.session.of_type(contrib_session)).outerjoin(
                EventNote.subcontribution).outerjoin(
                    SubContribution.contribution.of_type(subcontrib_contrib)).
            outerjoin(
                subcontrib_contrib.event.of_type(subcontrib_event)).outerjoin(
                    subcontrib_contrib.session.of_type(
                        subcontrib_session)).outerjoin(
                            EventNote.session).outerjoin(
                                Session.event.of_type(session_event)))

        objs, pagenav = self._paginate(query, page, EventNote.id, user,
                                       admin_override_enabled)

        query = (EventNote.query.filter(EventNote.id.in_(
            n.id for n in objs)).options(
                joinedload(EventNote.contribution),
                joinedload(EventNote.subcontribution).joinedload(
                    SubContribution.contribution),
                joinedload(EventNote.event).options(
                    undefer(Event.detailed_category_chain)),
                joinedload(EventNote.current_revision).joinedload(
                    EventNoteRevision.user).joinedload('_affiliation'),
            ))
        notes_by_id = {n.id: n for n in query}
        notes = [notes_by_id[n.id] for n in objs]

        res = HTMLStrippingEventNoteSchema(many=True).dump(notes)
        return pagenav, EventNoteResultSchema(many=True).load(res)
Exemple #56
0
def _query_contributions_with_user_as_reviewer(event, user):
    query = Contribution.query.with_parent(event)
    query = query.filter(db.or_(Contribution.paper_content_reviewers.any(User.id == user.id),
                                Contribution.paper_layout_reviewers.any(User.id == user.id)),
                         Contribution._paper_revisions.any())
    return query
Exemple #57
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)
Exemple #58
0
def _process_cascaded_event_contents(records, additional_events=None):
    """
    Flatten a series of records into its most basic elements (subcontribution level).

    Yields results.

    :param records: queue records to process
    :param additional_events: events whose content will be included in addition to those
                              found in records
    """
    changed_events = additional_events or set()
    changed_contributions = set()
    changed_subcontributions = set()

    session_records = {
        rec.session_id
        for rec in records if rec.type == EntryType.session
    }
    contribution_records = {
        rec.contrib_id
        for rec in records if rec.type == EntryType.contribution
    }
    subcontribution_records = {
        rec.subcontrib_id
        for rec in records if rec.type == EntryType.subcontribution
    }
    event_records = {
        rec.event_id
        for rec in records if rec.type == EntryType.event
    }

    if event_records:
        changed_events.update(Event.query.filter(Event.id.in_(event_records)))

    yield from changed_events

    # Sessions are added (explicitly changed only, since they don't need to be sent anywhere)
    if session_records:
        changed_contributions.update(
            Contribution.query.filter(
                Contribution.session_id.in_(session_records),
                ~Contribution.is_deleted))

    # Contributions are added (implictly + explicitly changed)
    changed_event_ids = {ev.id for ev in changed_events}

    condition = Contribution.event_id.in_(
        changed_event_ids) & ~Contribution.is_deleted
    if contribution_records:
        condition = db.or_(condition,
                           Contribution.id.in_(contribution_records))
    contrib_query = Contribution.query.filter(condition).options(
        joinedload('subcontributions'))

    for contribution in contrib_query:
        yield contribution
        changed_subcontributions.update(contribution.subcontributions)

    # Same for subcontributions
    if subcontribution_records:
        changed_subcontributions.update(
            SubContribution.query.filter(
                SubContribution.id.in_(subcontribution_records)))
    yield from changed_subcontributions