Пример #1
0
def dummy_abstract(db, dummy_event, dummy_user, create_dummy_person):
    abstract = Abstract(
        friendly_id=314,
        title='Broken Symmetry and the Mass of Gauge Vector Mesons',
        event=dummy_event,
        submitter=dummy_user,
        locator={
            'event_id': -314,
            'abstract_id': 1234
        },
        judgment_comment='Vague but interesting!')

    author1 = create_dummy_person(abstract, 'John', 'Doe', '*****@*****.**',
                                  'ACME', UserTitle.mr, True,
                                  AuthorType.primary)
    author2 = create_dummy_person(abstract, 'Pocahontas', 'Silva',
                                  '*****@*****.**', 'ACME',
                                  UserTitle.prof, False, AuthorType.primary)
    coauthor1 = create_dummy_person(abstract, 'John', 'Smith',
                                    '*****@*****.**', 'ACME', UserTitle.dr,
                                    False, AuthorType.primary)

    abstract.person_links = [author1, author2, coauthor1]
    db.session.add(abstract)
    db.session.flush()
    return abstract
Пример #2
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
Пример #3
0
def create_mock_abstract(event):
    """Create a mock abstract that can be used in previews.

    Brace for geek references.
    """
    User = namedtuple('Author', ['first_name', 'last_name', 'title', 'full_name'])
    Track = namedtuple('Track', ['title'])
    Session = namedtuple('Session', ['title'])
    ContributionType = namedtuple('ContributionType', ['name'])
    Contribution = namedtuple('Contribution', ['title', 'track', 'session', 'type', 'locator'])
    Abstract = namedtuple('Abstract', ['friendly_id', 'title', 'event_new', 'submitter', 'contribution',
                                       'primary_authors', 'secondary_authors', 'locator', 'judgment_comment',
                                       'accepted_track', 'accepted_contrib_type', 'state', 'merged_into'])

    englert = User(full_name="Fran\xe7ois Englert", first_name="Fran\xe7ois", last_name="Englert", title="Prof.")
    brout = User(full_name="Robert Brout", first_name="Robert", last_name="Brout", title="Prof.")
    guralnik = User(full_name="Gerald Guralnik", first_name="Gerald", last_name="Guralnik", title="Prof.")
    hagen = User(full_name="Carl Hagen", first_name="Carl", last_name="Hagen", title="Prof.")
    kibble = User(full_name="Tom Kibble", first_name="Tom", last_name="Kibble", title="Prof.")
    higgs = User(full_name="Peter Higgs", first_name="Peter", last_name="Higgs", title="Prof.")

    track = Track(title=_("Higgs Fields"))
    session = Session(title=_("Higgs Fields Posters"))
    contribution_type = ContributionType(name=_("Poster"))
    contribution = Contribution(title="Broken Symmetry and the Mass of Gauge Vector Mesons",
                                track=track,
                                session=session,
                                type=contribution_type,
                                locator={'confId': -314, 'contrib_id': 1234})

    target_abstract = Abstract(friendly_id=315,
                               title="Broken Symmetry",
                               accepted_track=track,
                               accepted_contrib_type=contribution_type,
                               event_new=event,
                               submitter=brout,
                               state=AbstractState.accepted,
                               contribution=contribution,
                               primary_authors=[englert, brout],
                               secondary_authors=[guralnik, hagen, kibble, higgs],
                               locator={'confId': -314, 'abstract_id': 1235},
                               judgment_comment='Vague but interesting!',
                               merged_into=None)

    abstract = Abstract(friendly_id=314,
                        title="Broken Symmetry and the Mass of Gauge Vector Mesons",
                        accepted_track=track,
                        accepted_contrib_type=contribution_type,
                        event_new=event,
                        submitter=brout,
                        state=AbstractState.accepted,
                        contribution=contribution,
                        primary_authors=[englert, brout],
                        secondary_authors=[guralnik, hagen, kibble, higgs],
                        locator={'confId': -314, 'abstract_id': 1234},
                        judgment_comment='Vague but interesting!',
                        merged_into=target_abstract)

    return abstract
Пример #4
0
 def as_new(self):
     try:
         return self.all_for_event(self.event)[int(self._id)]
     except KeyError:
         # then the abstract is new and has to be fetched from the DB
         return Abstract.find_one(event_new=self.event,
                                  friendly_id=self._id)
Пример #5
0
def test_notification_rules(mocker, abstract_objects, create_email_template,
                            dummy_user, dummy_event):
    send_email = mocker.patch(
        'indico.modules.events.abstracts.notifications.send_email')

    event, abstract, track, contrib_type = abstract_objects
    event.abstract_email_templates.append(
        create_email_template(event, 0, 'merge', 'merged poster for track', [{
            'state': [AbstractState.merged.value],
            'track': [track.id]
        }], True))

    send_abstract_notifications(abstract)
    assert send_email.call_count == 0

    abstract.state = AbstractState.accepted
    abstract.judge = dummy_user
    abstract.judgment_dt = now_utc(False)
    abstract.accepted_track = track
    send_abstract_notifications(abstract)
    assert send_email.call_count == 0

    abstract.state = AbstractState.merged
    abstract.merged_into = Abstract(title='test',
                                    submitter=dummy_user,
                                    event=dummy_event)
    abstract.accepted_track = None
    abstract.submitted_for_tracks = {track}
    send_abstract_notifications(abstract)
    assert send_email.call_count == 1
Пример #6
0
def compat_abstract(endpoint,
                    confId,
                    friendly_id,
                    track_id=None,
                    management=False):
    abstract = Abstract.find(event_id=confId,
                             friendly_id=friendly_id).first_or_404()
    return redirect(
        url_for('abstracts.' + endpoint, abstract, management=management))
Пример #7
0
def dummy_abstract(db, dummy_event, dummy_user, create_dummy_person):
    abstract = Abstract(friendly_id=314,
                        title="Broken Symmetry and the Mass of Gauge Vector Mesons",
                        event=dummy_event,
                        submitter=dummy_user,
                        locator={'confId': -314, 'abstract_id': 1234},
                        judgment_comment='Vague but interesting!')

    author1 = create_dummy_person(abstract, 'John', 'Doe', '*****@*****.**', 'ACME', UserTitle.mr, True,
                                  AuthorType.primary)
    author2 = create_dummy_person(abstract, 'Pocahontas', 'Silva', '*****@*****.**', 'ACME', UserTitle.prof,
                                  False, AuthorType.primary)
    coauthor1 = create_dummy_person(abstract, 'John', 'Smith', '*****@*****.**', 'ACME', UserTitle.dr, False,
                                    AuthorType.primary)

    abstract.person_links = [author1, author2, coauthor1]
    db.session.add(abstract)
    db.session.flush()
    return abstract
Пример #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
Пример #9
0
def compat_abstract(endpoint, confId, friendly_id, track_id=None, management=False):
    abstract = Abstract.find(event_id=confId, friendly_id=friendly_id).first_or_404()
    return redirect(url_for('abstracts.' + endpoint, abstract, management=management))
Пример #10
0
 def all_for_event(cls, event):
     return {a.friendly_id: a for a in Abstract.find(event_new=event)}
Пример #11
0
 def all_for_event(cls, event):
     return {a.friendly_id: a for a in Abstract.find(event_new=event)}
Пример #12
0
def create_mock_abstract(event):
    """Create a mock abstract that can be used in previews.

    Brace for geek references.
    """
    User = namedtuple('Author', ['first_name', 'last_name', 'title', 'full_name'])
    Track = namedtuple('Track', ['title'])
    Session = namedtuple('Session', ['title'])
    ContributionType = namedtuple('ContributionType', ['name'])
    Contribution = namedtuple('Contribution', ['title', 'track', 'session', 'type', 'locator'])
    Abstract = namedtuple('Abstract', ['friendly_id', 'title', 'event', 'submitter', 'contribution',
                                       'primary_authors', 'secondary_authors', 'locator', 'judgment_comment',
                                       'accepted_track', 'accepted_contrib_type', 'state', 'merged_into'])

    class _MockLocator(dict):
        def __init__(self, locator, **sublocators):
            super().__init__(locator)
            self._sublocators = sublocators

        def __getattr__(self, attr):
            try:
                return self._sublocators[attr]
            except KeyError:
                raise AttributeError

    englert = User(full_name='Fran\xe7ois Englert', first_name='Fran\xe7ois', last_name='Englert', title='Prof.')
    brout = User(full_name='Robert Brout', first_name='Robert', last_name='Brout', title='Prof.')
    guralnik = User(full_name='Gerald Guralnik', first_name='Gerald', last_name='Guralnik', title='Prof.')
    hagen = User(full_name='Carl Hagen', first_name='Carl', last_name='Hagen', title='Prof.')
    kibble = User(full_name='Tom Kibble', first_name='Tom', last_name='Kibble', title='Prof.')
    higgs = User(full_name='Peter Higgs', first_name='Peter', last_name='Higgs', title='Prof.')

    track = Track(title='Higgs Fields')
    session = Session(title='Higgs Fields Posters')
    contribution_type = ContributionType(name='Poster')
    contribution = Contribution(title='Broken Symmetry and the Mass of Gauge Vector Mesons',
                                track=track,
                                session=session,
                                type=contribution_type,
                                locator={'event_id': -314, 'contrib_id': 1234})

    target_abstract = Abstract(friendly_id=315,
                               title='Broken Symmetry',
                               accepted_track=track,
                               accepted_contrib_type=contribution_type,
                               event=event,
                               submitter=brout,
                               state=AbstractState.accepted,
                               contribution=contribution,
                               primary_authors=[englert, brout],
                               secondary_authors=[guralnik, hagen, kibble, higgs],
                               locator=_MockLocator({'event_id': -314, 'abstract_id': 1235},
                                                    token={'event_id': -314,
                                                           'uuid': '12345678-9abc-def0-1234-56789abcdef0'}),
                               judgment_comment='Vague but interesting!',
                               merged_into=None)

    abstract = Abstract(friendly_id=314,
                        title='Broken Symmetry and the Mass of Gauge Vector Mesons',
                        accepted_track=track,
                        accepted_contrib_type=contribution_type,
                        event=event,
                        submitter=brout,
                        state=AbstractState.accepted,
                        contribution=contribution,
                        primary_authors=[englert, brout],
                        secondary_authors=[guralnik, hagen, kibble, higgs],
                        locator=_MockLocator({'event_id': -314, 'abstract_id': 1234},
                                             token={'event_id': -314, 'uuid': '12345678-9abc-def0-1234-56789abcdef0'}),
                        judgment_comment='Vague but interesting!',
                        merged_into=target_abstract)

    return abstract
Пример #13
0
 def _create_abstract(event, title, **kwargs):
     abstract = Abstract(event=event, title=title, **kwargs)
     db.session.add(abstract)
     db.session.flush()
     return abstract
Пример #14
0
    def _migrate_abstract(self, old_abstract):
        submitter = self.user_from_legacy(old_abstract._submitter._user,
                                          system_user=True)
        submitted_dt = old_abstract._submissionDate
        modified_dt = (old_abstract._modificationDate if
                       (submitted_dt - old_abstract._modificationDate) >
                       timedelta(seconds=10) else None)
        description = getattr(old_abstract, '_fields', {}).get('content', '')
        description = convert_to_unicode(
            getattr(description, 'value',
                    description))  # str or AbstractFieldContent

        type_ = old_abstract._contribTypes[0]
        type_id = None
        try:
            type_id = self.event_ns.legacy_contribution_type_map[
                type_].id if type_ else None
        except KeyError:
            self.print_warning(
                'Abstract {} - invalid contrib type {}, setting to None'.
                format(old_abstract._id,
                       convert_to_unicode(getattr(type_, '_name',
                                                  str(type_)))))

        abstract = Abstract(friendly_id=int(old_abstract._id),
                            title=convert_to_unicode(old_abstract._title),
                            description=description,
                            submitter=submitter,
                            submitted_dt=submitted_dt,
                            submitted_contrib_type_id=type_id,
                            submission_comment=convert_to_unicode(
                                old_abstract._comments),
                            modified_dt=modified_dt)
        self.print_info('%[white!]Abstract %[cyan]{}%[reset]: {}'.format(
            abstract.friendly_id, abstract.title))
        self.event.abstracts.append(abstract)
        self.event_ns.abstract_map[old_abstract] = abstract

        accepted_type_id = None
        accepted_track_id = None

        old_contribution = getattr(old_abstract, '_contribution', None)
        if old_contribution:
            assert old_contribution.__class__.__name__ == 'AcceptedContribution'
            if old_abstract._currentStatus.__class__.__name__ == 'AbstractStatusAccepted':
                old_contrib_type = old_abstract._currentStatus._contribType
                try:
                    accepted_type_id = (
                        self.event_ns.
                        legacy_contribution_type_map[old_contrib_type].id
                        if old_contrib_type else None)
                except KeyError:
                    self.print_warning(
                        '%[yellow!]Contribution {} - invalid contrib type {}, setting to None'
                        .format(old_contribution.id,
                                convert_to_unicode(old_contrib_type._name)))

                old_accepted_track = old_abstract._currentStatus._track
                accepted_track_id = int(
                    old_accepted_track.id) if old_accepted_track else None

        if old_contribution and old_contribution.id is not None:
            self.event_ns.legacy_contribution_abstracts[
                old_contribution] = abstract

        try:
            accepted_track = (
                self.event_ns.track_map_by_id.get(accepted_track_id)
                if accepted_track_id is not None else None)
        except KeyError:
            self.print_error(
                '%[yellow!]Abstract #{} accepted in invalid track #{}'.format(
                    abstract.friendly_id, accepted_track_id))
            accepted_track = None

        # state
        old_state = old_abstract._currentStatus
        old_state_name = old_state.__class__.__name__
        self.event_ns.old_abstract_state_map[abstract] = old_state
        abstract.state = self.STATE_MAP[old_state_name]

        if abstract.state == AbstractState.accepted:
            abstract.accepted_contrib_type_id = accepted_type_id
            abstract.accepted_track = accepted_track

        if abstract.state in self.JUDGED_STATES:
            abstract.judge = self.user_from_legacy(old_state._responsible,
                                                   system_user=True)
            abstract.judgment_dt = as_utc(old_state._date)

        # files
        for old_attachment in getattr(old_abstract, '_attachments',
                                      {}).itervalues():
            storage_backend, storage_path, size, md5 = self._get_local_file_info(
                old_attachment)
            if storage_path is None:
                self.print_error(
                    '%[red!]File not found on disk; skipping it [{}]'.format(
                        convert_to_unicode(old_attachment.fileName)))
                continue
            content_type = mimetypes.guess_type(
                old_attachment.fileName)[0] or 'application/octet-stream'
            filename = secure_filename(
                convert_to_unicode(old_attachment.fileName), 'attachment')
            attachment = AbstractFile(filename=filename,
                                      content_type=content_type,
                                      size=size,
                                      md5=md5,
                                      storage_backend=storage_backend,
                                      storage_file_id=storage_path)
            abstract.files.append(attachment)

        # internal comments
        for old_comment in old_abstract._intComments:
            comment = AbstractComment(
                user=self.user_from_legacy(old_comment._responsible,
                                           system_user=True),
                text=convert_to_unicode(old_comment._content),
                created_dt=old_comment._creationDate,
                modified_dt=old_comment._modificationDate)
            abstract.comments.append(comment)

        # tracks
        reallocated = set(r._track for r in getattr(
            old_abstract, '_trackReallocations', {}).itervalues())
        for old_track in old_abstract._tracks.values():
            abstract.reviewed_for_tracks.add(
                self.event_ns.track_map.get(old_track))
            if old_track not in reallocated:
                abstract.submitted_for_tracks.add(
                    self.event_ns.track_map.get(old_track))

        # reviews/judgments
        self._migrate_abstract_reviews(abstract, old_abstract)
        # persons
        self._migrate_abstract_persons(abstract, old_abstract)
        # email log
        self._migrate_abstract_email_log(abstract, old_abstract)

        # contribution/abstract fields
        abstract.field_values = list(
            self._migrate_abstract_field_values(old_abstract))
        return abstract
Пример #15
0
    def _migrate_abstracts(self):
        old_by_id = {oa.friendly_id: oa for oa in self.event.old_abstracts}
        abstract_map = {}
        old_abstract_state_map = {}
        as_duplicate_reviews = set()
        for zodb_abstract in self.amgr._abstracts.itervalues():
            old_abstract = old_by_id[int(zodb_abstract._id)]
            submitter = self._user_from_legacy(zodb_abstract._submitter._user, janitor=True)
            submitted_dt = zodb_abstract._submissionDate
            modified_dt = (zodb_abstract._modificationDate
                           if (submitted_dt - zodb_abstract._modificationDate) > timedelta(seconds=10)
                           else None)
            try:
                accepted_track = (self.track_map_by_id[old_abstract.accepted_track_id]
                                  if old_abstract.accepted_track_id is not None
                                  else None)
            except KeyError:
                self.importer.print_error(cformat('%{yellow!}Abstract #{} accepted in invalid track #{}')
                                          .format(old_abstract.friendly_id, old_abstract.accepted_track_id),
                                          event_id=self.event.id)
                accepted_track = None
            abstract = Abstract(id=old_abstract.id,
                                friendly_id=old_abstract.friendly_id,
                                title=convert_to_unicode(zodb_abstract._title),
                                description=old_abstract.description,
                                submitter=submitter,
                                submitted_dt=submitted_dt,
                                submitted_contrib_type_id=old_abstract.type_id,
                                submission_comment=convert_to_unicode(zodb_abstract._comments),
                                modified_dt=modified_dt)
            self.importer.print_info(cformat('%{white!}Abstract:%{reset} {}').format(abstract.title))
            self.event.abstracts.append(abstract)
            abstract_map[zodb_abstract] = abstract

            # files
            for old_attachment in getattr(zodb_abstract, '_attachments', {}).itervalues():
                storage_backend, storage_path, size = self.importer._get_local_file_info(old_attachment)
                if storage_path is None:
                    self.importer.print_error(cformat('%{red!}File not found on disk; skipping it [{}]')
                                              .format(convert_to_unicode(old_attachment.fileName)),
                                              event_id=self.event.id)
                    continue
                content_type = mimetypes.guess_type(old_attachment.fileName)[0] or 'application/octet-stream'
                filename = secure_filename(convert_to_unicode(old_attachment.fileName), 'attachment')
                attachment = AbstractFile(filename=filename, content_type=content_type, size=size,
                                          storage_backend=storage_backend, storage_file_id=storage_path)
                abstract.files.append(attachment)

            # internal comments
            for old_comment in zodb_abstract._intComments:
                comment = AbstractComment(user=self._user_from_legacy(old_comment._responsible),
                                          text=convert_to_unicode(old_comment._content),
                                          created_dt=old_comment._creationDate,
                                          modified_dt=old_comment._modificationDate)
                abstract.comments.append(comment)

            # state
            old_state = zodb_abstract._currentStatus
            old_state_name = old_state.__class__.__name__
            old_abstract_state_map[abstract] = old_state
            abstract.state = self.STATE_MAP[old_state_name]
            if abstract.state == AbstractState.accepted:
                abstract.accepted_contrib_type_id = old_abstract.accepted_type_id
                abstract.accepted_track = accepted_track

            if abstract.state in self.JUDGED_STATES:
                abstract.judge = self._user_from_legacy(old_state._responsible, janitor=True)
                abstract.judgment_dt = as_utc(old_state._date)

            # tracks
            reallocated = set(r._track for r in getattr(zodb_abstract, '_trackReallocations', {}).itervalues())
            for old_track in zodb_abstract._tracks.values():
                abstract.reviewed_for_tracks.add(self.track_map[old_track])
                if old_track not in reallocated:
                    abstract.submitted_for_tracks.add(self.track_map[old_track])

            # judgments (reviews)
            self._migrate_abstract_reviews(abstract, zodb_abstract, old_abstract, as_duplicate_reviews)
            # persons
            self._migrate_abstract_persons(abstract, zodb_abstract)
            # email log
            self._migrate_abstract_email_log(abstract, zodb_abstract)

        # merges/duplicates
        for abstract in self.event.abstracts:
            old_state = old_abstract_state_map[abstract]
            if abstract.state == AbstractState.merged:
                abstract.merged_into = abstract_map[old_state._target]
            elif abstract.state == AbstractState.duplicate:
                abstract.duplicate_of = abstract_map[old_state._original]

        # mark-as-duplicate judgments
        for review, old_abstract in as_duplicate_reviews:
            try:
                review.proposed_related_abstract = abstract_map[old_abstract]
            except KeyError:
                self.importer.print_error(cformat('%{yellow!}Abstract #{} marked as duplicate of invalid abstract #{}')
                                          .format(review.abstract.friendly_id, old_abstract._id),
                                          event_id=self.event.id)
                # delete the review; it would violate our CHECKs
                review.abstract = None
                # not needed but avoids some warnings about the object not in the session
                review.track = None
                review.user = None
Пример #16
0
 def as_new(self):
     try:
         return self.all_for_event(self.event)[int(self._id)]
     except KeyError:
         # then the abstract is new and has to be fetched from the DB
         return Abstract.find_one(event_new=self.event, friendly_id=self._id)
Пример #17
0
 def _new_abstract(self, event):
     abstract = Abstract(event_new=event)
     db.session.flush()
     return abstract
Пример #18
0
    def _migrate_abstracts(self):
        old_by_id = {oa.friendly_id: oa for oa in self.event.old_abstracts}
        abstract_map = {}
        old_abstract_state_map = {}
        as_duplicate_reviews = set()
        for zodb_abstract in self.amgr._abstracts.itervalues():
            old_abstract = old_by_id[int(zodb_abstract._id)]
            submitter = self._user_from_legacy(zodb_abstract._submitter._user,
                                               janitor=True)
            submitted_dt = zodb_abstract._submissionDate
            modified_dt = (zodb_abstract._modificationDate if
                           (submitted_dt - zodb_abstract._modificationDate) >
                           timedelta(seconds=10) else None)
            try:
                accepted_track = (
                    self.track_map_by_id[old_abstract.accepted_track_id]
                    if old_abstract.accepted_track_id is not None else None)
            except KeyError:
                self.importer.print_error(cformat(
                    '%{yellow!}Abstract #{} accepted in invalid track #{}'
                ).format(old_abstract.friendly_id,
                         old_abstract.accepted_track_id),
                                          event_id=self.event.id)
                accepted_track = None
            abstract = Abstract(id=old_abstract.id,
                                friendly_id=old_abstract.friendly_id,
                                title=convert_to_unicode(zodb_abstract._title),
                                description=old_abstract.description,
                                submitter=submitter,
                                submitted_dt=submitted_dt,
                                submitted_contrib_type_id=old_abstract.type_id,
                                submission_comment=convert_to_unicode(
                                    zodb_abstract._comments),
                                modified_dt=modified_dt)
            self.importer.print_info(
                cformat('%{white!}Abstract:%{reset} {}').format(
                    abstract.title))
            self.event.abstracts.append(abstract)
            abstract_map[zodb_abstract] = abstract

            # files
            for old_attachment in getattr(zodb_abstract, '_attachments',
                                          {}).itervalues():
                storage_backend, storage_path, size = self.importer._get_local_file_info(
                    old_attachment)
                if storage_path is None:
                    self.importer.print_error(cformat(
                        '%{red!}File not found on disk; skipping it [{}]'
                    ).format(convert_to_unicode(old_attachment.fileName)),
                                              event_id=self.event.id)
                    continue
                content_type = mimetypes.guess_type(
                    old_attachment.fileName)[0] or 'application/octet-stream'
                filename = secure_filename(
                    convert_to_unicode(old_attachment.fileName), 'attachment')
                attachment = AbstractFile(filename=filename,
                                          content_type=content_type,
                                          size=size,
                                          storage_backend=storage_backend,
                                          storage_file_id=storage_path)
                abstract.files.append(attachment)

            # internal comments
            for old_comment in zodb_abstract._intComments:
                comment = AbstractComment(
                    user=self._user_from_legacy(old_comment._responsible),
                    text=convert_to_unicode(old_comment._content),
                    created_dt=old_comment._creationDate,
                    modified_dt=old_comment._modificationDate)
                abstract.comments.append(comment)

            # state
            old_state = zodb_abstract._currentStatus
            old_state_name = old_state.__class__.__name__
            old_abstract_state_map[abstract] = old_state
            abstract.state = self.STATE_MAP[old_state_name]
            if abstract.state == AbstractState.accepted:
                abstract.accepted_contrib_type_id = old_abstract.accepted_type_id
                abstract.accepted_track = accepted_track

            if abstract.state in self.JUDGED_STATES:
                abstract.judge = self._user_from_legacy(old_state._responsible,
                                                        janitor=True)
                abstract.judgment_dt = as_utc(old_state._date)

            # tracks
            reallocated = set(r._track for r in getattr(
                zodb_abstract, '_trackReallocations', {}).itervalues())
            for old_track in zodb_abstract._tracks.values():
                abstract.reviewed_for_tracks.add(self.track_map[old_track])
                if old_track not in reallocated:
                    abstract.submitted_for_tracks.add(
                        self.track_map[old_track])

            # judgments (reviews)
            self._migrate_abstract_reviews(abstract, zodb_abstract,
                                           old_abstract, as_duplicate_reviews)
            # persons
            self._migrate_abstract_persons(abstract, zodb_abstract)
            # email log
            self._migrate_abstract_email_log(abstract, zodb_abstract)

        # merges/duplicates
        for abstract in self.event.abstracts:
            old_state = old_abstract_state_map[abstract]
            if abstract.state == AbstractState.merged:
                abstract.merged_into = abstract_map[old_state._target]
            elif abstract.state == AbstractState.duplicate:
                abstract.duplicate_of = abstract_map[old_state._original]

        # mark-as-duplicate judgments
        for review, old_abstract in as_duplicate_reviews:
            try:
                review.proposed_related_abstract = abstract_map[old_abstract]
            except KeyError:
                self.importer.print_error(cformat(
                    '%{yellow!}Abstract #{} marked as duplicate of invalid abstract #{}'
                ).format(review.abstract.friendly_id, old_abstract._id),
                                          event_id=self.event.id)
                # delete the review; it would violate our CHECKs
                review.abstract = None
                # not needed but avoids some warnings about the object not in the session
                review.track = None
                review.user = None