def get_attachment_count(category_id=None): """Get the number of attachments in events in a category. :param category_id: The category ID to get statistics for. Attachments from subcategories are also included. :return: The number of attachments """ category_filter = Event.category_chain_overlaps(category_id) if category_id else True subcontrib_contrib = db.aliased(Contribution) query = (db.session .query(db.func.count(Attachment.id)) .join(Attachment.folder) .join(AttachmentFolder.event) .outerjoin(AttachmentFolder.session) .outerjoin(AttachmentFolder.contribution) .outerjoin(AttachmentFolder.subcontribution) .outerjoin(subcontrib_contrib, subcontrib_contrib.id == SubContribution.contribution_id) .filter(AttachmentFolder.link_type != LinkType.category, ~Attachment.is_deleted, ~AttachmentFolder.is_deleted, ~Event.is_deleted, # we have exactly one of those or none if the attachment is on the event itself ~db.func.coalesce(Session.is_deleted, Contribution.is_deleted, SubContribution.is_deleted, False), # in case of a subcontribution we also need to check that the contrib is not deleted (subcontrib_contrib.is_deleted.is_(None) | ~subcontrib_contrib.is_deleted), category_filter)) return query.scalar()
def _process(self): self.user.settings.set('suggest_categories', True) tz = session.tzinfo hours, minutes = timedelta_split(tz.utcoffset(datetime.now()))[:2] categories = get_related_categories(self.user) categories_events = [] if categories: category_ids = {c['categ'].id for c in categories.itervalues()} today = now_utc(False).astimezone(tz).date() query = (Event.query .filter(~Event.is_deleted, Event.category_chain_overlaps(category_ids), Event.start_dt.astimezone(session.tzinfo) >= today) .options(joinedload('category').load_only('id', 'title'), joinedload('series'), subqueryload('acl_entries'), load_only('id', 'category_id', 'start_dt', 'end_dt', 'title', 'access_key', 'protection_mode', 'series_id', 'series_pos', 'series_count')) .order_by(Event.start_dt, Event.id)) categories_events = get_n_matching(query, 10, lambda x: x.can_access(self.user)) from_dt = now_utc(False) - relativedelta(weeks=1, hour=0, minute=0, second=0) linked_events = [(event, {'management': bool(roles & self.management_roles), 'reviewing': bool(roles & self.reviewer_roles), 'attendance': bool(roles & self.attendance_roles)}) for event, roles in get_linked_events(self.user, from_dt, 10).iteritems()] return WPUser.render_template('dashboard.html', 'dashboard', offset='{:+03d}:{:02d}'.format(hours, minutes), user=self.user, categories=categories, categories_events=categories_events, suggested_categories=get_suggested_categories(self.user), linked_events=linked_events)
def get_upcoming_events(): """Get the global list of upcoming events""" from indico.modules.events import Event data = upcoming_events_settings.get_all() if not data['max_entries'] or not data['entries']: return tz = timezone(config.DEFAULT_TIMEZONE) now = now_utc(False).astimezone(tz) base_query = (Event.query .filter(Event.effective_protection_mode == ProtectionMode.public, ~Event.is_deleted, Event.end_dt.astimezone(tz) > now) .options(load_only('id', 'title', 'start_dt', 'end_dt'))) queries = [] predicates = {'category': lambda id_: Event.category_id == id_, 'category_tree': lambda id_: Event.category_chain_overlaps(id_) & Event.is_visible_in(id_), 'event': lambda id_: Event.id == id_} for entry in data['entries']: delta = timedelta(days=entry['days']) query = (base_query .filter(predicates[entry['type']](entry['id'])) .filter(db.cast(Event.start_dt.astimezone(tz), db.Date) > (now - delta).date()) .with_entities(Event, db.literal(entry['weight']).label('weight'))) queries.append(query) query = (queries[0].union(*queries[1:]) .order_by(db.desc('weight'), Event.start_dt, Event.title) .limit(data['max_entries'])) for row in query: event = row[0] # we cache the result of the function and is_deleted is used in the repr # and having a broken repr on the cached objects would be ugly set_committed_value(event, 'is_deleted', False) yield event
def serialize_category_ical(category, user, event_filter): """Export the events in a category to iCal :param category: The category to export :param user: The user who needs to be able to access the events :param event_filter: A SQLalchemy criterion to restrict which events will be returned. Usually something involving the start/end date of the event. """ own_room_strategy = joinedload('own_room') own_room_strategy.load_only('building', 'floor', 'number', 'name') own_room_strategy.lazyload('owner') own_venue_strategy = joinedload('own_venue').load_only('name') query = (Event.query .filter(Event.category_chain_overlaps(category.id), ~Event.is_deleted, event_filter) .options(load_only('id', 'category_id', 'start_dt', 'end_dt', 'title', 'description', 'own_venue_name', 'own_room_name', 'protection_mode', 'access_key'), subqueryload('acl_entries'), joinedload('person_links'), own_room_strategy, own_venue_strategy) .order_by(Event.start_dt)) events = [e for e in query if e.can_access(user)] cal = ical.Calendar() cal.add('version', '2.0') cal.add('prodid', '-//CERN//INDICO//EN') now = now_utc(False) for event in events: url = url_for('event.conferenceDisplay', confId=event.id, _external=True) location = ('{} ({})'.format(event.room_name, event.venue_name) if event.venue_name and event.room_name else (event.venue_name or event.room_name)) cal_event = ical.Event() cal_event.add('uid', u'indico-event-{}@cern.ch'.format(event.id)) cal_event.add('dtstamp', now) cal_event.add('dtstart', event.start_dt) cal_event.add('dtend', event.end_dt) cal_event.add('url', url) cal_event.add('summary', event.title) cal_event.add('location', location) description = [] if event.person_links: speakers = [u'{} ({})'.format(x.full_name, x.affiliation) if x.affiliation else x.full_name for x in event.person_links] description.append(u'Speakers: {}'.format(u', '.join(speakers))) if event.description: desc_text = unicode(event.description) or u'<p/>' # get rid of RichMarkup try: description.append(unicode(html.fromstring(desc_text).text_content())) except ParserError: # this happens e.g. if desc_text contains only a html comment pass description.append(url) cal_event.add('description', u'\n'.join(description)) cal.add_component(cal_event) return BytesIO(cal.to_ical())
def serialize_category_atom(category, url, user, event_filter): """Export the events in a category to Atom :param category: The category to export :param url: The URL of the feed :param user: The user who needs to be able to access the events :param event_filter: A SQLalchemy criterion to restrict which events will be returned. Usually something involving the start/end date of the event. """ query = (Event.query.filter(Event.category_chain_overlaps( category.id), ~Event.is_deleted, event_filter).options( load_only('id', 'category_id', 'start_dt', 'title', 'description', 'protection_mode', 'access_key'), subqueryload('acl_entries')).order_by(Event.start_dt)) events = [e for e in query if e.can_access(user)] feed = AtomFeed(feed_url=url, title='Indico Feed [{}]'.format(category.title)) for event in events: feed.add( title=event.title, summary=unicode(event.description), # get rid of RichMarkup url=event.external_url, updated=event.start_dt) return BytesIO(feed.to_string().encode('utf-8'))
def serialize_category_atom(category, url, user, event_filter): """Export the events in a category to Atom. :param category: The category to export :param url: The URL of the feed :param user: The user who needs to be able to access the events :param event_filter: A SQLalchemy criterion to restrict which events will be returned. Usually something involving the start/end date of the event. """ query = (Event.query .filter(Event.category_chain_overlaps(category.id), ~Event.is_deleted, event_filter) .options(load_only('id', 'category_id', 'start_dt', 'title', 'description', 'protection_mode', 'access_key'), subqueryload('acl_entries')) .order_by(Event.start_dt)) events = [e for e in query if e.can_access(user)] feed = FeedGenerator() feed.id(url) feed.title(f'Indico Feed [{category.title}]') feed.link(href=url, rel='self') for event in events: entry = feed.add_entry(order='append') entry.id(event.external_url) entry.title(event.title) entry.summary(sanitize_html(str(event.description)) or None, type='html') entry.link(href=event.external_url) entry.updated(event.start_dt) return BytesIO(feed.atom_str(pretty=True))
def get_attachment_count(category_id=None): """Get the number of attachments in events in a category. :param category_id: The category ID to get statistics for. Attachments from subcategories are also included. :return: The number of attachments """ category_filter = Event.category_chain_overlaps( category_id) if category_id else True subcontrib_contrib = db.aliased(Contribution) query = ( db.session.query(db.func.count(Attachment.id)).join( Attachment.folder).join(AttachmentFolder.event).outerjoin( AttachmentFolder.session).outerjoin( AttachmentFolder.contribution).outerjoin( AttachmentFolder.subcontribution).outerjoin( subcontrib_contrib, subcontrib_contrib.id == SubContribution.contribution_id). filter( AttachmentFolder.link_type != LinkType.category, ~Attachment.is_deleted, ~AttachmentFolder.is_deleted, ~Event.is_deleted, # we have exactly one of those or none if the attachment is on the event itself ~db.func.coalesce(Session.is_deleted, Contribution.is_deleted, SubContribution.is_deleted, False), # in case of a subcontribution we also need to check that the contrib is not deleted (subcontrib_contrib.is_deleted.is_(None) | ~subcontrib_contrib.is_deleted), category_filter)) return query.scalar()
def serialize_category_atom(category, url, user, event_filter): """Export the events in a category to Atom :param category: The category to export :param url: The URL of the feed :param user: The user who needs to be able to access the events :param event_filter: A SQLalchemy criterion to restrict which events will be returned. Usually something involving the start/end date of the event. """ query = (Event.query .filter(Event.category_chain_overlaps(category.id), ~Event.is_deleted, event_filter) .options(load_only('id', 'category_id', 'start_dt', 'title', 'description', 'protection_mode', 'access_key'), subqueryload('acl_entries')) .order_by(Event.start_dt)) events = [e for e in query if e.can_access(user)] feed = AtomFeed(feed_url=url, title='Indico Feed [{}]'.format(category.title)) for event in events: feed.add(title=event.title, summary=unicode(event.description), # get rid of RichMarkup url=event.external_url, updated=event.start_dt) return BytesIO(feed.to_string().encode('utf-8'))
def search_events(self, q, user, page, category_id, admin_override_enabled): filters = [Event.title_matches(q), ~Event.is_deleted] if category_id is not None: filters.append(Event.category_chain_overlaps(category_id)) query = (Event.query.filter(*filters).options( load_only('id', 'category_id', 'access_key', 'protection_mode'), undefer(Event.effective_protection_mode), _apply_acl_entry_strategy(selectinload(Event.acl_entries), EventPrincipal))) objs, pagenav = self._paginate(query, page, Event.id, user, admin_override_enabled) query = (Event.query.filter(Event.id.in_(e.id for e in objs)).options( undefer(Event.detailed_category_chain), selectinload(Event.person_links).joinedload('person').joinedload( 'user').load_only('is_system'), joinedload(Event.own_venue), joinedload(Event.own_room).options(raiseload('*'), joinedload('location')), )) events_by_id = {e.id: e for e in query} events = [events_by_id[e.id] for e in objs] res = HTMLStrippingEventSchema(many=True).dump(events) return pagenav, EventResultSchema(many=True).load(res)
def category_events(self, catIds): from indico.modules.events import Event query = (Event.query .filter(~Event.is_deleted, Event.category_chain_overlaps(map(int, catIds)), Event.happens_between(self._fromDT, self._toDT)) .options(joinedload('category').load_only('id', 'title'))) return self._process(x.as_legacy for x in query)
def category(self, idlist): query = (Event.query .filter(~Event.is_deleted, Event.category_chain_overlaps(map(int, idlist)), Event.happens_between(self._fromDT, self._toDT)) .options(*self._get_query_options(self._detail_level))) query = self._update_query(query) return self.serialize_events(x for x in query if self._filter_event(x) and x.can_access(self.user))
def get_min_year(category_id=None): """Get the min year. :param category_id: The category ID to get statistics for. :return: The year. """ category_filter = Event.category_chain_overlaps(category_id) if category_id else True min_dt = db.session.query(db.func.min(Event.created_dt)).filter(~Event.is_deleted, category_filter).scalar() return min_dt.year if min_dt else date.today().year
def get_min_year(category_id=None): """Get the min year. :param category_id: The category ID to get statistics for. :return: A `datetime` Object. """ category_filter = Event.category_chain_overlaps( category_id) if category_id else True return db.session.query(db.func.min(Event.created_dt)).filter( ~Event.is_deleted, category_filter).scalar()
def category(self, idlist): try: idlist = map(int, idlist) except ValueError: raise HTTPAPIError('Category IDs must be numeric', 400) query = (Event.query .filter(~Event.is_deleted, Event.category_chain_overlaps(idlist), Event.happens_between(self._fromDT, self._toDT)) .options(*self._get_query_options(self._detail_level))) query = self._update_query(query) return self.serialize_events(x for x in query if self._filter_event(x) and x.can_access(self.user))
def search_events(self, q, user, page, category_id, admin_override_enabled): filters = [Event.title_matches(q), ~Event.is_deleted] if category_id is not None: filters.append(Event.category_chain_overlaps(category_id)) query = (Event.query.filter(*filters).options( subqueryload(Event.acl_entries), undefer(Event.effective_protection_mode))) objs, pagenav = self._paginate(query, page, Event.id, user, admin_override_enabled) res = HTMLStrippingEventSchema(many=True).dump(objs) return pagenav, EventResultSchema(many=True).load(res)
def get_events_in_categories(category_ids, user, limit=10): """Get all the user-accessible events in a given set of categories.""" tz = session.tzinfo today = now_utc(False).astimezone(tz).date() query = (Event.query.filter( ~Event.is_deleted, Event.category_chain_overlaps(category_ids), Event.start_dt.astimezone(session.tzinfo) >= today).options( joinedload('category').load_only('id', 'title'), joinedload('series'), subqueryload('acl_entries'), load_only('id', 'category_id', 'start_dt', 'end_dt', 'title', 'access_key', 'protection_mode', 'series_id', 'series_pos', 'series_count')).order_by(Event.start_dt, Event.id)) return get_n_matching(query, limit, lambda x: x.can_access(user))
def get_events_by_year(category_id=None): """Get the number of events for each year. :param category_id: The category ID to get statistics for. Events from subcategories are also included. :return: A dictionary mapping years to event counts. """ category_filter = Event.category_chain_overlaps( category_id) if category_id else True query = (db.session.query( db.cast(db.extract('year', Event.start_dt), db.Integer).label('year'), db.func.count()).filter( ~Event.is_deleted, category_filter).order_by('year').group_by('year')) return dict(query)
def get_events_by_year(category_id=None): """Get the number of events for each year. :param category_id: The category ID to get statistics for. Events from subcategories are also included. :return: An `OrderedDict` mapping years to event counts. """ category_filter = Event.category_chain_overlaps(category_id) if category_id else True query = (db.session .query(db.cast(db.extract('year', Event.start_dt), db.Integer).label('year'), db.func.count()) .filter(~Event.is_deleted, category_filter) .order_by('year') .group_by('year')) return OrderedDict(query)
def get_contribs_by_year(category_id=None): """Get the number of contributions for each year. :param category_id: The category ID to get statistics for. Contributions from subcategories are also included. :return: A dictionary mapping years to contribution counts. """ category_filter = Event.category_chain_overlaps( category_id) if category_id else True query = (db.session.query( db.cast(db.extract('year', TimetableEntry.start_dt), db.Integer).label('year'), db.func.count()).join(TimetableEntry.event).filter( TimetableEntry.type == TimetableEntryType.CONTRIBUTION, ~Event.is_deleted, category_filter).order_by('year').group_by('year')) return dict(query)
def serialize_categories_ical(category_ids, user, event_filter=True, event_filter_fn=None, update_query=None): """Export the events in a category to iCal. :param category_ids: Category IDs to export :param user: The user who needs to be able to access the events :param event_filter: A SQLalchemy criterion to restrict which events will be returned. Usually something involving the start/end date of the event. :param event_filter_fn: A callable that determines which events to include (after querying) :param update_query: A callable that can update the query used to retrieve the events. Must return the updated query object. """ own_room_strategy = joinedload('own_room') own_room_strategy.load_only('building', 'floor', 'number', 'verbose_name') own_room_strategy.lazyload('owner') own_venue_strategy = joinedload('own_venue').load_only('name') query = (Event.query.filter( Event.category_chain_overlaps(category_ids), ~Event.is_deleted, event_filter).options( load_only('id', 'category_id', 'start_dt', 'end_dt', 'title', 'description', 'own_venue_name', 'own_room_name', 'protection_mode', 'access_key'), subqueryload('acl_entries'), joinedload('person_links'), own_room_strategy, own_venue_strategy).order_by(Event.start_dt)) if update_query: query = update_query(query) it = iter(query) if event_filter_fn: it = filter(event_filter_fn, it) events = list(it) # make sure the parent categories are in sqlalchemy's identity cache. # this avoids query spam from `protection_parent` lookups _parent_categs = ( Category._get_chain_query( Category.id.in_({e.category_id for e in events})) # noqa: F841 .options(load_only('id', 'parent_id', 'protection_mode'), joinedload('acl_entries')).all()) return BytesIO(events_to_ical(events, user))
def category(self, idlist, format): try: idlist = map(int, idlist) except ValueError: raise HTTPAPIError('Category IDs must be numeric', 400) if format == 'ics': buf = serialize_categories_ical(idlist, self.user, event_filter=Event.happens_between(self._fromDT, self._toDT), event_filter_fn=self._filter_event, update_query=self._update_query) return send_file('events.ics', buf, 'text/calendar') else: query = (Event.query .filter(~Event.is_deleted, Event.category_chain_overlaps(idlist), Event.happens_between(self._fromDT, self._toDT)) .options(*self._get_query_options(self._detail_level))) query = self._update_query(query) return self.serialize_events(x for x in query if self._filter_event(x) and x.can_access(self.user))
def get_contribs_by_year(category_id=None): """Get the number of contributions for each year. :param category_id: The category ID to get statistics for. Contributions from subcategories are also included. :return: An `OrderedDict` mapping years to contribution counts. """ category_filter = Event.category_chain_overlaps(category_id) if category_id else True query = (db.session .query(db.cast(db.extract('year', TimetableEntry.start_dt), db.Integer).label('year'), db.func.count()) .join(TimetableEntry.event) .filter(TimetableEntry.type == TimetableEntryType.CONTRIBUTION, ~Event.is_deleted, category_filter) .order_by('year') .group_by('year')) return OrderedDict(query)
def serialize_categories_ical(category_ids, user, event_filter=True, event_filter_fn=None, update_query=None): """Export the events in a category to iCal :param category_ids: Category IDs to export :param user: The user who needs to be able to access the events :param event_filter: A SQLalchemy criterion to restrict which events will be returned. Usually something involving the start/end date of the event. :param event_filter_fn: A callable that determines which events to include (after querying) :param update_query: A callable that can update the query used to retrieve the events. Must return the updated query object. """ own_room_strategy = joinedload('own_room') own_room_strategy.load_only('building', 'floor', 'number', 'verbose_name') own_room_strategy.lazyload('owner') own_venue_strategy = joinedload('own_venue').load_only('name') query = (Event.query .filter(Event.category_chain_overlaps(category_ids), ~Event.is_deleted, event_filter) .options(load_only('id', 'category_id', 'start_dt', 'end_dt', 'title', 'description', 'own_venue_name', 'own_room_name', 'protection_mode', 'access_key'), subqueryload('acl_entries'), joinedload('person_links'), own_room_strategy, own_venue_strategy) .order_by(Event.start_dt)) if update_query: query = update_query(query) it = iter(query) if event_filter_fn: it = ifilter(event_filter_fn, it) events = list(it) # make sure the parent categories are in sqlalchemy's identity cache. # this avoids query spam from `protection_parent` lookups _parent_categs = (Category._get_chain_query(Category.id.in_({e.category_id for e in events})) .options(load_only('id', 'parent_id', 'protection_mode'), joinedload('acl_entries')) .all()) cal = ical.Calendar() cal.add('version', '2.0') cal.add('prodid', '-//CERN//INDICO//EN') now = now_utc(False) for event in events: if not event.can_access(user): continue location = ('{} ({})'.format(event.room_name, event.venue_name) if event.venue_name and event.room_name else (event.venue_name or event.room_name)) cal_event = ical.Event() cal_event.add('uid', u'indico-event-{}@{}'.format(event.id, url_parse(config.BASE_URL).host)) cal_event.add('dtstamp', now) cal_event.add('dtstart', event.start_dt) cal_event.add('dtend', event.end_dt) cal_event.add('url', event.external_url) cal_event.add('summary', event.title) cal_event.add('location', location) description = [] if event.person_links: speakers = [u'{} ({})'.format(x.full_name, x.affiliation) if x.affiliation else x.full_name for x in event.person_links] description.append(u'Speakers: {}'.format(u', '.join(speakers))) if event.description: desc_text = unicode(event.description) or u'<p/>' # get rid of RichMarkup try: description.append(unicode(html.fromstring(desc_text).text_content())) except ParserError: # this happens e.g. if desc_text contains only a html comment pass description.append(event.external_url) cal_event.add('description', u'\n'.join(description)) cal.add_component(cal_event) return BytesIO(cal.to_ical())
def serialize_categories_ical(category_ids, user, event_filter=True, event_filter_fn=None, update_query=None): """Export the events in a category to iCal :param category_ids: Category IDs to export :param user: The user who needs to be able to access the events :param event_filter: A SQLalchemy criterion to restrict which events will be returned. Usually something involving the start/end date of the event. :param event_filter_fn: A callable that determines which events to include (after querying) :param update_query: A callable that can update the query used to retrieve the events. Must return the updated query object. """ own_room_strategy = joinedload('own_room') own_room_strategy.load_only('building', 'floor', 'number', 'name') own_room_strategy.lazyload('owner') own_venue_strategy = joinedload('own_venue').load_only('name') query = (Event.query.filter( Event.category_chain_overlaps(category_ids), ~Event.is_deleted, event_filter).options( load_only('id', 'category_id', 'start_dt', 'end_dt', 'title', 'description', 'own_venue_name', 'own_room_name', 'protection_mode', 'access_key'), subqueryload('acl_entries'), joinedload('person_links'), own_room_strategy, own_venue_strategy).order_by(Event.start_dt)) if update_query: query = update_query(query) it = iter(query) if event_filter_fn: it = ifilter(event_filter_fn, it) events = list(it) # make sure the parent categories are in sqlalchemy's identity cache. # this avoids query spam from `protection_parent` lookups _parent_categs = (Category._get_chain_query( Category.id.in_({e.category_id for e in events})).options( load_only('id', 'parent_id', 'protection_mode'), joinedload('acl_entries')).all()) cal = ical.Calendar() cal.add('version', '2.0') cal.add('prodid', '-//CERN//INDICO//EN') now = now_utc(False) for event in events: if not event.can_access(user): continue location = ('{} ({})'.format(event.room_name, event.venue_name) if event.venue_name and event.room_name else (event.venue_name or event.room_name)) cal_event = ical.Event() cal_event.add( 'uid', u'indico-event-{}@{}'.format(event.id, url_parse(config.BASE_URL).host)) cal_event.add('dtstamp', now) cal_event.add('dtstart', event.start_dt) cal_event.add('dtend', event.end_dt) cal_event.add('url', event.external_url) cal_event.add('summary', event.title) cal_event.add('location', location) description = [] if event.person_links: speakers = [ u'{} ({})'.format(x.full_name, x.affiliation) if x.affiliation else x.full_name for x in event.person_links ] description.append(u'Speakers: {}'.format(u', '.join(speakers))) if event.description: desc_text = unicode( event.description) or u'<p/>' # get rid of RichMarkup try: description.append( unicode(html.fromstring(desc_text).text_content())) except ParserError: # this happens e.g. if desc_text contains only a html comment pass description.append(event.external_url) cal_event.add('description', u'\n'.join(description)) cal.add_component(cal_event) return BytesIO(cal.to_ical())
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_attachments(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) attachment_strategy = _apply_acl_entry_strategy( selectinload(Attachment.acl_entries), AttachmentPrincipal) folder_strategy = contains_eager(Attachment.folder) folder_strategy.load_only('id', 'protection_mode', 'link_type', 'category_id', 'event_id', 'linked_event_id', 'contribution_id', 'subcontribution_id', 'session_id') _apply_acl_entry_strategy( folder_strategy.selectinload(AttachmentFolder.acl_entries), AttachmentFolderPrincipal) # event event_strategy = folder_strategy.contains_eager( AttachmentFolder.linked_event) _apply_event_access_strategy(event_strategy) _apply_acl_entry_strategy( event_strategy.selectinload(Event.acl_entries), EventPrincipal) # contribution contrib_strategy = folder_strategy.contains_eager( AttachmentFolder.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 = folder_strategy.contains_eager( AttachmentFolder.subcontribution) subcontrib_strategy.load_only('id', 'contribution_id', 'title') 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 = folder_strategy.contains_eager( AttachmentFolder.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) attachment_filters = [ Attachment.title_matches(q), ~Attachment.is_deleted, ~AttachmentFolder.is_deleted, AttachmentFolder.link_type != LinkType.category, db.or_( AttachmentFolder.link_type != LinkType.event, ~Event.is_deleted, ), db.or_(AttachmentFolder.link_type != LinkType.contribution, ~Contribution.is_deleted & ~contrib_event.is_deleted), db.or_( AttachmentFolder.link_type != LinkType.subcontribution, db.and_( ~SubContribution.is_deleted, ~subcontrib_contrib.is_deleted, ~subcontrib_event.is_deleted, )), db.or_(AttachmentFolder.link_type != LinkType.session, ~Session.is_deleted & ~session_event.is_deleted) ] if category_id is not None: attachment_filters.append( AttachmentFolder.event.has( Event.category_chain_overlaps(category_id))) if event_id is not None: attachment_filters.append(AttachmentFolder.event_id == event_id) query = ( Attachment.query.join( Attachment.folder).filter(*attachment_filters).options( folder_strategy, attachment_strategy, joinedload( Attachment.user).joinedload('_affiliation')).outerjoin( AttachmentFolder.linked_event).outerjoin( AttachmentFolder.contribution).outerjoin( Contribution.event.of_type(contrib_event)). outerjoin(Contribution.session.of_type(contrib_session)).outerjoin( AttachmentFolder.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( AttachmentFolder.session).outerjoin( Session.event.of_type(session_event))) objs, pagenav = self._paginate(query, page, Attachment.id, user, admin_override_enabled) query = (Attachment.query.filter(Attachment.id.in_( a.id for a in objs)).options( joinedload(Attachment.folder).options( joinedload(AttachmentFolder.subcontribution), joinedload(AttachmentFolder.event).options( undefer(Event.detailed_category_chain))))) attachments_by_id = {a.id: a for a in query} attachments = [attachments_by_id[a.id] for a in objs] res = AttachmentSchema(many=True).dump(attachments) return pagenav, AttachmentResultSchema(many=True).load(res)
def search_contribs(self, q, user, page, category_id, event_id, admin_override_enabled): # XXX: Ideally we would search in subcontributions as well, but our pagination # does not really work when we do not have a single unique ID contrib_filters = [ Contribution.title_matches(q) | Contribution.description_matches(q), ~Contribution.is_deleted, ~Event.is_deleted ] if category_id is not None: contrib_filters.append(Event.category_chain_overlaps(category_id)) if event_id is not None: contrib_filters.append(Contribution.event_id == event_id) query = (Contribution.query.filter(*contrib_filters).join( Contribution.event).options( load_only('id', 'session_id', 'event_id', 'protection_mode'), undefer(Contribution.effective_protection_mode), _apply_acl_entry_strategy( selectinload(Contribution.acl_entries), ContributionPrincipal), joinedload(Contribution.session).options( load_only('id', 'protection_mode', 'event_id'), selectinload(Session.acl_entries)), contains_eager('event').options( _apply_acl_entry_strategy(selectinload(Event.acl_entries), EventPrincipal)))) objs, pagenav = self._paginate(query, page, Contribution.id, user, admin_override_enabled) event_strategy = joinedload(Contribution.event) event_strategy.joinedload(Event.own_venue) event_strategy.joinedload(Event.own_room).options( raiseload('*'), joinedload('location')) event_strategy.undefer(Event.detailed_category_chain) session_strategy = joinedload(Contribution.session) session_strategy.joinedload(Session.own_venue) session_strategy.joinedload(Session.own_room).options( raiseload('*'), joinedload('location')) session_block_strategy = joinedload(Contribution.session_block) session_block_strategy.joinedload(SessionBlock.own_venue) session_block_strategy.joinedload(SessionBlock.own_room).options( raiseload('*'), joinedload('location')) session_block_session_strategy = session_block_strategy.joinedload( SessionBlock.session) session_block_session_strategy.joinedload(Session.own_venue) session_block_session_strategy.joinedload(Session.own_room).options( raiseload('*'), joinedload('location')) query = (Contribution.query.filter( Contribution.id.in_(c.id for c in objs)).options( selectinload(Contribution.person_links).joinedload( 'person').joinedload('user').load_only('is_system'), event_strategy, session_strategy, session_block_strategy, joinedload(Contribution.type), joinedload(Contribution.own_venue), joinedload(Contribution.own_room).options( raiseload('*'), joinedload('location')), joinedload(Contribution.timetable_entry), )) contribs_by_id = {c.id: c for c in query} contribs = [contribs_by_id[c.id] for c in objs] res = HTMLStrippingContributionSchema(many=True).dump(contribs) return pagenav, ContributionResultSchema(many=True).load(res)