Example #1
0
def test_contrib_friendly_id(monkeypatch, dummy_event, create_contribution):
    counter = Incrementer()
    monkeypatch.setattr(contrib_module, 'increment_and_get', counter)

    contrib_1 = create_contribution(dummy_event, 'Contribution 1',
                                    timedelta(minutes=60))
    assert contrib_1.friendly_id == 1

    contrib_2 = create_contribution(dummy_event, 'Contribution 2',
                                    timedelta(minutes=60))
    assert contrib_2.friendly_id == 2

    assert counter == 2

    # pre-allocate 8 friendly ids
    Contribution.allocate_friendly_ids(dummy_event, 8)
    assert g.friendly_ids[Contribution][dummy_event.id] == range(3, 11)
    assert counter == 10

    for fid in g.friendly_ids[Contribution][dummy_event.id][:]:
        contrib = create_contribution(dummy_event,
                                      'Contribution {}'.format(fid),
                                      timedelta(minutes=30))
        assert contrib.friendly_id == fid

    # increment_and_get doesn't get called because the ids
    # have been pre-allocated
    assert counter == 10
Example #2
0
def create_contribution(event, contrib_data, custom_fields_data=None, session_block=None, extend_parent=False):
    start_dt = contrib_data.pop('start_dt', None)
    contrib = Contribution(event_new=event)
    contrib.populate_from_dict(contrib_data)
    if start_dt is not None:
        schedule_contribution(contrib, start_dt=start_dt, session_block=session_block, extend_parent=extend_parent)
    if custom_fields_data:
        set_custom_fields(contrib, custom_fields_data)
    db.session.flush()
    signals.event.contribution_created.send(contrib)
    logger.info('Contribution %s created by %s', contrib, session.user)
    contrib.event_new.log(EventLogRealm.management, EventLogKind.positive, 'Contributions',
                          'Contribution "{}" has been created'.format(contrib.title), session.user)
    return contrib
Example #3
0
 def _process(self):
     inherited_location = self.event.location_data
     inherited_location['inheriting'] = True
     default_duration = contribution_settings.get(self.event,
                                                  'default_duration')
     contrib_form_class = make_contribution_form(self.event)
     form = contrib_form_class(obj=FormDefaults(
         location_data=inherited_location, duration=default_duration),
                               event=self.event)
     if form.validate_on_submit():
         # Create empty contribution so it can be compared to the new one in flash_if_unregistered
         contrib = Contribution()
         with flash_if_unregistered(self.event,
                                    lambda: contrib.person_links):
             contrib = create_contribution(self.event,
                                           *get_field_values(form.data))
         flash(
             _("Contribution '{}' created successfully").format(
                 contrib.title), 'success')
         tpl_components = self.list_generator.render_list(contrib)
         if tpl_components['hide_contrib']:
             self.list_generator.flash_info_message(contrib)
         return jsonify_data(**tpl_components)
     return jsonify_template('events/contributions/forms/contribution.html',
                             form=form)
    def _migrate_event_reviewing(self, conf):
        conference_settings = getattr(conf, '_confPaperReview', None)
        if not conference_settings:
            return

        event = conf.as_event
        contrib_index = conference_settings._contribution_index = IOBTree()
        contrib_reviewers = _invert_mapping(conference_settings._reviewerContribution)
        contrib_referees = _invert_mapping(conference_settings._refereeContribution)
        contrib_editors = _invert_mapping(conference_settings._editorContribution)

        for old_contribution in conf.contributions.itervalues():
            review_manager = getattr(old_contribution, '_reviewManager', None)
            new_contribution = Contribution.find_one(event_id=event.id, friendly_id=int(old_contribution.id))

            cid = int(new_contribution.id)
            if review_manager:
                review_manager._contrib_id = cid
                contrib_index[cid] = review_manager

            self._migrate_contribution_roles(old_contribution, new_contribution, contrib_reviewers,
                                             PaperReviewingRoleType.reviewer, event.id)
            self._migrate_contribution_roles(old_contribution, new_contribution, contrib_referees,
                                             PaperReviewingRoleType.referee, event.id)
            self._migrate_contribution_roles(old_contribution, new_contribution, contrib_editors,
                                             PaperReviewingRoleType.editor, event.id)

            self._migrate_reviewing_materials(old_contribution, new_contribution, review_manager, event.id)
Example #5
0
 def _process_args(self):
     RHPapersBase._process_args(self)
     self.contribution = Contribution.get_one(
         request.view_args['contrib_id'], is_deleted=False)
     self.paper = self.contribution.paper
     if self.paper is None and self.PAPER_REQUIRED:
         raise NotFound
Example #6
0
 def _create_contribution(title, duration):
     entry = Contribution(event_new=dummy_event_new,
                          title=title,
                          duration=duration)
     db.session.add(entry)
     db.session.flush()
     return entry
    def _migrate_event_reviewing(self, conf):
        conference_settings = getattr(conf, '_confPaperReview', None)
        if not conference_settings:
            return

        event = conf.as_event
        contrib_index = conference_settings._contribution_index = IOBTree()
        contrib_reviewers = _invert_mapping(conference_settings._reviewerContribution)
        contrib_referees = _invert_mapping(conference_settings._refereeContribution)
        contrib_editors = _invert_mapping(conference_settings._editorContribution)

        for old_contribution in conf.contributions.itervalues():
            review_manager = getattr(old_contribution, '_reviewManager', None)
            new_contribution = Contribution.find_one(event_id=event.id, friendly_id=int(old_contribution.id))

            cid = int(new_contribution.id)
            if review_manager:
                review_manager._contrib_id = cid
                contrib_index[cid] = review_manager

            self._migrate_contribution_roles(old_contribution, new_contribution, contrib_reviewers,
                                             PaperReviewingRoleType.reviewer, event.id)
            self._migrate_contribution_roles(old_contribution, new_contribution, contrib_referees,
                                             PaperReviewingRoleType.referee, event.id)
            self._migrate_contribution_roles(old_contribution, new_contribution, contrib_editors,
                                             PaperReviewingRoleType.editor, event.id)

            self._migrate_reviewing_materials(old_contribution, new_contribution, review_manager, event.id)
Example #8
0
 def _create_contribution(event,
                          title,
                          duration=timedelta(minutes=20),
                          **kwargs):
     entry = Contribution(event=event,
                          title=title,
                          duration=duration,
                          **kwargs)
     db.session.add(entry)
     db.session.flush()
     return entry
    def update_data_vc_room(self, vc_room, data, is_new=False):
        super(RedirectorPlugin, self).update_data_vc_room(vc_room, data)

        for key in ['room_url_base']:
            if key in data:
                vc_room.data[key] = data.pop(key)
                contrib = Contribution.get(data['contribution'])
                cid = contrib.id if contrib else 0
                vc_room.data['room_url'] = url_for_plugin(
                    'vc_redirector.vc_redirect', contrib_id=cid)

        flag_modified(vc_room, 'data')
Example #10
0
def create_contribution(event,
                        contrib_data,
                        custom_fields_data=None,
                        session_block=None,
                        extend_parent=False):
    user = session.user if session else None
    start_dt = contrib_data.pop('start_dt', None)
    contrib = Contribution(event=event)
    contrib.populate_from_dict(contrib_data)
    if custom_fields_data:
        set_custom_fields(contrib, custom_fields_data)
    db.session.flush()
    if start_dt is not None:
        schedule_contribution(contrib,
                              start_dt=start_dt,
                              session_block=session_block,
                              extend_parent=extend_parent)
    signals.event.contribution_created.send(contrib)
    logger.info('Contribution %s created by %s', contrib, user)
    contrib.log(EventLogRealm.management, EventLogKind.positive,
                'Contributions',
                f'Contribution {contrib.verbose_title} has been created', user)
    # Note: If you ever add more stuff here that should run for any new contribution, make sure
    # to also add it to ContributionCloner.clone_single_contribution
    return contrib
Example #11
0
def obj_deref(ref):
    """Returns the object identified by `ref`"""
    from indico_livesync.models.queue import EntryType
    if ref['type'] == EntryType.category:
        return CategoryManager().getById(ref['category_id'], True)
    elif ref['type'] == EntryType.event:
        return Event.get(ref['event_id'])
    elif ref['type'] == EntryType.contribution:
        return Contribution.get(ref['contrib_id'])
    elif ref['type'] == EntryType.subcontribution:
        return SubContribution.get(ref['subcontrib_id'])
    else:
        raise ValueError('Unexpected object type: {}'.format(ref['type']))
Example #12
0
    def _checkParams(self):
        data = request.json
        self.object = None
        if 'categId' in data:
            self.object = Category.get_one(data['categId'])
        elif 'contribId' in data:
            self.object = Contribution.get_one(data['contribId'])
        elif 'sessionId' in data:
            self.object = Session.get_one(data['sessionId'])
        elif 'confId' in data:
            self.object = Event.get_one(data['confId'])

        if self.object is None:
            raise BadRequest
Example #13
0
    def _process_args(self):
        data = request.json
        self.object = None
        if 'categId' in data:
            self.object = Category.get_or_404(data['categId'])
        elif 'contribId' in data:
            self.object = Contribution.get_or_404(data['contribId'])
        elif 'sessionId' in data:
            self.object = Session.get_or_404(data['sessionId'])
        elif 'eventId' in data:
            self.object = Event.get_or_404(data['eventId'])

        if self.object is None:
            raise BadRequest
Example #14
0
    def _process_args(self):
        data = request.json
        self.object = None
        if 'categId' in data:
            self.object = Category.get_one(data['categId'])
        elif 'contribId' in data:
            self.object = Contribution.get_one(data['contribId'])
        elif 'sessionId' in data:
            self.object = Session.get_one(data['sessionId'])
        elif 'confId' in data:
            self.object = Event.get_one(data['confId'])

        if self.object is None:
            raise BadRequest
Example #15
0
def obj_deref(ref):
    """Returns the object identified by `ref`"""
    from indico_livesync.models.queue import EntryType
    if ref['type'] == EntryType.category:
        return Category.get_one(ref['category_id'])
    elif ref['type'] == EntryType.event:
        return Event.get_one(ref['event_id'])
    elif ref['type'] == EntryType.session:
        return Session.get_one(ref['session_id'])
    elif ref['type'] == EntryType.contribution:
        return Contribution.get_one(ref['contrib_id'])
    elif ref['type'] == EntryType.subcontribution:
        return SubContribution.get_one(ref['subcontrib_id'])
    else:
        raise ValueError('Unexpected object type: {}'.format(ref['type']))
Example #16
0
def test_contrib_friendly_id(monkeypatch, dummy_event, create_contribution):
    counter = Incrementer()
    monkeypatch.setattr(contrib_module, 'increment_and_get', counter)

    contrib_1 = create_contribution(dummy_event, 'Contribution 1', timedelta(minutes=60))
    assert contrib_1.friendly_id == 1

    contrib_2 = create_contribution(dummy_event, 'Contribution 2', timedelta(minutes=60))
    assert contrib_2.friendly_id == 2

    assert counter == 2

    # pre-allocate 8 friendly ids
    Contribution.allocate_friendly_ids(dummy_event, 8)
    assert g.friendly_ids[Contribution][dummy_event.id] == range(3, 11)
    assert counter == 10

    for fid in g.friendly_ids[Contribution][dummy_event.id][:]:
        contrib = create_contribution(dummy_event, 'Contribution {}'.format(fid), timedelta(minutes=30))
        assert contrib.friendly_id == fid

    # increment_and_get doesn't get called because the ids
    # have been pre-allocated
    assert counter == 10
Example #17
0
def _process_cascaded_event_contents(records, additional_events=None):
    """
    Flatten a series of records into its most basic elements (subcontribution level).

    Yields results.

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

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

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

    for event in changed_events:
        yield event

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

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

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

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

    # Same for subcontributions
    if subcontribution_records:
        changed_subcontributions.update(SubContribution.find(SubContribution.id.in_(subcontribution_records)))
    for subcontrib in changed_subcontributions:
        yield subcontrib
Example #18
0
    def _handleGet(self):
        contributions = Contribution.find(event_new=self._conf.as_event, is_deleted=False).options(
            joinedload("timetable_entry"), joinedload("paper_reviewing_roles")
        )

        filter = {}

        # filtering if the active user is a referee: he can only see his own contribs
        isOnlyReferee = (
            RCReferee.hasRights(self)
            and not RCPaperReviewManager.hasRights(self)
            and not self._conf.canModify(self.getAW())
        )

        # We want to make an 'or', not an 'and' of the reviewing assign status

        filter["reviewing"] = {}
        if isOnlyReferee:
            filter["reviewing"]["referee"] = self._getUser()
        elif self._showWithReferee:
            filter["reviewing"]["referee"] = "any"
        if self._showWithEditor:
            filter["reviewing"]["editor"] = "any"
        if self._showWithReviewer:
            filter["reviewing"]["reviewer"] = "any"

        filter["type"] = self._selTypes
        filter["track"] = self._selTracks
        filter["session"] = self._selSessions

        filter["materialsubmitted"] = self._showWithMaterial

        filterCrit = ContributionsReviewingFilterCrit(self._conf, filter)
        sortingCrit = contribFilters.SortingCriteria(["number"])

        filterCrit.getField("type").setShowNoValue(self._typeShowNoValue)
        filterCrit.getField("track").setShowNoValue(self._trackShowNoValue)
        filterCrit.getField("session").setShowNoValue(self._sessionShowNoValue)

        filterCrit.getField("reviewing").setShowNoValue(self._showWithoutTeam)
        filterCrit.getField("materialsubmitted").setShowNoValue(self._showWithoutMaterial)

        f = filters.SimpleFilter(filterCrit, sortingCrit)
        contributions = f.apply(contributions)

        return [_serialize_contribution(contrib) for contrib in contributions]
Example #19
0
    def _handleGet(self):
        contributions = (Contribution.find(
            event_new=self._conf.as_event,
            is_deleted=False).options(joinedload('timetable_entry'),
                                      joinedload('paper_reviewing_roles')))

        filter = {}

        #filtering if the active user is a referee: he can only see his own contribs
        isOnlyReferee = RCReferee.hasRights(self) \
            and not RCPaperReviewManager.hasRights(self) \
            and not self._conf.canModify(self.getAW())

        # We want to make an 'or', not an 'and' of the reviewing assign status

        filter["reviewing"] = {}
        if isOnlyReferee:
            filter["reviewing"]["referee"] = self._getUser()
        elif self._showWithReferee:
            filter["reviewing"]["referee"] = "any"
        if self._showWithEditor:
            filter["reviewing"]["editor"] = "any"
        if self._showWithReviewer:
            filter["reviewing"]["reviewer"] = "any"

        filter["type"] = self._selTypes
        filter["track"] = self._selTracks
        filter["session"] = self._selSessions

        filter["materialsubmitted"] = self._showWithMaterial

        filterCrit = ContributionsReviewingFilterCrit(self._conf, filter)
        sortingCrit = contribFilters.SortingCriteria(["number"])

        filterCrit.getField("type").setShowNoValue(self._typeShowNoValue)
        filterCrit.getField("track").setShowNoValue(self._trackShowNoValue)
        filterCrit.getField("session").setShowNoValue(self._sessionShowNoValue)

        filterCrit.getField("reviewing").setShowNoValue(self._showWithoutTeam)
        filterCrit.getField("materialsubmitted").setShowNoValue(
            self._showWithoutMaterial)

        f = filters.SimpleFilter(filterCrit, sortingCrit)
        contributions = f.apply(contributions)

        return [_serialize_contribution(contrib) for contrib in contributions]
Example #20
0
 def _migrate_papers(self):
     contributions = {
         c.id: c
         for c in (Contribution.find(event_new=self.event).options(
             joinedload('legacy_paper_reviewing_roles')))
     }
     if not hasattr(self.pr, '_contribution_index'):
         self.importer.print_warning(
             cformat('%{yellow!}Event has no contribution index!'),
             event_id=self.event.id)
         return
     for contrib_id, rm in self.pr._contribution_index.iteritems():
         if contrib_id not in contributions:
             self.importer.print_warning(
                 cformat('%{yellow!}Contribution {} not found in event'
                         ).format(contrib_id),
                 event_id=self.event.id)
             continue
         contribution = contributions[contrib_id]
         self._migrate_paper_roles(contribution)
         self._migrate_revisions(contribution, rm)
def RHredirectToExternal(contrib_id):

    contrib = Contribution.get_or_404(contrib_id)
    event = contrib.event
    if not session.user:
        flash(_("The vc link  is only available to logged in users."), 'error')
        raise BadRequest(response=redirect(event.url))

    vcas = contrib.vc_room_associations
    vca = None
    for _vca in vcas:
        vca = _vca
        if isinstance(vca.vc_room.plugin, RedirectorPlugin):
            break
    else:
        raise BadRequest(response=redirect(event.url))
    if vca.data.get('only_registered_users') and \
        not any([x[1] for x in get_event_regforms(event, session.user)]):
        flash(_("The vc link is only available to registered users."), 'error')
        raise BadRequest(response=redirect(event.url))

    vcroom = vca.vc_room
    url = vcroom.data['room_url_base']
    data = {'id': contrib.friendly_id, 'username': session.user.name}

    req = requests.post(url, json=data)
    if req.status_code != 200:
        flash('Error: The redirector did not succeed!', 'error')
        raise BadRequest(response=redirect(event.url))

    res = req.json()
    if res['status'] != 'success':
        flash(_("Videoconference link:") + ' ' + res['message'], 'error')
        raise BadRequest(response=redirect(event.url))

    return redirect(res['url'])
Example #22
0
def get_category_timetable(categ_ids, start_dt, end_dt, detail_level='event', tz=utc, from_categ=None, grouped=True):
    """Retrieve time blocks that fall within a specific time interval
       for a given set of categories.

       :param categ_ids: iterable containing list of category IDs
       :param start_dt: start of search interval (``datetime``, expected
                        to be in display timezone)
       :param end_dt: end of search interval (``datetime`` in expected
                      to be in display timezone)
       :param detail_level: the level of detail of information
                            (``event|session|contribution``)
       :param tz: the ``timezone`` information should be displayed in
       :param from_categ: ``Category`` that will be taken into account to calculate
                          visibility
       :param grouped: Whether to group results by start date
       :returns: a dictionary containing timetable information in a
                 structured way. See source code for examples.
    """
    day_start = start_dt.astimezone(utc)
    day_end = end_dt.astimezone(utc)
    dates_overlap = lambda t: (t.start_dt >= day_start) & (t.start_dt <= day_end)

    items = defaultdict(lambda: defaultdict(list))

    # first of all, query TimetableEntries/events that fall within
    # specified range of dates (and category set)
    events = _query_events(categ_ids, day_start, day_end)
    if from_categ:
        events = events.filter(Event.is_visible_in(from_categ))
    for eid, tt_start_dt in events:
        if tt_start_dt:
            items[eid][tt_start_dt.astimezone(tz).date()].append(tt_start_dt)
        else:
            items[eid] = None

    # then, retrieve detailed information about the events
    event_ids = set(items)
    query = (Event.find(Event.id.in_(event_ids))
             .options(subqueryload(Event.person_links).joinedload(EventPersonLink.person),
                      joinedload(Event.own_room).noload('owner'),
                      joinedload(Event.own_venue),
                      joinedload(Event.category).undefer('effective_icon_data'),
                      undefer('effective_protection_mode')))
    scheduled_events = defaultdict(list)
    ongoing_events = []
    events = []
    for e in query:
        if grouped:
            local_start_dt = e.start_dt.astimezone(tz).date()
            local_end_dt = e.end_dt.astimezone(tz).date()
            if items[e.id] is None:
                # if there is no TimetableEntry, this means the event has not timetable on that interval
                for day in iterdays(max(start_dt.date(), local_start_dt), min(end_dt.date(), local_end_dt)):
                    # if the event starts on this date, we've got a time slot
                    if day.date() == local_start_dt:
                        scheduled_events[day.date()].append((e.start_dt, e))
                    else:
                        ongoing_events.append(e)
            else:
                for start_d, start_dts in items[e.id].viewitems():
                    scheduled_events[start_d].append((start_dts[0], e))
        else:
            events.append(e)

    # result['events'][date(...)] -> [(datetime(....), Event(...))]
    # result[event_id]['contribs'][date(...)] -> [(TimetableEntry(...), Contribution(...))]
    # result['ongoing_events'] = [Event(...)]
    if grouped:
        result = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
    else:
        result = defaultdict(lambda: defaultdict(list))

    result.update({
        'events': scheduled_events if grouped else events,
        'ongoing_events': ongoing_events
    })

    # according to detail level, ask for extra information from the DB
    if detail_level != 'event':
        query = _query_blocks(event_ids, dates_overlap, detail_level)
        if grouped:
            for b in query:
                start_date = b.timetable_entry.start_dt.astimezone(tz).date()
                result[b.session.event_id]['blocks'][start_date].append((b.timetable_entry, b))
        else:
            for b in query:
                result[b.session.event_id]['blocks'].append(b)

    if detail_level == 'contribution':
        query = (Contribution.find(Contribution.event_id.in_(event_ids),
                                   dates_overlap(TimetableEntry),
                                   ~Contribution.is_deleted)
                 .options(contains_eager(Contribution.timetable_entry),
                          joinedload(Contribution.person_links))
                 .join(TimetableEntry))
        if grouped:
            for c in query:
                start_date = c.timetable_entry.start_dt.astimezone(tz).date()
                result[c.event_id]['contribs'][start_date].append((c.timetable_entry, c))
        else:
            for c in query:
                result[c.event_id]['contributions'].append(c)

        query = (Break.find(TimetableEntry.event_id.in_(event_ids), dates_overlap(TimetableEntry))
                 .options(contains_eager(Break.timetable_entry))
                 .join(TimetableEntry))
        if grouped:
            for b in query:
                start_date = b.timetable_entry.start_dt.astimezone(tz).date()
                result[b.timetable_entry.event_id]['breaks'][start_date].append((b.timetable_entry, b))
        else:
            for b in query:
                result[b.timetable_entry.event_id]['breaks'].append(b)
    return result
Example #23
0
    def _migrate_contribution(self, old_contrib, friendly_id):
        ac = old_contrib._Contribution__ac
        try:
            description = old_contrib._fields.get('content', '')
        except AttributeError:
            if not self.is_legacy_event:
                self.print_warning('Contribution {} has no fields'.format(old_contrib))
            description = ''
        description = convert_to_unicode(getattr(description, 'value', description))  # str or AbstractFieldContent
        status = getattr(old_contrib, '_status', None)
        status_class = status.__class__.__name__ if status else None

        contrib = Contribution(event_new=self.event, friendly_id=friendly_id,
                               title=convert_to_unicode(old_contrib.title),
                               render_mode=RenderMode.html,
                               description=description, duration=old_contrib.duration,
                               protection_mode=PROTECTION_MODE_MAP[ac._accessProtection],
                               board_number=convert_to_unicode(getattr(old_contrib, '_boardNumber', '')),
                               keywords=self._process_keywords(getattr(old_contrib, '_keywords', '')),
                               is_deleted=(status_class == 'ContribStatusWithdrawn'))
        if old_contrib._track is not None:
            track = self.event_ns.track_map.get(old_contrib._track)
            if not track:
                self.print_warning('Track not found: {}. Setting to None.'.format(old_contrib._track))
            else:
                contrib.track = track
        if not self.quiet:
            self.print_info('%[cyan]Contribution%[reset] {}'.format(contrib.title))
        self.event_ns.legacy_contribution_map[old_contrib] = contrib
        contrib.legacy_mapping = LegacyContributionMapping(event_new=self.event, legacy_contribution_id=old_contrib.id)
        # contribution type
        if old_contrib._type is not None:
            try:
                contrib.type = self.event_ns.legacy_contribution_type_map[old_contrib._type]
            except AttributeError:
                self.print_warning('%[yellow!]Invalid contrib type {}'
                                   .format(convert_to_unicode(old_contrib._type._name)))
        # abstract
        if old_contrib in self.event_ns.legacy_contribution_abstracts:
            contrib.abstract = self.event_ns.legacy_contribution_abstracts[old_contrib]
        # ACLs (managers, read access, submitters)
        principals = {}
        self._process_ac(ContributionPrincipal, principals, ac)
        for submitter in old_contrib._submitters:
            self._process_principal(ContributionPrincipal, principals, submitter, 'Submitter', roles={'submit'})
        self._process_principal_emails(ContributionPrincipal, principals, getattr(old_contrib, '_submittersEmail', []),
                                       'Submitter', roles={'submit'})
        contrib.acl_entries = set(principals.itervalues())
        # speakers, authors and co-authors
        contrib.person_links = list(self._migrate_contribution_person_links(old_contrib))
        # references ("report numbers")
        contrib.references = list(self._process_references(ContributionReference, old_contrib))
        # contribution/abstract fields
        if hasattr(old_contrib, '_fields'):
            contrib.field_values = list(self._migrate_contribution_field_values(old_contrib))
        contrib.subcontributions = [self._migrate_subcontribution(old_contrib, old_subcontrib, pos)
                                    for pos, old_subcontrib in enumerate(old_contrib._subConts, 1)]
        contrib._last_friendly_subcontribution_id = len(contrib.subcontributions)
        return contrib
Example #24
0
 def _checkParams(self, params):
     RHManageContributionsBase._checkParams(self, params)
     self.contrib = Contribution.find_one(id=request.view_args['contrib_id'], is_deleted=False)
Example #25
0
 def _process_args(self):
     RHConferenceBaseDisplay._process_args(self)
     self.contrib = Contribution.get_one(request.view_args['contrib_id'],
                                         is_deleted=False)
Example #26
0
 def _checkParams(self, params):
     RHConferenceBaseDisplay._checkParams(self, params)
     self.contrib = Contribution.get_one(request.view_args['contrib_id'], is_deleted=False)
Example #27
0
 def _process_args(self):
     RHPapersBase._process_args(self)
     self.contribution = Contribution.get_one(request.view_args['contrib_id'], is_deleted=False)
     self.paper = self.contribution.paper
     if self.paper is None and self.PAPER_REQUIRED:
         raise NotFound
Example #28
0
def _process_cascaded_event_contents(records, additional_events=None):
    """
    Flatten a series of records into its most basic elements (subcontribution level).

    Yields results.

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

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

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

    for event in changed_events:
        yield event

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

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

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

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

    # Same for subcontributions
    if subcontribution_records:
        changed_subcontributions.update(
            SubContribution.find(
                SubContribution.id.in_(subcontribution_records)))
    for subcontrib in changed_subcontributions:
        yield subcontrib
Example #29
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)
Example #30
0
def import_contributions_from_csv(event, f):
    """Import timetable contributions from a CSV file into an event."""
    reader = csv.reader(f.read().splitlines())
    contrib_data = []

    for num_row, row in enumerate(reader, 1):
        try:
            start_dt, duration, title, first_name, last_name, affiliation, email = \
                [to_unicode(value).strip() for value in row]
            email = email.lower()
        except ValueError:
            raise UserValueError(_('Row {}: malformed CSV data - please check that the number of columns is correct')
                                 .format(num_row))
        try:
            parsed_start_dt = event.tzinfo.localize(dateutil.parser.parse(start_dt)) if start_dt else None
        except ValueError:
            raise UserValueError(_("Row {row}: can't parse date: \"{date}\"").format(row=num_row, date=start_dt))

        try:
            parsed_duration = timedelta(minutes=int(duration)) if duration else None
        except ValueError:
            raise UserValueError(_("Row {row}: can't parse duration: {duration}").format(row=num_row,
                                                                                         duration=duration))

        if not title:
            raise UserValueError(_("Row {}: contribution title is required").format(num_row))

        if email and not validate_email(email):
            raise UserValueError(_("Row {row}: invalid email address: {email}").format(row=num_row, email=email))

        contrib_data.append({
            'start_dt': parsed_start_dt,
            'duration': parsed_duration or timedelta(minutes=20),
            'title': title,
            'speaker': {
                'first_name': first_name,
                'last_name': last_name,
                'affiliation': affiliation,
                'email': email
            }
        })

    # now that we're sure the data is OK, let's pre-allocate the friendly ids
    # for the contributions in question
    Contribution.allocate_friendly_ids(event, len(contrib_data))
    contributions = []
    all_changes = defaultdict(list)

    for contrib_fields in contrib_data:
        speaker_data = contrib_fields.pop('speaker')

        with track_time_changes() as changes:
            contribution = create_contribution(event, contrib_fields, extend_parent=True)

        contributions.append(contribution)
        for key, val in changes[event].viewitems():
            all_changes[key].append(val)

        email = speaker_data['email']
        if not email:
            continue

        # set the information of the speaker
        person = get_event_person(event, {
            'firstName': speaker_data['first_name'],
            'familyName': speaker_data['last_name'],
            'affiliation': speaker_data['affiliation'],
            'email': email
        })
        link = ContributionPersonLink(person=person, is_speaker=True)
        link.populate_from_dict({
            'first_name': speaker_data['first_name'],
            'last_name': speaker_data['last_name'],
            'affiliation': speaker_data['affiliation']
        })
        contribution.person_links.append(link)

    return contributions, all_changes
Example #31
0
 def _process_args(self):
     RHManageContributionsBase._process_args(self)
     self.contrib = Contribution.find_one(
         id=request.view_args['contrib_id'], is_deleted=False)
Example #32
0
def get_category_timetable(categ_ids, start_dt, end_dt, detail_level='event', tz=utc, from_categ=None, grouped=True):
    """Retrieve time blocks that fall within a specific time interval
       for a given set of categories.

       :param categ_ids: iterable containing list of category IDs
       :param start_dt: start of search interval (``datetime``, expected
                        to be in display timezone)
       :param end_dt: end of search interval (``datetime`` in expected
                      to be in display timezone)
       :param detail_level: the level of detail of information
                            (``event|session|contribution``)
       :param tz: the ``timezone`` information should be displayed in
       :param from_categ: ``Category`` that will be taken into account to calculate
                          visibility
       :param grouped: Whether to group results by start date
       :returns: a dictionary containing timetable information in a
                 structured way. See source code for examples.
    """
    day_start = start_dt.astimezone(utc)
    day_end = end_dt.astimezone(utc)
    dates_overlap = lambda t: (t.start_dt >= day_start) & (t.start_dt <= day_end)

    items = defaultdict(lambda: defaultdict(list))

    # first of all, query TimetableEntries/events that fall within
    # specified range of dates (and category set)
    events = _query_events(categ_ids, day_start, day_end)
    if from_categ:
        events = events.filter(Event.is_visible_in(from_categ))
    for eid, tt_start_dt in events:
        if tt_start_dt:
            items[eid][tt_start_dt.astimezone(tz).date()].append(tt_start_dt)
        else:
            items[eid] = None

    # then, retrieve detailed information about the events
    event_ids = set(items)
    query = (Event.find(Event.id.in_(event_ids))
             .options(subqueryload(Event.person_links).joinedload(EventPersonLink.person),
                      joinedload(Event.own_room).noload('owner'),
                      joinedload(Event.own_venue),
                      joinedload(Event.category).undefer('effective_icon_data'),
                      undefer('effective_protection_mode')))
    scheduled_events = defaultdict(list)
    ongoing_events = []
    events = []
    for e in query:
        if grouped:
            local_start_dt = e.start_dt.astimezone(tz).date()
            local_end_dt = e.end_dt.astimezone(tz).date()
            if items[e.id] is None:
                # if there is no TimetableEntry, this means the event has not timetable on that interval
                for day in iterdays(max(start_dt.date(), local_start_dt), min(end_dt.date(), local_end_dt)):
                    # if the event starts on this date, we've got a time slot
                    if day.date() == local_start_dt:
                        scheduled_events[day.date()].append((e.start_dt, e))
                    else:
                        ongoing_events.append(e)
            else:
                for start_d, start_dts in items[e.id].viewitems():
                    scheduled_events[start_d].append((start_dts[0], e))
        else:
            events.append(e)

    # result['events'][date(...)] -> [(datetime(....), Event(...))]
    # result[event_id]['contribs'][date(...)] -> [(TimetableEntry(...), Contribution(...))]
    # result['ongoing_events'] = [Event(...)]
    if grouped:
        result = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
    else:
        result = defaultdict(lambda: defaultdict(list))

    result.update({
        'events': scheduled_events if grouped else events,
        'ongoing_events': ongoing_events
    })

    # according to detail level, ask for extra information from the DB
    if detail_level != 'event':
        query = _query_blocks(event_ids, dates_overlap, detail_level)
        if grouped:
            for b in query:
                start_date = b.timetable_entry.start_dt.astimezone(tz).date()
                result[b.session.event_id]['blocks'][start_date].append((b.timetable_entry, b))
        else:
            for b in query:
                result[b.session.event_id]['blocks'].append(b)

    if detail_level == 'contribution':
        query = (Contribution.find(Contribution.event_id.in_(event_ids),
                                   dates_overlap(TimetableEntry),
                                   ~Contribution.is_deleted)
                 .options(contains_eager(Contribution.timetable_entry),
                          joinedload(Contribution.person_links))
                 .join(TimetableEntry))
        if grouped:
            for c in query:
                start_date = c.timetable_entry.start_dt.astimezone(tz).date()
                result[c.event_id]['contribs'][start_date].append((c.timetable_entry, c))
        else:
            for c in query:
                result[c.event_id]['contributions'].append(c)

        query = (Break.find(TimetableEntry.event_id.in_(event_ids), dates_overlap(TimetableEntry))
                 .options(contains_eager(Break.timetable_entry))
                 .join(TimetableEntry))
        if grouped:
            for b in query:
                start_date = b.timetable_entry.start_dt.astimezone(tz).date()
                result[b.timetable_entry.event_id]['breaks'][start_date].append((b.timetable_entry, b))
        else:
            for b in query:
                result[b.timetable_entry.event_id]['breaks'].append(b)
    return result
Example #33
0
 def _get_event_path(self, data):
     if not (contrib := Contribution.get(data['contribution_id'])):
         return []
Example #34
0
 def _process_args(self):
     RHDisplayEventBase._process_args(self)
     self.contrib = Contribution.get_one(request.view_args['contrib_id'], is_deleted=False)
Example #35
0
 def _checkParams(self, params):
     RHConferenceBaseDisplay._checkParams(self, params)
     self.contrib = Contribution.get_one(request.view_args['contrib_id'],
                                         is_deleted=False)
Example #36
0
 def _checkParams(self, params):
     RHManageContributionsBase._checkParams(self, params)
     self.contrib = Contribution.find_one(
         id=request.view_args['contrib_id'], is_deleted=False)
Example #37
0
 def _process_args(self):
     RHManageContributionsBase._process_args(self)
     self.contrib = Contribution.find_one(id=request.view_args['contrib_id'], is_deleted=False)
Example #38
0
def import_contributions_from_csv(event, f):
    """Import timetable contributions from a CSV file into an event."""
    with csv_text_io_wrapper(f) as ftxt:
        reader = csv.reader(ftxt.read().splitlines())

    contrib_data = []
    for num_row, row in enumerate(reader, 1):
        try:
            start_dt, duration, title, first_name, last_name, affiliation, email = (
                value.strip() for value in row)
            email = email.lower()
        except ValueError:
            raise UserValueError(
                _('Row {}: malformed CSV data - please check that the number of columns is correct'
                  ).format(num_row))
        try:
            parsed_start_dt = event.tzinfo.localize(
                dateutil.parser.parse(start_dt)) if start_dt else None
        except ValueError:
            raise UserValueError(
                _('Row {row}: can\'t parse date: "{date}"').format(
                    row=num_row, date=start_dt))

        try:
            parsed_duration = timedelta(
                minutes=int(duration)) if duration else None
        except ValueError:
            raise UserValueError(
                _("Row {row}: can't parse duration: {duration}").format(
                    row=num_row, duration=duration))

        if not title:
            raise UserValueError(
                _('Row {}: contribution title is required').format(num_row))

        if email and not validate_email(email):
            raise UserValueError(
                _('Row {row}: invalid email address: {email}').format(
                    row=num_row, email=email))

        contrib_data.append({
            'start_dt':
            parsed_start_dt,
            'duration':
            parsed_duration or timedelta(minutes=20),
            'title':
            title,
            'speaker': {
                'first_name': first_name,
                'last_name': last_name,
                'affiliation': affiliation,
                'email': email
            }
        })

    # now that we're sure the data is OK, let's pre-allocate the friendly ids
    # for the contributions in question
    Contribution.allocate_friendly_ids(event, len(contrib_data))
    contributions = []
    all_changes = defaultdict(list)

    for contrib_fields in contrib_data:
        speaker_data = contrib_fields.pop('speaker')

        with track_time_changes() as changes:
            contribution = create_contribution(event,
                                               contrib_fields,
                                               extend_parent=True)

        contributions.append(contribution)
        for key, val in changes[event].items():
            all_changes[key].append(val)

        email = speaker_data['email']
        if not email:
            continue

        # set the information of the speaker
        person = get_event_person(event, speaker_data)
        link = ContributionPersonLink(person=person, is_speaker=True)
        link.populate_from_dict({
            'first_name': speaker_data['first_name'],
            'last_name': speaker_data['last_name'],
            'affiliation': speaker_data['affiliation']
        })
        contribution.person_links.append(link)

    return contributions, all_changes
Example #39
0
 def contribution(self):
     return Contribution.get(self._contrib_id)
Example #40
0
 def _process_args(self):
     RHDisplayEventBase._process_args(self)
     self.contrib = Contribution.get_one(request.view_args['contrib_id'],
                                         is_deleted=False)
Example #41
0
 def contribution(self):
     return Contribution.get(self._contrib_id)