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))
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)
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)
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
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')
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())
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)))
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)
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)
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))
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()
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)
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))
def get_room_events(room, start_dt, end_dt, repeat_frequency, repeat_interval): occurrences = ReservationOccurrence.create_series(start_dt, end_dt, (repeat_frequency, repeat_interval)) excluded_categories = rb_settings.get('excluded_categories') return (Event.query .filter(~Event.is_deleted, Event.own_room == room, db.or_(Event.happens_between(as_utc(occ.start_dt), as_utc(occ.end_dt)) for occ in occurrences), Event.timezone == config.DEFAULT_TIMEZONE, db.and_(Event.category_id != cat['id'] for cat in excluded_categories), Event.acl_entries.any(db.and_(EventPrincipal.type == PrincipalType.user, EventPrincipal.user_id == session.user.id, EventPrincipal.full_access))) .all())
def _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)
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)))
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))
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)
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())
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
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 }
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)
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}
def get_matching_events(start_dt, end_dt, repeat_frequency, repeat_interval): """Get events suitable for booking linking. This finds events that overlap with an occurrence of a booking with the given dates where the user is a manager. """ occurrences = ReservationOccurrence.create_series(start_dt, end_dt, (repeat_frequency, repeat_interval)) excluded_categories = rb_settings.get('excluded_categories') return (Event.query .filter(~Event.is_deleted, ~Event.room_reservation_links.any(ReservationLink.reservation.has(Reservation.is_accepted)), db.or_(Event.happens_between(as_utc(occ.start_dt), as_utc(occ.end_dt)) for occ in occurrences), Event.timezone == config.DEFAULT_TIMEZONE, db.and_(Event.category_id != cat.id for cat in excluded_categories), Event.acl_entries.any(db.and_(EventPrincipal.type == PrincipalType.user, EventPrincipal.user_id == session.user.id, EventPrincipal.full_access))) .all())
def _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()
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))
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
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
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)
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)))
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)
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()
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) ) )))
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) ) )))
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)
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
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))
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))
def search_for_rooms(filters, allow_admin=False, availability=None): """Search for a room, using the provided filters. :param filters: The filters, provided as a dictionary :param allow_admin: A boolean specifying whether admins have override privileges :param availability: A boolean specifying whether (un)available rooms should be provided, or `None` in case all rooms should be returned. """ query = (Room.query .outerjoin(favorite_room_table, db.and_(favorite_room_table.c.user_id == session.user.id, favorite_room_table.c.room_id == Room.id)) .reset_joinpoint() # otherwise filter_by() would apply to the favorite table .options(joinedload('owner').load_only('id')) .filter(~Room.is_deleted) .order_by(favorite_room_table.c.user_id.is_(None), db.func.indico.natsort(Room.full_name))) criteria = {} if 'capacity' in filters: query = query.filter(Room.capacity >= filters['capacity']) if 'building' in filters: criteria['building'] = filters['building'] if 'division' in filters: criteria['division'] = filters['division'] query = query.filter_by(**criteria) if 'text' in filters: text = ' '.join(filters['text'].strip().split()) query = query.filter(_make_room_text_filter(text)) if filters.get('equipment'): subquery = (db.session.query(RoomEquipmentAssociation) .with_entities(db.func.count(RoomEquipmentAssociation.c.room_id)) .filter( RoomEquipmentAssociation.c.room_id == Room.id, EquipmentType.name.in_(filters['equipment']) ) .join(EquipmentType, RoomEquipmentAssociation.c.equipment_id == EquipmentType.id) .correlate(Room) .as_scalar()) query = query.filter(subquery == len(filters['equipment'])) if filters.get('features'): for feature in filters['features']: query = query.filter(Room.available_equipment.any(EquipmentType.features.any(RoomFeature.name == feature))) if filters.get('favorite'): query = query.filter(favorite_room_table.c.user_id.isnot(None)) if filters.get('mine'): ids = get_managed_room_ids(session.user) query = query.filter(Room.id.in_(ids)) query = _filter_coordinates(query, filters) if availability is None: return query start_dt, end_dt = filters['start_dt'], filters['end_dt'] repeatability = (filters['repeat_frequency'], filters['repeat_interval']) availability_filters = [Room.filter_available(start_dt, end_dt, repeatability, include_blockings=False, include_pre_bookings=True)] if not (allow_admin and rb_is_admin(session.user)): selected_period_days = (filters['end_dt'] - filters['start_dt']).days booking_limit_days = db.func.coalesce(Room.booking_limit_days, rb_settings.get('booking_limit')) criterion = db.and_(Room.filter_bookable_hours(start_dt.time(), end_dt.time()), Room.filter_nonbookable_periods(start_dt, end_dt), db.or_(booking_limit_days.is_(None), selected_period_days <= booking_limit_days)) unbookable_ids = [room.id for room in query.filter(db.and_(*availability_filters), ~criterion) if not room.can_override(session.user, allow_admin=False)] availability_filters.append(~Room.id.in_(unbookable_ids)) availability_criterion = db.and_(*availability_filters) if availability is False: availability_criterion = ~availability_criterion return query.filter(availability_criterion)
def 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
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
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())
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))
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))
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
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)
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))
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
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)
def search_for_rooms(filters, allow_admin=False, availability=None): """Search for a room, using the provided filters. :param filters: The filters, provided as a dictionary :param allow_admin: A boolean specifying whether admins have override privileges :param availability: A boolean specifying whether (un)available rooms should be provided, or `None` in case all rooms should be returned. """ query = ( Room.query.outerjoin( favorite_room_table, db.and_( favorite_room_table.c.user_id == session.user.id, favorite_room_table.c.room_id == Room.id)).reset_joinpoint( ) # otherwise filter_by() would apply to the favorite table .options(joinedload('owner').load_only('id')).filter( ~Room.is_deleted).order_by(favorite_room_table.c.user_id.is_(None), db.func.indico.natsort(Room.full_name))) criteria = {} if 'capacity' in filters: query = query.filter(Room.capacity >= filters['capacity']) if 'building' in filters: criteria['building'] = filters['building'] if 'division' in filters: criteria['division'] = filters['division'] query = query.filter_by(**criteria) if 'text' in filters: text = ' '.join(filters['text'].strip().split()) if text.startswith('#') and text[1:].isdigit(): query = query.filter(Room.id == int(text[1:])) else: query = query.filter(_make_room_text_filter(text)) if filters.get('equipment'): subquery = (db.session.query(RoomEquipmentAssociation).with_entities( db.func.count(RoomEquipmentAssociation.c.room_id)).filter( RoomEquipmentAssociation.c.room_id == Room.id, EquipmentType.name.in_(filters['equipment'])).join( EquipmentType, RoomEquipmentAssociation.c.equipment_id == EquipmentType.id).correlate(Room).as_scalar()) query = query.filter(subquery == len(filters['equipment'])) if filters.get('features'): for feature in filters['features']: query = query.filter( Room.available_equipment.any( EquipmentType.features.any(RoomFeature.name == feature))) if filters.get('favorite'): query = query.filter(favorite_room_table.c.user_id.isnot(None)) if filters.get('mine'): ids = get_managed_room_ids(session.user) query = query.filter(Room.id.in_(ids)) query = _filter_coordinates(query, filters) if availability is None: return query start_dt, end_dt = filters['start_dt'], filters['end_dt'] repeatability = (filters['repeat_frequency'], filters['repeat_interval']) availability_filters = [ Room.filter_available(start_dt, end_dt, repeatability, include_blockings=False, include_pre_bookings=False) ] if not (allow_admin and rb_is_admin(session.user)): selected_period_days = (filters['end_dt'] - filters['start_dt']).days booking_limit_days = db.func.coalesce(Room.booking_limit_days, rb_settings.get('booking_limit')) criterion = db.and_( Room.filter_bookable_hours(start_dt.time(), end_dt.time()), Room.filter_nonbookable_periods(start_dt, end_dt), db.or_(booking_limit_days.is_(None), selected_period_days <= booking_limit_days)) unbookable_ids = [ room.id for room in query.filter(db.and_( *availability_filters), ~criterion) if not room.can_override(session.user, allow_admin=False) ] availability_filters.append(~Room.id.in_(unbookable_ids)) availability_criterion = db.and_(*availability_filters) if availability is False: availability_criterion = ~availability_criterion return query.filter(availability_criterion)
def _process_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