예제 #1
0
파일: util.py 프로젝트: bkolobara/indico
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()
예제 #2
0
파일: controllers.py 프로젝트: jas01/indico
 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)
예제 #3
0
파일: util.py 프로젝트: iammujtaba/indico
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
예제 #4
0
파일: serialize.py 프로젝트: fph/indico
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())
예제 #5
0
파일: util.py 프로젝트: ThiefMaster/indico
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
예제 #6
0
 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)
예제 #7
0
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))
예제 #9
0
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()
예제 #10
0
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())
예제 #11
0
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'))
예제 #12
0
    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)
예제 #13
0
파일: api.py 프로젝트: fph/indico
 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)
예제 #14
0
파일: api.py 프로젝트: fph/indico
 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))
예제 #15
0
파일: util.py 프로젝트: mkopcic/indico
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
예제 #16
0
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()
예제 #17
0
파일: api.py 프로젝트: wtakase/indico
 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))
예제 #18
0
    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)
예제 #19
0
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))
예제 #20
0
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)
예제 #21
0
파일: util.py 프로젝트: bkolobara/indico
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)
예제 #22
0
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)
예제 #23
0
파일: serialize.py 프로젝트: javfg/indico
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))
예제 #24
0
 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))
예제 #25
0
파일: api.py 프로젝트: ipaste/indico
 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))
예제 #26
0
파일: util.py 프로젝트: bkolobara/indico
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)
예제 #27
0
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())
예제 #28
0
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())
예제 #29
0
    def search_notes(self, q, user, page, category_id, event_id,
                     admin_override_enabled):
        contrib_event = db.aliased(Event)
        contrib_session = db.aliased(Session)
        subcontrib_contrib = db.aliased(Contribution)
        subcontrib_session = db.aliased(Session)
        subcontrib_event = db.aliased(Event)
        session_event = db.aliased(Event)

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

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

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

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

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

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

        res = HTMLStrippingEventNoteSchema(many=True).dump(notes)
        return pagenav, EventNoteResultSchema(many=True).load(res)
예제 #30
0
    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)
예제 #31
0
    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)