Example #1
0
def reset_abstract_state(abstract):
    abstract.reset_state()
    db.session.flush()
    logger.info('Abstract %s state reset by %s', abstract, session.user)
    abstract.event.log(EventLogRealm.management, EventLogKind.change, 'Abstracts',
                       'State of abstract {} reset'.format(abstract.verbose_title),
                       session.user)
Example #2
0
def update_reviewed_for_tracks(abstract, tracks):
    _update_tracks(abstract, tracks, only_reviewed_for=True)
    db.session.flush()
    logger.info('Reviewed tracks of abstract %s updated by %s', abstract, session.user)
    abstract.event.log(EventLogRealm.reviewing, EventLogKind.change, 'Abstracts',
                       'Reviewed tracks of abstract {} updated'.format(abstract.verbose_title),
                       session.user)
Example #3
0
def create_abstract_review(abstract, track, user, review_data, questions_data):
    review = AbstractReview(abstract=abstract, track=track, user=user)
    review.populate_from_dict(review_data)
    log_data = {}
    for question in abstract.event.abstract_review_questions:
        value = questions_data['question_{}'.format(question.id)]
        review.ratings.append(AbstractReviewRating(question=question, value=value))
        log_data[question.title] = question.field.get_friendly_value(value)
    db.session.flush()
    logger.info("Abstract %s received a review by %s for track %s", abstract, user, track)
    log_data.update({
        'Track': track.title,
        'Action': orig_string(review.proposed_action.title),
        'Comment': review.comment
    })
    if review.proposed_action == AbstractAction.accept:
        log_data['Contribution type'] = (review.proposed_contribution_type.name if review.proposed_contribution_type
                                         else None)
    elif review.proposed_action == AbstractAction.change_tracks:
        log_data['Other tracks'] = sorted(t.title for t in review.proposed_tracks)
    elif review.proposed_action in {AbstractAction.mark_as_duplicate, AbstractAction.merge}:
        log_data['Other abstract'] = review.proposed_related_abstract.verbose_title
    abstract.event.log(EventLogRealm.reviewing, EventLogKind.positive, 'Abstracts',
                       'Abstract {} reviewed'.format(abstract.verbose_title), user, data=log_data)
    return review
Example #4
0
def delete_abstract_comment(comment):
    comment.is_deleted = True
    db.session.flush()
    logger.info("Abstract comment %s deleted by %s", comment, session.user)
    comment.abstract.event.log(EventLogRealm.reviewing, EventLogKind.negative, 'Abstracts',
                               'Comment on abstract {} removed'.format(comment.abstract.verbose_title),
                               session.user)
Example #5
0
def create_abstract_review(abstract, track, user, review_data, questions_data):
    review = AbstractReview(abstract=abstract, track=track, user=user)
    review.populate_from_dict(review_data)
    log_data = {}
    for question in abstract.event.abstract_review_questions:
        value = int(questions_data['question_{}'.format(question.id)])
        review.ratings.append(AbstractReviewRating(question=question, value=value))
        log_data[question.text] = value
    db.session.flush()
    logger.info("Abstract %s received a review by %s for track %s", abstract, user, track)
    log_data.update({
        'Track': track.title,
        'Action': orig_string(review.proposed_action.title),
        'Comment': review.comment
    })
    if review.proposed_action == AbstractAction.accept:
        log_data['Contribution type'] = (review.proposed_contribution_type.name if review.proposed_contribution_type
                                         else None)
    elif review.proposed_action == AbstractAction.change_tracks:
        log_data['Other tracks'] = sorted(t.title for t in review.proposed_tracks)
    elif review.proposed_action in {AbstractAction.mark_as_duplicate, AbstractAction.merge}:
        log_data['Other abstract'] = review.proposed_related_abstract.verbose_title
    abstract.event.log(EventLogRealm.management, EventLogKind.positive, 'Abstracts',
                       'Abstract {} reviewed'.format(abstract.verbose_title), user, data=log_data)
    return review
Example #6
0
def delete_abstract_comment(comment):
    comment.is_deleted = True
    db.session.flush()
    logger.info("Abstract comment %s deleted by %s", comment, session.user)
    comment.abstract.event.log(EventLogRealm.management, EventLogKind.negative, 'Abstracts',
                               'Comment on abstract {} removed'.format(comment.abstract.verbose_title),
                               session.user)
Example #7
0
def reset_abstract_state(abstract):
    abstract.reset_state()
    db.session.flush()
    logger.info('Abstract %s state reset by %s', abstract, session.user)
    abstract.log(EventLogRealm.reviewing, LogKind.change, 'Abstracts',
                 f'State of abstract {abstract.verbose_title} reset',
                 session.user)
Example #8
0
def create_abstract(event,
                    abstract_data,
                    custom_fields_data=None,
                    send_notifications=False):
    abstract = Abstract(event=event, submitter=session.user)
    tracks = abstract_data.pop('submitted_for_tracks', None)
    attachments = abstract_data.pop('attachments', None)
    abstract.populate_from_dict(abstract_data)
    if tracks is not None:
        _update_tracks(abstract, tracks)
    if custom_fields_data:
        set_custom_fields(abstract, custom_fields_data)
    db.session.flush()

    if attachments:
        add_abstract_files(abstract, attachments['added'], log_action=False)
    signals.event.abstract_created.send(abstract)

    if send_notifications:
        send_abstract_notifications(abstract)
    logger.info('Abstract %s created by %s', abstract, session.user)
    abstract.event.log(EventLogRealm.reviewing, EventLogKind.positive,
                       'Abstracts',
                       'Abstract {} created'.format(abstract.verbose_title),
                       session.user)
    return abstract
Example #9
0
def update_reviewed_for_tracks(abstract, tracks):
    _update_tracks(abstract, tracks, only_reviewed_for=True)
    db.session.flush()
    logger.info('Reviewed tracks of abstract %s updated by %s', abstract, session.user)
    abstract.event.log(EventLogRealm.management, EventLogKind.change, 'Abstracts',
                       'Reviewed tracks of abstract {} updated'.format(abstract.verbose_title),
                       session.user)
Example #10
0
    def _process(self):
        roles = get_roles_for_event(self.event)
        form = AbstractReviewingRolesForm(event=self.event,
                                          obj=FormDefaults(roles=roles))

        if form.validate_on_submit():
            role_data = form.roles.role_data
            self.event.global_conveners = set(role_data['global_conveners'])
            self.event.global_abstract_reviewers = set(
                role_data['global_reviewers'])

            for track, user_roles in role_data['track_roles'].viewitems():
                track.conveners = set(user_roles['convener'])
                track.abstract_reviewers = set(user_roles['reviewer'])

            # Update actual ACLs
            update_object_principals(self.event,
                                     role_data['all_conveners'],
                                     permission='track_convener')
            update_object_principals(self.event,
                                     role_data['all_reviewers'],
                                     permission='abstract_reviewer')

            flash(_("Abstract reviewing roles have been updated."), 'success')
            logger.info(
                "Abstract reviewing roles of %s have been updated by %s",
                self.event, session.user)
            return jsonify_data()
        return jsonify_form(form,
                            skip_labels=True,
                            form_header_kwargs={'id': 'reviewing-role-form'},
                            disabled_until_change=True)
Example #11
0
def reset_abstract_state(abstract):
    abstract.reset_state()
    db.session.flush()
    logger.info('Abstract %s state reset by %s', abstract, session.user)
    abstract.event.log(EventLogRealm.reviewing, EventLogKind.change, 'Abstracts',
                       'State of abstract {} reset'.format(abstract.verbose_title),
                       session.user)
Example #12
0
def add_abstract_files(abstract, files, log_action=True):
    if not files:
        return
    for f in files:
        filename = secure_filename(f.filename, 'attachment')
        content_type = mimetypes.guess_type(
            f.filename)[0] or f.mimetype or 'application/octet-stream'
        abstract_file = AbstractFile(filename=filename,
                                     content_type=content_type,
                                     abstract=abstract)
        abstract_file.save(f.stream)
        db.session.flush()
    if log_action:
        logger.info('%d abstract file(s) added to %s by %s', len(files),
                    abstract, session.user)
        num = len(files)
        if num == 1:
            msg = 'Added file to abstract {}'.format(abstract.verbose_title)
        else:
            msg = 'Added {} files to abstract {}'.format(
                num, abstract.verbose_title)
        abstract.event.log(
            EventLogRealm.reviewing,
            EventLogKind.positive,
            'Abstracts',
            msg,
            session.user,
            data={'Files': ', '.join(f.filename for f in abstract.files)})
Example #13
0
def judge_abstract(abstract, abstract_data, judgment, judge, contrib_session=None, merge_persons=False,
                   send_notifications=False):
    from indico.modules.events.tracks.models.tracks import Track
    abstract.judge = judge
    abstract.judgment_dt = now_utc()
    abstract.judgment_comment = abstract_data['judgment_comment']
    log_data = {'Judgment': orig_string(judgment.title)}
    if judgment == AbstractAction.accept:
        abstract.state = AbstractState.accepted
        abstract.accepted_track = abstract_data.get('accepted_track')
        if abstract_data.get('override_contrib_type') or abstract_data.get('accepted_contrib_type'):
            abstract.accepted_contrib_type = abstract_data.get('accepted_contrib_type')
        else:
            abstract.accepted_contrib_type = abstract.submitted_contrib_type
        if not abstract.contribution:
            abstract.contribution = create_contribution_from_abstract(abstract, contrib_session)
        if abstract.accepted_track:
            log_data['Track'] = abstract.accepted_track.title
        if abstract.accepted_contrib_type:
            log_data['Type'] = abstract.accepted_contrib_type.name

        from indico.modules.events.contributions.models.limits import ContributionLimit
        from sqlalchemy import func

        if not abstract.accepted_contrib_type:
            raise Exception("The contribution type is missing.")

        limit_obj =  ContributionLimit.query.filter_by(event_id=abstract.event.id,
                                                       track_id=(None if not abstract.accepted_track else abstract.accepted_track.id),
                                                       type_id=abstract.accepted_contrib_type.id).first()
        limit = None if not limit_obj else limit_obj.value
        val = Abstract.query.filter_by(event_id=abstract.event.id,
                                       accepted_track_id=(None if not abstract.accepted_track else abstract.accepted_track.id),
                                       accepted_contrib_type_id=abstract.accepted_contrib_type.id).count()

        if limit and val >= limit+1:
            raise Exception("Abstract admission limit of <b>%s</b> has been reached for type <i>'%s'</i> on track <i>'%s'</i>."
            " Please either reset a previous judgement or report this." % (limit, abstract.accepted_contrib_type.name,
            'No track' if not abstract.accepted_track else abstract.accepted_track.title))

    elif judgment == AbstractAction.reject:
        abstract.state = AbstractState.rejected
    elif judgment == AbstractAction.mark_as_duplicate:
        abstract.state = AbstractState.duplicate
        abstract.duplicate_of = abstract_data['duplicate_of']
        log_data['Duplicate of'] = abstract.duplicate_of.verbose_title
    elif judgment == AbstractAction.merge:
        abstract.state = AbstractState.merged
        abstract.merged_into = abstract_data['merged_into']
        log_data['Merged into'] = abstract.merged_into.verbose_title
        log_data['Merge authors'] = merge_persons
        if merge_persons:
            _merge_person_links(abstract.merged_into, abstract)
    db.session.flush()
    if send_notifications:
        log_data['Notifications sent'] = send_abstract_notifications(abstract)
    logger.info('Abstract %s judged by %s', abstract, judge)
    abstract.event.log(EventLogRealm.management, EventLogKind.change, 'Abstracts',
                       'Abstract {} judged'.format(abstract.verbose_title), judge, data=log_data)
Example #14
0
def delete_abstract_comment(comment):
    comment.is_deleted = True
    db.session.flush()
    logger.info('Abstract comment %s deleted by %s', comment, session.user)
    comment.abstract.log(
        EventLogRealm.reviewing, LogKind.negative, 'Abstracts',
        f'Comment on abstract {comment.abstract.verbose_title} removed',
        session.user)
Example #15
0
def create_abstract_comment(abstract, comment_data):
    comment = AbstractComment(user=session.user)
    comment.populate_from_dict(comment_data)
    comment.abstract = abstract
    db.session.flush()
    logger.info("Abstract %s received a comment from %s", abstract, session.user)
    abstract.log(EventLogRealm.reviewing, EventLogKind.positive, 'Abstracts',
                 'Abstract {} received a comment'.format(abstract.verbose_title), session.user)
Example #16
0
 def _process(self):
     form = self.field_cls.create_config_form()
     if form.validate_on_submit():
         new_question = create_reviewing_question(self.event, AbstractReviewQuestion, self.field_cls, form)
         self.event.abstract_review_questions.append(new_question)
         logger.info("Abstract reviewing question %r created by %r", new_question, session.user)
         return jsonify_data(flash=False)
     return jsonify_form(form, fields=getattr(form, '_order', None))
Example #17
0
 def _process(self):
     form = self.field_cls.create_config_form()
     if form.validate_on_submit():
         new_question = create_reviewing_question(self.event, AbstractReviewQuestion, self.field_cls, form)
         self.event.abstract_review_questions.append(new_question)
         logger.info("Abstract reviewing question %r created by %r", new_question, session.user)
         return jsonify_data(flash=False)
     return jsonify_form(form, fields=getattr(form, '_order', None))
Example #18
0
def update_reviewed_for_tracks(abstract, tracks):
    _update_tracks(abstract, tracks, only_reviewed_for=True)
    db.session.flush()
    logger.info('Reviewed tracks of abstract %s updated by %s', abstract,
                session.user)
    abstract.log(
        EventLogRealm.reviewing, LogKind.change, 'Abstracts',
        f'Reviewed tracks of abstract {abstract.verbose_title} updated',
        session.user)
Example #19
0
def create_abstract_comment(abstract, comment_data):
    comment = AbstractComment(user=session.user)
    comment.populate_from_dict(comment_data)
    comment.abstract = abstract
    db.session.flush()
    logger.info("Abstract %s received a comment from %s", abstract, session.user)
    abstract.event.log(EventLogRealm.reviewing, EventLogKind.positive, 'Abstracts',
                       'Abstract {} received a comment'.format(abstract.verbose_title),
                       session.user)
Example #20
0
def update_abstract_review(review, review_data, questions_data):
    event = review.abstract.event
    changes = review.populate_from_dict(review_data)
    review.modified_dt = now_utc()
    log_fields = {}
    for question in event.abstract_review_questions:
        field_name = 'question_{}'.format(question.id)
        rating = question.get_review_rating(review, allow_create=True)
        old_value = rating.value
        rating.value = questions_data[field_name]
        if old_value != rating.value:
            field_type = question.field_type
            changes[field_name] = (
                question.field.get_friendly_value(old_value),
                question.field.get_friendly_value(rating.value))
            log_fields[field_name] = {
                'title': question.title,
                'type': field_type if field_type != 'rating' else 'number'
            }

    db.session.flush()
    logger.info("Abstract review %s modified", review)
    log_fields.update({'proposed_action': 'Action', 'comment': 'Comment'})
    if review.proposed_action in {
            AbstractAction.mark_as_duplicate, AbstractAction.merge
    }:
        log_fields['proposed_related_abstract'] = {
            'title':
            'Other abstract',
            'type':
            'string',
            'convert':
            lambda change: [x.verbose_title if x else None for x in change]
        }
    elif review.proposed_action == AbstractAction.accept:
        log_fields['proposed_contribution_type'] = {
            'title': 'Contribution type',
            'type': 'string',
            'convert': lambda change: [x.name if x else None for x in change]
        }
    elif review.proposed_action == AbstractAction.change_tracks:
        log_fields['proposed_tracks'] = {
            'title': 'Other tracks',
            'convert':
            lambda change: [sorted(t.title for t in x) for x in change]
        }
    event.log(EventLogRealm.reviewing,
              EventLogKind.change,
              'Abstracts',
              'Review for abstract {} modified'.format(
                  review.abstract.verbose_title),
              session.user,
              data={
                  'Track': review.track.title,
                  'Changes': make_diff_log(changes, log_fields)
              })
Example #21
0
def update_abstract_comment(comment, comment_data):
    changes = comment.populate_from_dict(comment_data)
    comment.modified_by = session.user
    comment.modified_dt = now_utc()
    db.session.flush()
    logger.info("Abstract comment %s modified by %s", comment, session.user)
    comment.abstract.event.log(EventLogRealm.management, EventLogKind.change, 'Abstracts',
                               'Comment on abstract {} modified'.format(comment.abstract.verbose_title),
                               session.user,
                               data={'Changes': make_diff_log(changes, {'text': 'Text', 'visibility': 'Visibility'})})
Example #22
0
def update_abstract_comment(comment, comment_data):
    changes = comment.populate_from_dict(comment_data)
    comment.modified_by = session.user
    comment.modified_dt = now_utc()
    db.session.flush()
    logger.info("Abstract comment %s modified by %s", comment, session.user)
    comment.abstract.event.log(EventLogRealm.reviewing, EventLogKind.change, 'Abstracts',
                               'Comment on abstract {} modified'.format(comment.abstract.verbose_title),
                               session.user,
                               data={'Changes': make_diff_log(changes, {'text': 'Text', 'visibility': 'Visibility'})})
Example #23
0
    def _process(self):
        roles = {}
        event_permissions = event_permissions_schema.dump(self.event).get('acl_entries', {})
        roles['global'] = self._map_event_to_track_permissions(event_permissions)
        tracks = Track.query.with_parent(self.event).options(subqueryload('acl_entries'))
        tracks_by_id = {str(track.id): track for track in tracks}
        for track in tracks:
            roles[str(track.id)] = track_permissions_schema.dump(track).get('acl_entries', {})
        form = AbstractReviewingRolesForm(event=self.event, obj=FormDefaults(roles=roles))

        if form.validate_on_submit():
            role_data = form.data['roles']

            # Update global permissions
            global_conveners = []
            global_reviewers = []
            global_roles = role_data.pop('global')
            for identifier, permissions in global_roles:
                principal = principal_from_identifier(identifier, allow_groups=True, allow_event_roles=True,
                                                      event_id=self.event.id)
                if 'convene' in permissions:
                    global_conveners.append(principal)
                if 'review' in permissions:
                    global_reviewers.append(principal)
            update_object_principals(self.event, global_conveners, permission='convene_all_abstracts')
            update_object_principals(self.event, global_reviewers, permission='review_all_abstracts')

            # Update track specific permissions
            track_conveners = []
            track_reviewers = []
            for (track_id, track_roles) in role_data.items():
                acl_entries = {}
                for identifier, permissions in track_roles:
                    principal = principal_from_identifier(identifier, allow_groups=True, allow_event_roles=True,
                                                          event_id=self.event.id)
                    acl_entries[principal] = set(permissions)
                    if 'convene' in permissions:
                        track_conveners.append(principal)
                    if 'review' in permissions:
                        track_reviewers.append(principal)
                track = tracks_by_id[track_id]
                current = {e.principal: get_unified_permissions(e) for e in track.acl_entries}
                update_principals_permissions(track, current, acl_entries)

            # Update event ACL for track and global permissions
            all_conveners = set(global_conveners + track_conveners)
            all_reviewers = set(global_reviewers + track_reviewers)
            update_object_principals(self.event, all_conveners, permission='track_convener')
            update_object_principals(self.event, all_reviewers, permission='abstract_reviewer')

            flash(_("Abstract reviewing roles have been updated."), 'success')
            logger.info("Abstract reviewing roles of %s have been updated by %s", self.event, session.user)
            return jsonify_data()
        return jsonify_form(form, skip_labels=True, form_header_kwargs={'id': 'reviewing-role-form'},
                            disabled_until_change=False)
Example #24
0
def delete_abstract(abstract, delete_contrib=False):
    abstract.is_deleted = True
    contrib = abstract.contribution
    abstract.contribution = None
    if delete_contrib and contrib:
        delete_contribution(contrib)
    db.session.flush()
    signals.event.abstract_deleted.send(abstract)
    logger.info('Abstract %s deleted by %s', abstract, session.user)
    abstract.event.log(EventLogRealm.reviewing, EventLogKind.negative, 'Abstracts',
                       'Abstract {} deleted'.format(abstract.verbose_title), session.user)
Example #25
0
def withdraw_abstract(abstract, delete_contrib=False):
    abstract.state = AbstractState.withdrawn
    contrib = abstract.contribution
    abstract.contribution = None
    if delete_contrib and contrib:
        delete_contribution(contrib)
    db.session.flush()
    signals.event.abstract_state_changed.send(abstract)
    logger.info('Abstract %s withdrawn by %s', abstract, session.user)
    abstract.event_new.log(EventLogRealm.management, EventLogKind.negative, 'Abstracts',
                           'Abstract {} withdrawn'.format(abstract.verbose_title), session.user)
Example #26
0
def withdraw_abstract(abstract, delete_contrib=False):
    abstract.state = AbstractState.withdrawn
    contrib = abstract.contribution
    abstract.contribution = None
    if delete_contrib and contrib:
        delete_contribution(contrib)
    db.session.flush()
    signals.event.abstract_state_changed.send(abstract)
    logger.info('Abstract %s withdrawn by %s', abstract, session.user)
    abstract.event_new.log(EventLogRealm.management, EventLogKind.negative, 'Abstracts',
                           'Abstract {} withdrawn'.format(abstract.verbose_title), session.user)
Example #27
0
def delete_abstract(abstract, delete_contrib=False):
    abstract.is_deleted = True
    contrib = abstract.contribution
    abstract.contribution = None
    if delete_contrib and contrib:
        delete_contribution(contrib)
    db.session.flush()
    signals.event.abstract_deleted.send(abstract)
    logger.info('Abstract %s deleted by %s', abstract, session.user)
    abstract.event.log(EventLogRealm.management, EventLogKind.negative, 'Abstracts',
                       'Abstract {} deleted'.format(abstract.verbose_title), session.user)
Example #28
0
def schedule_cfa(event, start_dt, end_dt, modification_end_dt):
    event.cfa.schedule(start_dt, end_dt, modification_end_dt)
    logger.info("Call for abstracts for %s scheduled by %s", event, session.user)
    log_data = {}
    if start_dt:
        log_data['Start'] = start_dt.isoformat()
    if end_dt:
        log_data['End'] = end_dt.isoformat()
    if modification_end_dt:
        log_data['Modification deadline'] = modification_end_dt.isoformat()
    event.log(EventLogRealm.management, EventLogKind.change, 'Abstracts', 'Call for abstracts scheduled', session.user,
              data=log_data)
Example #29
0
def schedule_cfa(event, start_dt, end_dt, modification_end_dt):
    event.cfa.schedule(start_dt, end_dt, modification_end_dt)
    logger.info("Call for abstracts for %s scheduled by %s", event, session.user)
    log_data = {}
    if start_dt:
        log_data['Start'] = start_dt.isoformat()
    if end_dt:
        log_data['End'] = end_dt.isoformat()
    if modification_end_dt:
        log_data['Modification deadline'] = modification_end_dt.isoformat()
    event.log(EventLogRealm.reviewing, EventLogKind.change, 'Abstracts', 'Call for abstracts scheduled', session.user,
              data=log_data)
Example #30
0
def withdraw_abstract(abstract):
    abstract.reset_state()
    abstract.state = AbstractState.withdrawn
    contrib = abstract.contribution
    abstract.contribution = None
    if contrib:
        delete_contribution(contrib)
    db.session.flush()
    signals.event.abstract_state_changed.send(abstract)
    logger.info('Abstract %s withdrawn by %s', abstract, session.user)
    abstract.log(EventLogRealm.reviewing, EventLogKind.negative, 'Abstracts',
                 f'Abstract {abstract.verbose_title} withdrawn', session.user)
Example #31
0
def delete_abstract_files(abstract, files):
    if not files:
        return
    num = len(files)
    for file_ in files:
        db.session.delete(file_)
    logger.info('%d abstract files deleted from %s by %s', num, abstract, session.user)
    if num == 1:
        msg = 'Deleted file from abstract {}'.format(abstract.verbose_title)
    else:
        msg = 'Deleted {} files from abstract {}'.format(num, abstract.verbose_title)
    abstract.event.log(EventLogRealm.management, EventLogKind.negative, 'Abstracts', msg, session.user,
                       data={'Files': ', '.join(f.filename for f in files)})
Example #32
0
def delete_abstract_files(abstract, files):
    if not files:
        return
    num = len(files)
    for file_ in files:
        db.session.delete(file_)
    logger.info('%d abstract files deleted from %s by %s', num, abstract, session.user)
    if num == 1:
        msg = 'Deleted file from abstract {}'.format(abstract.verbose_title)
    else:
        msg = 'Deleted {} files from abstract {}'.format(num, abstract.verbose_title)
    abstract.event.log(EventLogRealm.reviewing, EventLogKind.negative, 'Abstracts', msg, session.user,
                       data={'Files': ', '.join(f.filename for f in files)})
Example #33
0
def update_abstract(abstract, abstract_data, custom_fields_data=None):
    tracks = abstract_data.pop('submitted_for_tracks', None)
    attachments = abstract_data.pop('attachments', None)
    changes = {}

    if tracks is not None and abstract.edit_track_mode == EditTrackMode.both:
        changes.update(_update_tracks(abstract, tracks))

    if attachments:
        deleted_files = {f for f in abstract.files if f.id in attachments['deleted']}
        abstract.files = list(set(abstract.files) - deleted_files)
        delete_abstract_files(abstract, deleted_files)
        add_abstract_files(abstract, attachments['added'])

    changes.update(abstract.populate_from_dict(abstract_data))
    if custom_fields_data:
        changes.update(set_custom_fields(abstract, custom_fields_data))
    db.session.flush()
    logger.info('Abstract %s modified by %s', abstract, session.user)
    log_fields = {
        'title': 'Title',
        'description': 'Content',
        'submission_comment': 'Comment',
        'submitted_for_tracks': {
            'title': 'Tracks',
            'convert': lambda change: [sorted(t.title for t in x) for x in change]
        },
        'submitted_contrib_type': {
            'title': 'Contribution type',
            'type': 'string',
            'convert': lambda change: [t.name if t else None for t in change]
        }
    }
    for field_name, change in changes.iteritems():
        # we skip skip None -> '' changes (editing an abstract that
        # did not have a value for a new field yet without filling
        # it out)
        if not field_name.startswith('custom_') or not any(changes):
            continue
        field_id = int(field_name[7:])
        field = abstract.event.get_contribution_field(field_id)
        field_impl = field.field
        log_fields[field_name] = {
            'title': field.title,
            'type': field_impl.log_type,
            'convert': lambda change, field_impl=field_impl: map(field_impl.get_friendly_value, change)
        }
    abstract.event.log(EventLogRealm.reviewing, EventLogKind.change, 'Abstracts',
                       'Abstract {} modified'.format(abstract.verbose_title), session.user,
                       data={'Changes': make_diff_log(changes, log_fields)})
Example #34
0
def judge_abstract(abstract,
                   abstract_data,
                   judgment,
                   judge,
                   contrib_session=None,
                   merge_persons=False,
                   send_notifications=False):
    abstract.judge = judge
    abstract.judgment_dt = now_utc()
    abstract.judgment_comment = abstract_data['judgment_comment']
    log_data = {'Judgment': orig_string(judgment.title)}
    if judgment == AbstractAction.accept:
        abstract.state = AbstractState.accepted
        abstract.accepted_track = abstract_data.get('accepted_track')
        if abstract_data.get('override_contrib_type') or abstract_data.get(
                'accepted_contrib_type'):
            abstract.accepted_contrib_type = abstract_data.get(
                'accepted_contrib_type')
        else:
            abstract.accepted_contrib_type = abstract.submitted_contrib_type
        if not abstract.contribution:
            abstract.contribution = create_contribution_from_abstract(
                abstract, contrib_session)
        if abstract.accepted_track:
            log_data['Track'] = abstract.accepted_track.title
        if abstract.accepted_contrib_type:
            log_data['Type'] = abstract.accepted_contrib_type.name
    elif judgment == AbstractAction.reject:
        abstract.state = AbstractState.rejected
    elif judgment == AbstractAction.mark_as_duplicate:
        abstract.state = AbstractState.duplicate
        abstract.duplicate_of = abstract_data['duplicate_of']
        log_data['Duplicate of'] = abstract.duplicate_of.verbose_title
    elif judgment == AbstractAction.merge:
        abstract.state = AbstractState.merged
        abstract.merged_into = abstract_data['merged_into']
        log_data['Merged into'] = abstract.merged_into.verbose_title
        log_data['Merge authors'] = merge_persons
        if merge_persons:
            _merge_person_links(abstract.merged_into, abstract)
    db.session.flush()
    if send_notifications:
        log_data['Notifications sent'] = send_abstract_notifications(abstract)
    logger.info('Abstract %s judged by %s', abstract, judge)
    abstract.event.log(EventLogRealm.reviewing,
                       EventLogKind.change,
                       'Abstracts',
                       'Abstract {} judged'.format(abstract.verbose_title),
                       judge,
                       data=log_data)
Example #35
0
def update_abstract(abstract, abstract_data, custom_fields_data=None):
    tracks = abstract_data.pop('submitted_for_tracks', None)
    attachments = abstract_data.pop('attachments', None)
    changes = {}

    if tracks is not None and abstract.edit_track_mode == EditTrackMode.both:
        changes.update(_update_tracks(abstract, tracks))

    if attachments:
        deleted_files = {f for f in abstract.files if f.id in attachments['deleted']}
        abstract.files = list(set(abstract.files) - deleted_files)
        delete_abstract_files(abstract, deleted_files)
        add_abstract_files(abstract, attachments['added'])

    changes.update(abstract.populate_from_dict(abstract_data))
    if custom_fields_data:
        changes.update(set_custom_fields(abstract, custom_fields_data))
    db.session.flush()
    logger.info('Abstract %s modified by %s', abstract, session.user)
    log_fields = {
        'title': 'Title',
        'description': 'Content',
        'submission_comment': 'Comment',
        'submitted_for_tracks': {
            'title': 'Tracks',
            'convert': lambda change: [sorted(t.title for t in x) for x in change]
        },
        'submitted_contrib_type': {
            'title': 'Contribution type',
            'type': 'string',
            'convert': lambda change: [t.name if t else None for t in change]
        }
    }
    for field_name, change in changes.iteritems():
        # we skip skip None -> '' changes (editing an abstract that
        # did not have a value for a new field yet without filling
        # it out)
        if not field_name.startswith('custom_') or not any(changes):
            continue
        field_id = int(field_name[7:])
        field = abstract.event.get_contribution_field(field_id)
        field_impl = field.field
        log_fields[field_name] = {
            'title': field.title,
            'type': field_impl.log_type,
            'convert': lambda change, field_impl=field_impl: map(field_impl.get_friendly_value, change)
        }
    abstract.event.log(EventLogRealm.management, EventLogKind.change, 'Abstracts',
                       'Abstract {} modified'.format(abstract.verbose_title), session.user,
                       data={'Changes': make_diff_log(changes, log_fields)})
Example #36
0
def update_abstract_review(review, review_data, questions_data):
    event = review.abstract.event
    changes = review.populate_from_dict(review_data)
    review.modified_dt = now_utc()
    log_fields = {}
    for question in event.abstract_review_questions:
        field_name = 'question_{}'.format(question.id)
        rating = question.get_review_rating(review, allow_create=True)
        old_value = rating.value
        rating.value = questions_data[field_name]
        if old_value != rating.value:
            field_type = question.field_type
            changes[field_name] = (question.field.get_friendly_value(old_value),
                                   question.field.get_friendly_value(rating.value))
            log_fields[field_name] = {
                'title': question.title,
                'type': field_type if field_type != 'rating' else 'number'
            }

    db.session.flush()
    logger.info("Abstract review %s modified", review)
    log_fields.update({
        'proposed_action': 'Action',
        'comment': 'Comment'
    })
    if review.proposed_action in {AbstractAction.mark_as_duplicate, AbstractAction.merge}:
        log_fields['proposed_related_abstract'] = {
            'title': 'Other abstract',
            'type': 'string',
            'convert': lambda change: [x.verbose_title if x else None for x in change]
        }
    elif review.proposed_action == AbstractAction.accept:
        log_fields['proposed_contribution_type'] = {
            'title': 'Contribution type',
            'type': 'string',
            'convert': lambda change: [x.name if x else None for x in change]
        }
    elif review.proposed_action == AbstractAction.change_tracks:
        log_fields['proposed_tracks'] = {
            'title': 'Other tracks',
            'convert': lambda change: [sorted(t.title for t in x) for x in change]
        }
    event.log(EventLogRealm.reviewing, EventLogKind.change, 'Abstracts',
              'Review for abstract {} modified'.format(review.abstract.verbose_title),
              session.user, data={'Track': review.track.title, 'Changes': make_diff_log(changes, log_fields)})
Example #37
0
def delete_abstract_files(abstract, files):
    if not files:
        return
    num = len(files)
    for file_ in files:
        db.session.delete(file_)
    logger.info('%d abstract files deleted from %s by %s', num, abstract,
                session.user)
    if num == 1:
        msg = f'Deleted file from abstract {abstract.verbose_title}'
    else:
        msg = f'Deleted {num} files from abstract {abstract.verbose_title}'
    abstract.log(EventLogRealm.reviewing,
                 LogKind.negative,
                 'Abstracts',
                 msg,
                 session.user,
                 data={'Files': ', '.join(f.filename for f in files)})
Example #38
0
def add_abstract_files(abstract, files, log_action=True):
    if not files:
        return
    for f in files:
        filename = secure_filename(f.filename, 'attachment')
        content_type = mimetypes.guess_type(f.filename)[0] or f.mimetype or 'application/octet-stream'
        abstract_file = AbstractFile(filename=filename, content_type=content_type, abstract=abstract)
        abstract_file.save(f.stream)
        db.session.flush()
    if log_action:
        logger.info('%d abstract file(s) added to %s by %s', len(files), abstract, session.user)
        num = len(files)
        if num == 1:
            msg = 'Added file to abstract {}'.format(abstract.verbose_title)
        else:
            msg = 'Added {} files to abstract {}'.format(num, abstract.verbose_title)
        abstract.event.log(EventLogRealm.reviewing, EventLogKind.positive, 'Abstracts', msg, session.user,
                           data={'Files': ', '.join(f.filename for f in abstract.files)})
Example #39
0
def create_abstract(event, abstract_data, custom_fields_data=None, send_notifications=False):
    abstract = Abstract(event=event, submitter=session.user)
    tracks = abstract_data.pop('submitted_for_tracks', None)
    attachments = abstract_data.pop('attachments', None)
    abstract.populate_from_dict(abstract_data)
    if tracks is not None:
        _update_tracks(abstract, tracks)
    if custom_fields_data:
        set_custom_fields(abstract, custom_fields_data)
    db.session.flush()

    if attachments:
        add_abstract_files(abstract, attachments['added'], log_action=False)
    signals.event.abstract_created.send(abstract)

    if send_notifications:
        send_abstract_notifications(abstract)
    logger.info('Abstract %s created by %s', abstract, session.user)
    abstract.event.log(EventLogRealm.reviewing, EventLogKind.positive, 'Abstracts',
                       'Abstract {} created'.format(abstract.verbose_title), session.user)
    return abstract
Example #40
0
    def _process(self):
        roles = get_roles_for_event(self.event_new)
        form = AbstractReviewingRolesForm(event=self.event_new, obj=FormDefaults(roles=roles))

        if form.validate_on_submit():
            role_data = form.roles.role_data
            self.event_new.global_conveners = set(role_data['global_conveners'])
            self.event_new.global_abstract_reviewers = set(role_data['global_reviewers'])

            for track, user_roles in role_data['track_roles'].viewitems():
                track.conveners = set(user_roles['convener'])
                track.abstract_reviewers = set(user_roles['reviewer'])

            # Update actual ACLs
            update_object_principals(self.event_new, role_data['all_conveners'], role='track_convener')
            update_object_principals(self.event_new, role_data['all_reviewers'], role='abstract_reviewer')

            flash(_("Abstract reviewing roles have been updated."), 'success')
            logger.info("Abstract reviewing roles of %s have been updated by %s", self.event_new, session.user)
            return jsonify_data()
        return jsonify_form(form, skip_labels=True, form_header_kwargs={'id': 'reviewing-role-form'},
                            disabled_until_change=True)
Example #41
0
def judge_abstract(abstract, abstract_data, judgment, judge, contrib_session=None, merge_persons=False,
                   send_notifications=False):
    abstract.judge = judge
    abstract.judgment_dt = now_utc()
    abstract.judgment_comment = abstract_data['judgment_comment']
    log_data = {'Judgment': orig_string(judgment.title)}
    if judgment == AbstractAction.accept:
        abstract.state = AbstractState.accepted
        abstract.accepted_track = abstract_data.get('accepted_track')
        if abstract_data.get('override_contrib_type') or abstract_data.get('accepted_contrib_type'):
            abstract.accepted_contrib_type = abstract_data.get('accepted_contrib_type')
        else:
            abstract.accepted_contrib_type = abstract.submitted_contrib_type
        if not abstract.contribution:
            abstract.contribution = create_contribution_from_abstract(abstract, contrib_session)
        if abstract.accepted_track:
            log_data['Track'] = abstract.accepted_track.title
        if abstract.accepted_contrib_type:
            log_data['Type'] = abstract.accepted_contrib_type.name
    elif judgment == AbstractAction.reject:
        abstract.state = AbstractState.rejected
    elif judgment == AbstractAction.mark_as_duplicate:
        abstract.state = AbstractState.duplicate
        abstract.duplicate_of = abstract_data['duplicate_of']
        log_data['Duplicate of'] = abstract.duplicate_of.verbose_title
    elif judgment == AbstractAction.merge:
        abstract.state = AbstractState.merged
        abstract.merged_into = abstract_data['merged_into']
        log_data['Merged into'] = abstract.merged_into.verbose_title
        log_data['Merge authors'] = merge_persons
        if merge_persons:
            _merge_person_links(abstract.merged_into, abstract)
    db.session.flush()
    if send_notifications:
        log_data['Notifications sent'] = send_abstract_notifications(abstract)
    logger.info('Abstract %s judged by %s', abstract, judge)
    abstract.event.log(EventLogRealm.reviewing, EventLogKind.change, 'Abstracts',
                       'Abstract {} judged'.format(abstract.verbose_title), judge, data=log_data)
Example #42
0
def open_cfa(event):
    event.cfa.open()
    logger.info("Call for abstracts for %s opened by %s", event, session.user)
    event.log(EventLogRealm.reviewing, EventLogKind.positive, 'Abstracts', 'Call for abstracts opened', session.user)
Example #43
0
def close_cfa(event):
    event.cfa.close()
    logger.info("Call for abstracts for %s closed by %s", event, session.user)
    event.log(EventLogRealm.reviewing, EventLogKind.negative, 'Abstracts',
              'Call for abstracts closed', session.user)
Example #44
0
def open_cfa(event):
    event.cfa.open()
    logger.info("Call for abstracts for %s opened by %s", event, session.user)
    event.log(EventLogRealm.reviewing, EventLogKind.positive, 'Abstracts',
              'Call for abstracts opened', session.user)
Example #45
0
def close_cfa(event):
    event.cfa.close()
    logger.info("Call for abstracts for %s closed by %s", event, session.user)
    event.log(EventLogRealm.reviewing, EventLogKind.negative, 'Abstracts', 'Call for abstracts closed', session.user)