Exemple #1
0
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
Exemple #2
0
def get_events_with_abstract_reviewer_convener(user, dt=None):
    """
    Return a dict of event ids and the abstract reviewing related
    roles the user has in that event.

    :param user: A `User`
    :param dt: Only include events taking place on/after that date
    """
    data = defaultdict(set)
    # global reviewer/convener
    mapping = {'global_abstract_reviewer_for_events': 'abstract_reviewer',
               'global_convener_for_events': 'track_convener'}
    for rel, role in mapping.iteritems():
        query = (Event.query.with_parent(user, rel)
                 .filter(Event.ends_after(dt), ~Event.is_deleted)
                 .options(load_only('id')))
        for event in query:
            data[event.id].add(role)
    # track reviewer/convener
    mapping = {'abstract_reviewer_for_tracks': 'abstract_reviewer',
               'convener_for_tracks': 'track_convener'}
    for rel, role in mapping.iteritems():
        query = (Track.query.with_parent(user, rel)
                 .join(Track.event_new)
                 .filter(Event.ends_after(dt), ~Event.is_deleted)
                 .options(load_only('event_id')))
        for track in query:
            data[track.event_id].add(role)
    return data
Exemple #3
0
 def event(self, idlist):
     query = (Event.find(Event.id.in_(idlist),
                         ~Event.is_deleted,
                         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))
Exemple #4
0
def get_events_with_abstract_persons(user, dt=None):
    """
    Return a dict of event ids and the abstract submission related
    roles the user has in that event.

    :param user: A `User`
    :param dt: Only include events taking place on/after that date
    """
    data = defaultdict(set)
    bad_states = {AbstractState.withdrawn, AbstractState.rejected}
    # submitter
    query = (Abstract.query
             .filter(~Event.is_deleted,
                     ~Abstract.is_deleted,
                     ~Abstract.state.in_(bad_states),
                     Event.ends_after(dt),
                     Abstract.submitter == user)
             .join(Abstract.event_new)
             .options(load_only('event_id')))
    for abstract in query:
        data[abstract.event_id].add('abstract_submitter')
    # person
    abstract_criterion = db.and_(~Abstract.state.in_(bad_states), ~Abstract.is_deleted)
    query = (user.event_persons
             .filter(~Event.is_deleted,
                     Event.ends_after(dt),
                     EventPerson.abstract_links.any(AbstractPersonLink.abstract.has(abstract_criterion)))
             .join(EventPerson.event_new)
             .options(load_only('event_id')))
    for person in query:
        data[person.event_id].add('abstract_person')
    return data
Exemple #5
0
 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))
Exemple #6
0
 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)
Exemple #7
0
def create_event(category, event_type, data, add_creator_as_manager=True, features=None):
    """Create a new event.

    :param category: The category in which to create the event
    :param event_type: An `EventType` value
    :param data: A dict containing data used to populate the event
    :param add_creator_as_manager: Whether the creator (current user)
                                   should be added as a manager
    :param features: A list of features that will be enabled for the
                     event. If set, only those features will be used
                     and the default feature set for the event type
                     will be ignored.
    """
    event = Event(category=category, type_=event_type)
    data.setdefault('creator', session.user)
    theme = data.pop('theme', None)
    person_link_data = data.pop('person_link_data', {})
    event.populate_from_dict(data)
    db.session.flush()
    event.person_link_data = person_link_data
    if theme is not None:
        layout_settings.set(event, 'timetable_theme', theme)
    if add_creator_as_manager:
        with event.logging_disabled:
            event.update_principal(event.creator, full_access=True)
    if features is not None:
        features_event_settings.set(event, 'enabled', features)
    db.session.flush()
    signals.event.created.send(event)
    logger.info('Event %r created in %r by %r ', event, category, session.user)
    event.log(EventLogRealm.event, EventLogKind.positive, 'Event', 'Event created', session.user)
    db.session.flush()
    return event
Exemple #8
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())
Exemple #9
0
 def category_extra(self, ids):
     if self._toDT is None:
         has_future_events = False
     else:
         query = Event.find(Event.category_id.in_(ids), ~Event.is_deleted, Event.start_dt > self._toDT)
         has_future_events = query.has_rows()
     return {"eventCategories": self._build_category_path_data(ids), "moreFutureEvents": has_future_events}
Exemple #10
0
        def _iterate_objs(query_string):
            query = (Event.query
                     .filter(Event.title_matches(to_unicode(query_string)),
                             ~Event.is_deleted)
                     .options(undefer('effective_protection_mode')))
            sort_dir = db.desc if self._descending else db.asc
            if self._orderBy == 'start':
                query = query.order_by(sort_dir(Event.start_dt))
            elif self._orderBy == 'end':
                query = query.order_by(sort_dir(Event.end_dt))
            elif self._orderBy == 'id':
                query = query.order_by(sort_dir(Event.id))
            elif self._orderBy == 'title':
                query = query.order_by(sort_dir(db.func.lower(Event.title)))

            counter = 0
            # Query the DB in chunks of 1000 records per query until the limit is satisfied
            for event in query.yield_per(1000):
                if event.can_access(self._user):
                    counter += 1
                    # Start yielding only when the counter reaches the given offset
                    if (self._offset is None) or (counter > self._offset):
                        yield event
                        # Stop querying the DB when the limit is satisfied
                        if (self._limit is not None) and (counter == self._offset + self._limit):
                            break
Exemple #11
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)
Exemple #12
0
 def deserialize(self):
     if not self.force and self.data['indico_version'] != indico.__version__:
         click.secho('Version mismatch: trying to import event exported with {} to version {}'
                     .format(self.data['indico_version'], indico.__version__), fg='red')
         return None
     self._load_users(self.data)
     for tablename, tabledata in self.data['objects']:
         self._deserialize_object(db.metadata.tables[tablename], tabledata)
     if self.deferred_idrefs:
         # Any reference to an ID that was exported need to be replaced
         # with an actual ID at some point - either immediately (if the
         # referenced row was already imported) or later (usually in case
         # of circular dependencies where one of the IDs is not available
         # when the row is inserted).
         click.secho('BUG: Not all deferred idrefs have been consumed', fg='red')
         for uuid, values in self.deferred_idrefs.iteritems():
             click.secho('{}:'.format(uuid), fg='yellow', bold=True)
             for table, col, pk_value in values:
                 click.secho('  - {}.{} ({})'.format(table.fullname, col, pk_value), fg='yellow')
         raise Exception('Not all deferred idrefs have been consumed')
     event = Event.get(self.event_id)
     event.log(EventLogRealm.event, EventLogKind.other, 'Event', 'Event imported from another Indico instance')
     self._associate_users_by_email(event)
     db.session.flush()
     return event
Exemple #13
0
 def _getParams(self):
     super(NoteExportHook, self)._getParams()
     event = self._obj = Event.get(self._pathParams['event_id'], is_deleted=False)
     if event is None:
         raise HTTPAPIError('No such event', 404)
     session_id = self._pathParams.get('session_id')
     if session_id:
         self._obj = Session.query.with_parent(event).filter_by(id=session_id).first()
         if self._obj is None:
             raise HTTPAPIError("No such session", 404)
     contribution_id = self._pathParams.get('contribution_id')
     if contribution_id:
         contribution = self._obj = (Contribution.query.with_parent(event)
                                     .filter_by(id=contribution_id, is_deleted=False)
                                     .first())
         if contribution is None:
             raise HTTPAPIError("No such contribution", 404)
         subcontribution_id = self._pathParams.get('subcontribution_id')
         if subcontribution_id:
             self._obj = SubContribution.query.with_parent(contribution).filter_by(id=subcontribution_id,
                                                                                   is_deleted=False).first()
             if self._obj is None:
                 raise HTTPAPIError("No such subcontribution", 404)
     self._note = EventNote.get_for_linked_object(self._obj, preload_event=False)
     if self._note is None or self._note.is_deleted:
         raise HTTPAPIError("No such note", 404)
Exemple #14
0
def event_or_shorturl(confId, shorturl_namespace=False, force_overview=False):
    func = None
    event_ = Event.get(int(confId)) if confId.isdigit() else None
    if event_ and event_.is_deleted:
        raise NotFound(_('This event has been deleted.'))
    elif event_:
        # For obvious reasons an event id always comes first.
        # If it's used within the short url namespace we redirect to the event namespace, otherwise
        # we call the RH to display the event
        if shorturl_namespace:
            func = lambda: redirect(event_.url)
        else:
            request.view_args['confId'] = int(request.view_args['confId'])
            func = lambda: RHDisplayEvent().process()
    else:
        shorturl_event = (Event.query
                          .filter(db.func.lower(Event.url_shortcut) == confId.lower(),
                                  ~Event.is_deleted)
                          .one_or_none())
        if (shorturl_namespace or config.ROUTE_OLD_URLS) and shorturl_event:
            if shorturl_namespace:
                # Correct namespace => redirect to the event
                func = lambda: redirect(shorturl_event.url)
            else:
                # Old event namespace => 301-redirect to the new shorturl first to get Google etc. to update it
                func = lambda: redirect(shorturl_event.short_url, 301)
        elif is_legacy_id(confId):
            mapping = LegacyEventMapping.find_first(legacy_event_id=confId)
            if mapping is not None:
                url = url_for('events.display', confId=mapping.event_id)
                func = lambda: redirect(url, 301)

    if func is None:
        raise NotFound(_('An event with this ID/shortcut does not exist.'))
    return func()
Exemple #15
0
def test_deleted_relationships(db, dummy_event_new):
    event = dummy_event_new
    assert not event.contributions
    assert not event.sessions
    s = Session(event_new=event, title='s')
    sd = Session(event_new=event, title='sd', is_deleted=True)
    c = Contribution(event_new=event, title='c', session=sd, duration=timedelta(minutes=30))
    cd = Contribution(event_new=event, title='cd', session=sd, duration=timedelta(minutes=30), is_deleted=True)
    sc = SubContribution(contribution=c, title='sc', duration=timedelta(minutes=10))
    scd = SubContribution(contribution=c, title='scd', duration=timedelta(minutes=10), is_deleted=True)
    db.session.flush()
    db.session.expire_all()
    # reload all the objects from the db
    event = Event.get(event.id)
    s = Session.get(s.id)
    sd = Session.get(sd.id)
    c = Contribution.get(c.id)
    cd = Contribution.get(cd.id)
    sc = SubContribution.get(sc.id)
    scd = SubContribution.get(scd.id)
    # deleted items should not be in the lists
    assert event.sessions == [s]
    assert event.contributions == [c]
    assert sd.contributions == [c]
    assert c.subcontributions == [sc]
    # the other direction should work fine even in case of deletion
    assert s.event_new == event
    assert sd.event_new == event
    assert c.event_new == event
    assert cd.event_new == event
    assert sc.contribution == c
    assert scd.contribution == c
Exemple #16
0
def get_events_with_linked_sessions(user, dt=None):
    """Returns a dict with keys representing event_id and the values containing
    data about the user rights for sessions within the event

    :param user: A `User`
    :param dt: Only include events taking place on/after that date
    """
    query = (user.in_session_acls
             .options(load_only('session_id', 'roles', 'full_access', 'read_access'))
             .options(noload('*'))
             .options(contains_eager(SessionPrincipal.session).load_only('event_id'))
             .join(Session)
             .join(Event, Event.id == Session.event_id)
             .filter(~Session.is_deleted, ~Event.is_deleted, Event.ends_after(dt)))
    data = defaultdict(set)
    for principal in query:
        roles = data[principal.session.event_id]
        if 'coordinate' in principal.roles:
            roles.add('session_coordinator')
        if 'submit' in principal.roles:
            roles.add('session_submission')
        if principal.full_access:
            roles.add('session_manager')
        if principal.read_access:
            roles.add('session_access')
    return data
Exemple #17
0
 def category_events(self, catIds):
     from indico.modules.events import Event
     query = (Event.query
              .filter(~Event.is_deleted,
                      Event.category_chain.overlap(map(int, catIds)),
                      Event.happens_between(self._fromDT, self._toDT)))
     return self._process(x.as_legacy for x in query)
Exemple #18
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()
Exemple #19
0
def get_events_with_linked_sessions(user, from_dt=None, to_dt=None):
    """Returns a dict with keys representing event_id and the values containing
    data about the user rights for sessions within the event

    :param user: A `User`
    :param from_dt: The earliest event start time to look for
    :param to_dt: The latest event start time to look for
    """
    query = (user.in_session_acls
             .options(load_only('session_id', 'roles', 'full_access', 'read_access'))
             .options(noload('*'))
             .options(contains_eager(SessionPrincipal.session).load_only('event_id'))
             .join(Session)
             .join(Event, Event.id == Session.event_id)
             .filter(~Session.is_deleted, ~Event.is_deleted, Event.starts_between(from_dt, to_dt)))
    data = defaultdict(set)
    for principal in query:
        roles = data[principal.session.event_id]
        if 'coordinate' in principal.roles:
            roles.add('session_coordinator')
        if 'submit' in principal.roles:
            roles.add('session_submission')
        if principal.full_access:
            roles.add('session_manager')
        if principal.read_access:
            roles.add('session_access')
    return data
Exemple #20
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'))
Exemple #21
0
def create_event(category, event_type, data, add_creator_as_manager=True, features=None):
    from indico.modules.rb_new.operations.bookings import create_booking_for_event
    """Create a new event.

    :param category: The category in which to create the event
    :param event_type: An `EventType` value
    :param data: A dict containing data used to populate the event
    :param add_creator_as_manager: Whether the creator (current user)
                                   should be added as a manager
    :param features: A list of features that will be enabled for the
                     event. If set, only those features will be used
                     and the default feature set for the event type
                     will be ignored.
    """
    event = Event(category=category, type_=event_type)
    data.setdefault('creator', session.user)
    theme = data.pop('theme', None)
    create_booking = data.pop('create_booking', False)
    person_link_data = data.pop('person_link_data', {})
    event.populate_from_dict(data)
    db.session.flush()
    event.person_link_data = person_link_data
    if theme is not None:
        layout_settings.set(event, 'timetable_theme', theme)
    if add_creator_as_manager:
        with event.logging_disabled:
            event.update_principal(event.creator, full_access=True)
    if features is not None:
        features_event_settings.set(event, 'enabled', features)
    db.session.flush()
    signals.event.created.send(event)
    logger.info('Event %r created in %r by %r ', event, category, session.user)
    event.log(EventLogRealm.event, EventLogKind.positive, 'Event', 'Event created', session.user)
    db.session.flush()
    if create_booking:
        room_id = data['location_data'].pop('room_id', None)
        if room_id:
            booking = create_booking_for_event(room_id, event)
            if booking:
                logger.info('Booking %r created for event %r', booking, event)
                log_data = {'Room': booking.room.full_name,
                            'Date': booking.start_dt.strftime('%d/%m/%Y'),
                            'Times': '%s - %s' % (booking.start_dt.strftime('%H:%M'), booking.end_dt.strftime('%H:%M'))}
                event.log(EventLogRealm.event, EventLogKind.positive, 'Event', 'Room booked for the event',
                          session.user, data=log_data)
                db.session.flush()
    return event
Exemple #22
0
        def _iterate_objs(query_string):
            query = Event.find(Event.title_matches(to_unicode(query_string)), ~Event.is_deleted)
            if self._orderBy == 'start':
                query = query.order_by(Event.start_dt)
            elif self._orderBy == 'id':
                query = query.order_by(Event.id)

            counter = 0
            # Query the DB in chunks of 1000 records per query until the limit is satisfied
            for event in query.yield_per(1000):
                if event.can_access(self._aw.getUser().user if self._aw.getUser() else None):
                    counter += 1
                    # Start yielding only when the counter reaches the given offset
                    if (self._offset is None) or (counter > self._offset):
                        yield event
                        # Stop querying the DB when the limit is satisfied
                        if (self._limit is not None) and (counter == self._offset + self._limit):
                            break
Exemple #23
0
 def _process_args(self):
     if 'confId' in request.view_args:
         self.obj = Event.get_one(request.view_args['confId'], is_deleted=False)
         self.obj_type = 'event'
     elif 'category_id' in request.view_args:
         self.obj = Category.get_one(request.view_args['category_id'], is_deleted=False)
         self.obj_type = 'category' if not self.obj.is_root else None
     else:
         self.obj = Category.get_root()
         self.obj_type = None
Exemple #24
0
 def _getParams(self):
     super(AgreementExportHook, self)._getParams()
     type_ = self._pathParams['agreement_type']
     try:
         self._definition = get_agreement_definitions()[type_]
     except KeyError:
         raise HTTPAPIError('No such agreement type', 404)
     self.event = Event.get(self._pathParams['event_id'], is_deleted=False)
     if self.event is None:
         raise HTTPAPIError('No such event', 404)
Exemple #25
0
def get_events_created_by(user, from_dt=None, to_dt=None):
    """Gets the IDs of events created by the user

    :param user: A `User`
    :param from_dt: The earliest event start time to look for
    :param to_dt: The latest event start time to look for
    :return: A set of event ids
    """
    query = user.created_events.filter(~Event.is_deleted, Event.starts_between(from_dt, to_dt))
    return {event.id for event in query}
Exemple #26
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))
Exemple #27
0
 def category_extra(self, ids):
     if self._toDT is None:
         has_future_events = False
     else:
         query = Event.find(Event.category_id.in_(ids), ~Event.is_deleted, Event.start_dt > self._toDT)
         has_future_events = db.session.query(query.exists()).one()[0]
     return {
         'eventCategories': self._build_category_path_data(ids),
         'moreFutureEvents': has_future_events
     }
Exemple #28
0
def get_events_created_by(user, dt=None):
    """Gets the IDs of events created by the user

    :param user: A `User`
    :param dt: Only include events taking place on/after that date
    :return: A set of event ids
    """
    query = (user.created_events
             .filter(~Event.is_deleted, Event.ends_after(dt))
             .options(load_only('id')))
    return {event.id for event in query}
Exemple #29
0
def restore(event_id):
    """Restores a deleted event."""
    event = Event.get(event_id)
    if event is None:
        click.secho('This event does not exist', fg='red')
        sys.exit(1)
    elif not event.is_deleted:
        click.secho('This event is not deleted', fg='yellow')
        sys.exit(1)
    event.is_deleted = False
    db.session.commit()
    click.secho('Event undeleted: "{}"'.format(event.title), fg='green')
Exemple #30
0
 def validate_entries(self, field):
     if field.errors:
         return
     for entry in field.data:
         if entry['days'] < 0:
             raise ValidationError(_("'Days' must be a positive integer"))
         if entry['type'] not in {'category', 'event'}:
             raise ValidationError(_('Invalid type'))
         if entry['type'] == 'category' and not Category.get(entry['id'], is_deleted=False):
             raise ValidationError(_('Invalid category: {}').format(entry['id']))
         if entry['type'] == 'event' and not Event.get(entry['id'], is_deleted=False):
             raise ValidationError(_('Invalid event: {}').format(entry['id']))
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))
Exemple #32
0
 def _create_event(id_=None, legacy=False, **kwargs):
     conf = MockConference()
     # we specify `acl_entries` so SA doesn't load it when accessing it for
     # the first time, which would require no_autoflush blocks in some cases
     now = now_utc(exact=False)
     kwargs.setdefault('type_', EventType.meeting)
     kwargs.setdefault(
         'title', u'dummy#{}'.format(id_) if id_ is not None else u'dummy')
     kwargs.setdefault('start_dt', now)
     kwargs.setdefault('end_dt', now + timedelta(hours=1))
     kwargs.setdefault('timezone', 'UTC')
     kwargs.setdefault('category', dummy_category)
     conf.as_event = Event(id=id_,
                           creator=dummy_user,
                           acl_entries=set(),
                           **kwargs)
     db.session.flush()
     conf.id = str(conf.as_event.id)
     ch.add(conf)
     _events.append(conf)
     return conf if legacy else conf.as_event
Exemple #33
0
        def _iterate_objs(query_string):
            query = (Event.query
                     .filter(Event.title_matches(to_unicode(query_string)),
                             ~Event.is_deleted)
                     .options(undefer('effective_protection_mode')))
            if self._orderBy == 'start':
                query = query.order_by(Event.start_dt)
            elif self._orderBy == 'id':
                query = query.order_by(Event.id)

            counter = 0
            # Query the DB in chunks of 1000 records per query until the limit is satisfied
            for event in query.yield_per(1000):
                if event.can_access(self._aw.getUser().user if self._aw.getUser() else None):
                    counter += 1
                    # Start yielding only when the counter reaches the given offset
                    if (self._offset is None) or (counter > self._offset):
                        yield event
                        # Stop querying the DB when the limit is satisfied
                        if (self._limit is not None) and (counter == self._offset + self._limit):
                            break
Exemple #34
0
def _send_email(with_event):
    from flask import session
    from indico.core.notifications import send_email, make_email
    from indico.modules.events import Event
    from indico.modules.users import User
    from indico.web.flask.templating import get_template_module
    tpl = get_template_module('users/emails/registration_request_accepted.txt',
                              user=User.get(6))
    kwargs = {}
    if with_event:
        kwargs = {
            'event': Event.get(654658),
            'module': 'Test',
            'user': session.user
        }
    # send_email(make_email('m\[email protected]', template=tpl), **kwargs)
    # send_email(make_email('*****@*****.**', template=tpl), **kwargs)
    from indico.modules.events.registration.notifications import _notify_registration
    from indico.modules.events.registration.models.registrations import Registration
    _notify_registration(Registration.get(56757),
                         'registration_creation_to_registrant.html')
Exemple #35
0
 def _process(self):
     self.user.settings.set('suggest_categories', True)
     tz = timezone(DisplayTZ().getDisplayTZ())
     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(session.tzinfo).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 WPUserDashboard.render_template(
         'dashboard.html',
         'dashboard',
         timezone=unicode(tz),
         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)
Exemple #36
0
def get_object_from_args(args=None):
    """Retrieve an event object from request arguments.

    This utility is meant to be used in cases where the same controller
    can deal with objects attached to various parts of an event which
    use different URLs to indicate which object to use.

    :param args: The request arguments. If unspecified,
                 ``request.view_args`` is used.
    :return: An ``(object_type, event, object)`` tuple.  The event is
             always the :class:`Event` associated with the object.
             The object may be an `Event`, `Session`, `Contribution`
             or `SubContribution`.  If the object does not exist,
             ``(object_type, None, None)`` is returned.
    """
    if args is None:
        args = request.view_args
    object_type = args['object_type']
    event = Event.get(args['event_id'], is_deleted=False)
    if event is None:
        obj = None
    elif object_type == 'event':
        obj = event
    elif object_type == 'session':
        obj = Session.query.with_parent(event).filter_by(id=args['session_id']).first()
    elif object_type == 'contribution':
        obj = Contribution.query.with_parent(event).filter_by(id=args['contrib_id']).first()
    elif object_type == 'subcontribution':
        obj = (SubContribution.query
               .filter(SubContribution.id == args['subcontrib_id'],
                       ~SubContribution.is_deleted,
                       SubContribution.contribution.has(event=event, id=args['contrib_id'], is_deleted=False))
               .first())
    else:
        raise ValueError(f'Unexpected object type: {object_type}')
    if obj is not None:
        return object_type, event, obj
    else:
        return object_type, None, None
Exemple #37
0
def event_or_shorturl(confId, shorturl_namespace=False, force_overview=False):
    func = None
    event_ = Event.get(int(confId)) if confId.isdigit() else None
    if event_ and event_.is_deleted:
        raise NotFound(_('This event has been deleted.'))
    elif event_:
        # For obvious reasons an event id always comes first.
        # If it's used within the short url namespace we redirect to the event namespace, otherwise
        # we call the RH to display the event
        if shorturl_namespace:
            func = lambda: redirect(event_.url)
        else:
            params = request.args.to_dict()
            params['confId'] = confId
            request.view_args['confId'] = int(request.view_args['confId'])
            func = lambda: RHDisplayEvent().process(params)
    else:
        shorturl_event = (Event.query.filter(
            db.func.lower(Event.url_shortcut) == confId.lower(),
            ~Event.is_deleted).one_or_none())
        if (shorturl_namespace or
                current_app.config['INDICO_COMPAT_ROUTES']) and shorturl_event:
            if shorturl_namespace:
                # Correct namespace => redirect to the event
                func = lambda: redirect(shorturl_event.url)
            else:
                # Old event namespace => 301-redirect to the new shorturl first to get Google etc. to update it
                func = lambda: redirect(shorturl_event.short_url, 301)
        elif is_legacy_id(confId):
            mapping = LegacyEventMapping.find_first(legacy_event_id=confId)
            if mapping is not None:
                url = url_for('events.display', confId=mapping.event_id)
                func = lambda: redirect(url, 301)

    if func is None:
        raise NotFound(_('An event with this ID/shortcut does not exist.'))
    return func()
Exemple #38
0
def event_or_shorturl(event_id,
                      shorturl_namespace=False,
                      force_overview=False):
    event = Event.get(int(event_id)) if event_id.isdigit() and (
        event_id[0] != '0' or event_id == '0') else None
    if event and event.is_deleted:
        raise NotFound(_('This event has been deleted.'))
    elif event:
        # For obvious reasons an event id always comes first.
        # If it's used within the short url namespace we redirect to the event namespace, otherwise
        # we call the RH to display the event
        if shorturl_namespace:
            return redirect(event.url)
        elif not request.path.endswith('/'):
            return redirect(event.url, 301)
        else:
            request.view_args['event_id'] = int(event_id)
            return RHDisplayEvent().process()
    else:
        shorturl_event = (Event.query.filter(
            db.func.lower(Event.url_shortcut) == event_id.lower(),
            ~Event.is_deleted).one_or_none())
        if (shorturl_namespace or config.ROUTE_OLD_URLS) and shorturl_event:
            if shorturl_namespace:
                # Correct namespace => redirect to the event
                return redirect(shorturl_event.url)
            else:
                # Old event namespace => 301-redirect to the new shorturl first to get Google etc. to update it
                return redirect(shorturl_event.short_url, 301)
        elif is_legacy_id(event_id):
            mapping = LegacyEventMapping.query.filter_by(
                legacy_event_id=event_id).first()
            if mapping is not None:
                url = url_for('events.display', event_id=mapping.event_id)
                return redirect(url, 301)

    raise NotFound(_('An event with this ID/shortcut does not exist.'))
Exemple #39
0
 def _getParams(self):
     super(AttachmentsExportHook, self)._getParams()
     event = self._obj = Event.get(self._pathParams['event_id'],
                                   is_deleted=False)
     if event is None:
         raise HTTPAPIError('No such event', 404)
     session_id = self._pathParams.get('session_id')
     if session_id:
         self._obj = Session.query.with_parent(event).filter_by(
             id=session_id).first()
         if self._obj is None:
             raise HTTPAPIError("No such session", 404)
     contribution_id = self._pathParams.get('contribution_id')
     if contribution_id:
         contribution = self._obj = Contribution.query.with_parent(
             event).filter_by(id=contribution_id).first()
         if contribution is None:
             raise HTTPAPIError("No such contribution", 404)
         subcontribution_id = self._pathParams.get('subcontribution_id')
         if subcontribution_id:
             self._obj = SubContribution.query.with_parent(
                 contribution).filter_by(id=subcontribution_id).first()
             if self._obj is None:
                 raise HTTPAPIError("No such subcontribution", 404)
 def migrate(self):
     all_series = self.get_event_series()
     all_series_ids = set(chain.from_iterable(all_series))
     events = {
         e.id: e
         for e in Event.find(Event.id.in_(all_series_ids)).options(
             load_only('id', 'series_id'))
     }
     for series in all_series:
         series &= set(events)
         if len(series) < 2:
             self.print_warning('Skipping single-event series: {}'.format(
                 sorted(series)))
             continue
         es = EventSeries(show_sequence_in_title=False)
         for id_ in series:
             events[id_].series = es
         if not self.quiet:
             self.print_success(repr(series))
     (AttachmentFolder.query.filter(
         AttachmentFolder.title.op('~')('^part\d+$')).update(
             {AttachmentFolder.is_deleted: True},
             synchronize_session=False))
     db.session.commit()
Exemple #41
0
 def _process_args(self):
     RHUserBase._process_args(self)
     self.event = (
         Event.get_or_404(request.view_args['event_id']) if 'event_id' in request.view_args else None
     )
Exemple #42
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())
Exemple #43
0
 def _migrate_menu(self, event, container, parent=None, used=None):
     if used is None:
         used = set()
     for pos, item in enumerate(container._listLink, 1):
         data = {
             'parent': parent,
             'event_id': int(event.id),
             'is_enabled': item._active,
             'position': pos
         }
         item_type = item.__class__.__name__
         if item_type == 'SystemLink':
             if item._name in REMOVED_MENU_NAMES:
                 continue
             data['name'] = MENU_ENTRY_NAME_MAP[item._name]
             if not parent and data['name'] in NOT_TOP_LEVEL_NAMES:
                 self.print_warning(cformat(
                     '%{yellow}Skipping top-level menu entry {}').format(
                         data['name']),
                                    event_id=event.id)
                 continue
             elif data['name'] in used:
                 self.print_error(
                     cformat('%{red!}duplicate menu entry name {}; skipping'
                             ).format(data['name']),
                     event_id=event.id)
                 continue
             used.add(data['name'])
             data['title'] = _sanitize_title(item._caption)
             if not data['title']:
                 data['title'] = None
                 self.print_warning(cformat(
                     '%{yellow!}Menu entry {} has no title; using default').
                                    format(data['name']),
                                    event_id=event.id)
             elif data['title'].lower() in DEFAULT_MENU_TITLES[
                     data['name']]:
                 data['title'] = None
             if item._name == 'chatrooms':
                 data['plugin'] = 'chat'
                 data['type'] = MenuEntryType.plugin_link
             else:
                 data['type'] = MenuEntryType.internal_link
         elif item_type == 'Spacer':
             data['type'] = MenuEntryType.separator
         elif item_type == 'ExternLink':
             data['type'] = MenuEntryType.user_link
             data['title'] = _sanitize_title(item._caption)
             data['link_url'] = item._URL.strip()
             if not data['link_url']:
                 if getattr(item, '_listLink', None):
                     self.print_warning(cformat(
                         '%{yellow!}Link "{}" has no URL but children').
                                        format(data['title']),
                                        event_id=event.id)
                 else:
                     self.print_warning(cformat(
                         '%{yellow}Skipping link "{}" with no URL').format(
                             data['title']),
                                        event_id=event.id)
                     continue
             if not data['title']:
                 if getattr(item, '_listLink', None):
                     self.print_warning(cformat(
                         '%{yellow!}Link has no title but children'),
                                        event_id=event.id)
                 else:
                     self.print_warning(
                         cformat('%{yellow}Skipping link with no title'),
                         event_id=event.id)
                     continue
         elif item_type == 'PageLink':
             data['type'] = MenuEntryType.page
             data['title'] = _sanitize_title(item._caption)
             data['page'] = EventPage(event_id=event.id,
                                      html=item._page._content)
             data['page'].legacy_mapping = LegacyPageMapping(
                 event_id=event.id, legacy_page_id=item._page._id)
             if item._page._isHome:
                 Event.get(event.id).default_page = data['page']
         else:
             self.print_error(
                 'Unexpected menu item type: {}'.format(item_type),
                 event_id=event.id)
             continue
         entry = MenuEntry(**data)
         yield entry
         if getattr(item, '_listLink', None):
             # child entries
             if not parent:
                 for sub_entry in self._migrate_menu(
                         event, item, entry, used):
                     yield sub_entry
             else:
                 self.print_warning('Skipping children inside nested entry',
                                    event_id=event.id)
Exemple #44
0
    def search_notes(self, q, user, page, category_id, event_id,
                     admin_override_enabled):
        contrib_event = db.aliased(Event)
        contrib_session = db.aliased(Session)
        subcontrib_contrib = db.aliased(Contribution)
        subcontrib_session = db.aliased(Session)
        subcontrib_event = db.aliased(Event)
        session_event = db.aliased(Event)

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

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

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

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

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

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

        res = HTMLStrippingEventNoteSchema(many=True).dump(notes)
        return pagenav, EventNoteResultSchema(many=True).load(res)
Exemple #45
0
 def _process_args(self):
     self.event = Event.get(int(request.view_args['confId']))
     if self.event is None:
         raise NotFound(_('An event with this ID does not exist.'))
     elif self.event.is_deleted:
         raise NotFound(_('This event has been deleted.'))
Exemple #46
0
 def migrate_event_managers(self):
     self.print_step('migrating event managers/creators')
     creator_updates = []
     for event in committing_iterator(self._iter_events(), 5000):
         self.print_success('', event_id=event.id)
         ac = event._Conference__ac
         entries = {}
         # add creator as a manager
         try:
             creator = event._Conference__creator
         except AttributeError:
             # events created after the removal of the `self.__creator` assignment
             # should happen only on dev machines
             self.print_error(
                 cformat('%{red!}Event has no creator attribute'),
                 event_id=event.id)
         else:
             user = self.process_principal(event,
                                           entries,
                                           creator,
                                           'Creator',
                                           'green!',
                                           full_access=True)
             if user:
                 creator_updates.append({
                     'event_id': int(event.id),
                     'creator_id': user.id
                 })
         # add managers
         for manager in ac.managers:
             self.process_principal(event,
                                    entries,
                                    manager,
                                    'Manager',
                                    'blue!',
                                    full_access=True)
         # add email-based managers
         emails = getattr(ac, 'managersEmail', [])
         self.process_emails(event,
                             entries,
                             emails,
                             'Manager',
                             'green',
                             full_access=True)
         # add registrars
         for registrar in getattr(event, '_Conference__registrars', []):
             self.process_principal(event,
                                    entries,
                                    registrar,
                                    'Registrar',
                                    'cyan',
                                    roles={'registration'})
         # add submitters
         for submitter in getattr(ac, 'submitters', []):
             self.process_principal(event,
                                    entries,
                                    submitter,
                                    'Submitter',
                                    'magenta!',
                                    roles={'submit'})
         # email-based (pending) submitters
         pqm = getattr(event, '_pendingQueuesMgr', None)
         if pqm is not None:
             emails = set(getattr(pqm, '_pendingConfSubmitters', []))
             self.process_emails(event,
                                 entries,
                                 emails,
                                 'Submitter',
                                 'magenta',
                                 roles={'submit'})
         db.session.add_all(entries.itervalues())
     # assign creators
     if creator_updates:
         self.print_step('saving event creators')
         stmt = (Event.__table__.update().where(
             Event.id == db.bindparam('event_id')).values(
                 creator_id=db.bindparam('creator_id')))
         db.session.execute(stmt, creator_updates)
     updated = Event.find(Event.creator_id == None).update(
         {Event.creator_id: self.janitor.id})  # noqa
     db.session.commit()
     self.print_success('Set the janitor user {} for {} events'.format(
         self.janitor, updated),
                        always=True)
Exemple #47
0
 def _build_report(self):
     event = Event.get_one(self.params['event_id'], is_deleted=False)
     new_material = get_nested_attached_items(event)
     self.material = {'tree': [self._format_data(new_material)]}
Exemple #48
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)
Exemple #49
0
def create_event(category,
                 event_type,
                 data,
                 add_creator_as_manager=True,
                 features=None):
    from indico.modules.rb.operations.bookings import create_booking_for_event
    """Create a new event.

    :param category: The category in which to create the event
    :param event_type: An `EventType` value
    :param data: A dict containing data used to populate the event
    :param add_creator_as_manager: Whether the creator (current user)
                                   should be added as a manager
    :param features: A list of features that will be enabled for the
                     event. If set, only those features will be used
                     and the default feature set for the event type
                     will be ignored.
    """
    event = Event(category=category, type_=event_type)
    data.setdefault('creator', session.user)
    theme = data.pop('theme', None)
    create_booking = data.pop('create_booking', False)
    person_link_data = data.pop('person_link_data', {})
    event.populate_from_dict(data)
    db.session.flush()
    event.person_link_data = person_link_data
    if theme is not None:
        layout_settings.set(event, 'timetable_theme', theme)
    if add_creator_as_manager:
        with event.logging_disabled:
            event.update_principal(event.creator, full_access=True)
    if features is not None:
        features_event_settings.set(event, 'enabled', features)
    db.session.flush()
    signals.event.created.send(event)
    logger.info('Event %r created in %r by %r ', event, category, session.user)
    event.log(EventLogRealm.event, EventLogKind.positive, 'Event',
              'Event created', session.user)
    db.session.flush()
    if create_booking:
        room_id = data['location_data'].pop('room_id', None)
        if room_id:
            booking = create_booking_for_event(room_id, event)
            if booking:
                logger.info('Booking %r created for event %r', booking, event)
                log_data = {
                    'Room':
                    booking.room.full_name,
                    'Date':
                    booking.start_dt.strftime('%d/%m/%Y'),
                    'Times':
                    '%s - %s' % (booking.start_dt.strftime('%H:%M'),
                                 booking.end_dt.strftime('%H:%M'))
                }
                event.log(EventLogRealm.event,
                          EventLogKind.positive,
                          'Event',
                          'Room booked for the event',
                          session.user,
                          data=log_data)
                db.session.flush()
    return event
Exemple #50
0
 def migrate_event_stubs(self):
     self.print_step('migrating event stubs')
     for event_id in committing_iterator(self._iter_event_ids(), 5000):
         db.session.add(Event(id=int(event_id)))
Exemple #51
0
 def export_timetable(self, user):
     events = Event.find_all(Event.id.in_(map(int, self._idList)), ~Event.is_deleted)
     return {event.id: TimetableSerializer(event, management=False, user=user).serialize_timetable()
             for event in events}
Exemple #52
0
 def export_timetable(self, user):
     events = Event.find_all(Event.id.in_(map(int, self._idList)), ~Event.is_deleted)
     return {event.id: self._serialize_timetable(event, user) for event in events}
Exemple #53
0
def create_event(category,
                 event_type,
                 data,
                 add_creator_as_manager=True,
                 features=None,
                 cloning=False):
    """Create a new event.

    :param category: The category in which to create the event
    :param event_type: An `EventType` value
    :param data: A dict containing data used to populate the event
    :param add_creator_as_manager: Whether the creator (current user)
                                   should be added as a manager
    :param features: A list of features that will be enabled for the
                     event. If set, only those features will be used
                     and the default feature set for the event type
                     will be ignored.
    :param cloning: Whether the event is created via cloning or not
    """
    from indico.modules.rb.operations.bookings import create_booking_for_event
    event = Event(category=category, type_=event_type)
    data.setdefault('creator', session.user)
    theme = data.pop('theme', None)
    create_booking = data.pop('create_booking', False)
    person_link_data = data.pop('person_link_data', {})
    event.populate_from_dict(data)
    db.session.flush()
    event.person_link_data = person_link_data
    if theme is not None:
        layout_settings.set(event, 'timetable_theme', theme)
    if add_creator_as_manager:
        with event.logging_disabled:
            event.update_principal(event.creator, full_access=True)
    if features is not None:
        features_event_settings.set(event, 'enabled', features)
    db.session.flush()
    signals.event.created.send(event, cloning=cloning)
    logger.info('Event %r created in %r by %r ', event, category, session.user)
    sep = ' \N{RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK} '
    event.log(EventLogRealm.event,
              LogKind.positive,
              'Event',
              'Event created',
              session.user,
              data={
                  'Category':
                  sep.join(category.chain_titles) if category else None
              })
    if category:
        category.log(CategoryLogRealm.events,
                     LogKind.positive,
                     'Content',
                     f'Event created: "{event.title}"',
                     session.user,
                     data={
                         'ID': event.id,
                         'Type': orig_string(event.type_.title)
                     })
    db.session.flush()
    if create_booking:
        room_id = data['location_data'].pop('room_id', None)
        if room_id:
            booking = create_booking_for_event(room_id, event)
            if booking:
                logger.info('Booking %r created for event %r', booking, event)
                log_data = {
                    'Room':
                    booking.room.full_name,
                    'Date':
                    booking.start_dt.strftime('%d/%m/%Y'),
                    'Times':
                    '{} - {}'.format(booking.start_dt.strftime('%H:%M'),
                                     booking.end_dt.strftime('%H:%M'))
                }
                event.log(EventLogRealm.event,
                          LogKind.positive,
                          'Event',
                          'Room booked for the event',
                          session.user,
                          data=log_data)
                db.session.flush()
    return event
 def event(self):
     return Event.get(int(self.event_id), is_deleted=False)
Exemple #55
0
 def category_events(self, catIds):
     from indico.modules.events import Event
     query = (Event.query.filter(
         ~Event.is_deleted, Event.category_chain.overlap(map(int, catIds)),
         Event.happens_between(self._fromDT, self._toDT)))
     return self._process(x.as_legacy for x in query)
Exemple #56
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)
Exemple #57
0
 def event(self):
     return Event.get_one(self.event_id, is_deleted=False)
 def _events_query(self):
     return Event.find(
         Event.attachment_folders.any(
             AttachmentFolder.title.op('~')('^part\d+$')))
Exemple #59
0
def _query_categ_events(categ, start_dt, end_dt):
    return (Event.query
            .with_parent(categ)
            .filter(Event.happens_between(start_dt, end_dt))
            .options(load_only('id', 'start_dt', 'end_dt')))
Exemple #60
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())