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)
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)
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
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)
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
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)
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)
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
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)
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)
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)
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)})
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)
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)
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)
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))
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)
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)
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) })
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'})})
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'})})
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)
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)
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)
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)
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)
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)
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)
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)})
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)})
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)})
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)
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)})
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)})
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)})
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)})
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)
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)
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)
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)