def test_add_remove_corner_cases(app, db, communities, disable_request_email):
    """Test corner cases for community adding and removal."""
    (comm1, comm2, comm3) = communities
    communities_key = app.config["COMMUNITIES_RECORD_KEY"]
    # Create a record and create an inclusion request,
    # meanwhile adding a record manually outside the workflow
    rec1 = Record.create({'title': 'Foobar'})
    InclusionRequest.create(community=comm1, record=rec1)
    rec1[communities_key] = [
        'comm1',
    ]  # Add community manually
    assert InclusionRequest.query.count() == 1

    # Accepting record which was added manually outside the normal workflow
    comm1.accept_record(rec1)  # Should still work
    assert rec1[communities_key] == [
        'comm1',
    ]
    assert InclusionRequest.query.count() == 0
    assert comm1.oaiset.has_record(rec1)

    # Removing record which was removed manually outside the normal workflow
    rec1[communities_key] = []  # Remove community manually
    comm1.remove_record(rec1)  # Should still work
    assert communities_key in rec1
    assert len(rec1[communities_key]) == 0
    assert not comm1.oaiset.has_record(rec1)
def test_email_notification(app, db, communities, user):
    """Test mail notification sending for community request."""
    # Mock the send method of the Flask-Mail extension
    with app.extensions['mail'].record_messages() as outbox:
        (comm1, comm2, comm3) = communities
        # Create a record and accept it into the community by creating an
        # InclusionRequest and then calling the accept action
        rec1 = Record.create({'title': 'Foobar', 'description': 'Baz bar.'})
        InclusionRequest.create(community=comm1, record=rec1, user=user)
        assert len(outbox) == 1
def test_email_notification(app, db, communities, user):
    """Test mail notification sending for community request."""
    # Mock the send method of the Flask-Mail extension
    with app.extensions['mail'].record_messages() as outbox:
        (comm1, comm2, comm3) = communities
        # Create a record and accept it into the community by creating an
        # InclusionRequest and then calling the accept action
        rec1 = Record.create({
            'title': 'Foobar', 'description': 'Baz bar.'})
        InclusionRequest.create(community=comm1, record=rec1, user=user)
        assert len(outbox) == 1
Example #4
0
    def _remove_obsolete_irs(comms, record):
        """Remove obsolete inclusion requests.

        :param comms: Community IDs as declared in deposit. Used to remove
                      obsolete inclusion requests.
        :type comms: list of str
        :param record: Record corresponding to this deposit.
        :type record: `invenio_records.api.Record`
        """
        InclusionRequest.get_by_record(record.id).filter(
            InclusionRequest.id_community.notin_(comms)).delete(
                synchronize_session='fetch')
Example #5
0
    def _remove_obsolete_irs(comms, record):
        """Remove obsolete inclusion requests.

        :param comms: Community IDs as declared in deposit. Used to remove
                      obsolete inclusion requests.
        :type comms: list of str
        :param record: Record corresponding to this deposit.
        :type record: `invenio_records.api.Record`
        """
        InclusionRequest.get_by_record(record.id).filter(
            InclusionRequest.id_community.notin_(comms)).delete(
                synchronize_session='fetch')
Example #6
0
def migrate_record(record_uuid, logger=None):
    """Migrate a record."""
    try:
        # Migrate record
        record = Record.get_record(record_uuid)
        if '$schema' in record:
            if logger:
                logger.info("Record already migrated.")
            return
        record = transform_record(record)
        provisional_communities = record.pop('provisional_communities', None)
        record.commit()
        # Create provisional communities.
        if provisional_communities:
            for c_id in provisional_communities:
                try:
                    c = Community.get(c_id)
                    if c:
                        InclusionRequest.create(c, record, notify=False)
                    else:
                        if logger:
                            logger.warning(
                                "Community {0} does not exists "
                                "(record {1}).".format(
                                    c_id, str(record.id)))
                except InclusionRequestExistsError:
                    if logger:
                        logger.warning("Inclusion request exists.")
        # Register DOI
        doi = record.get('doi')
        if doi:
            is_internal = doi.startswith('10.5281')
            PersistentIdentifier.create(
                pid_type='doi',
                pid_value=doi,
                pid_provider='datacite' if is_internal else None,
                object_type='rec',
                object_uuid=record_uuid,
                status=(
                    PIDStatus.REGISTERED if is_internal
                    else PIDStatus.RESERVED),
            )
        db.session.commit()
    except NoResultFound:
        if logger:
            logger.info("Deleted record - no migration required.")
    except Exception:
        db.session.rollback()
        pid = PersistentIdentifier.get_by_object('recid', 'rec', record_uuid)
        pid.status = PIDStatus.RESERVED
        db.session.commit()
        raise
Example #7
0
    def _create_inclusion_requests(comms, record):
        """Create inclusion requests for communities.

        :param comms: Community IDs for which the inclusion requests might
                      should be created (if they don't exist already).
        :type comms: list of str
        :param record: Record corresponding to this deposit.
        :type record: `invenio_records.api.Record`
        """
        for comm_id in comms:
            comm = Community.get(comm_id)
            if not InclusionRequest.get(comm_id, record.id):
                InclusionRequest.create(comm, record)
Example #8
0
    def _create_inclusion_requests(comms, record):
        """Create inclusion requests for communities.

        :param comms: Community IDs for which the inclusion requests might
                      should be created (if they don't exist already).
        :type comms: list of str
        :param record: Record corresponding to this deposit.
        :type record: `invenio_records.api.Record`
        """
        for comm_id in comms:
            comm = Community.get(comm_id)
            if not InclusionRequest.get(comm_id, record.id):
                InclusionRequest.create(comm, record)
def test_community_delete_task(app, db, communities):
    """Test the community deletion task."""
    (comm1, comm2, comm3) = communities
    communities_key = app.config["COMMUNITIES_RECORD_KEY"]
    rec1 = Record.create({'title': 'Foobar'})
    InclusionRequest.create(community=comm1, record=rec1, notify=False)

    assert InclusionRequest.get(comm1.id, rec1.id)

    comm1.accept_record(rec1)
    assert 'comm1' in rec1[communities_key]

    comm1.delete()
    assert comm1.is_deleted
Example #10
0
def migrate_record(record_uuid, logger=None):
    """Migrate a record."""
    try:
        # Migrate record
        record = Record.get_record(record_uuid)
        if '$schema' in record:
            if logger:
                logger.info("Record already migrated.")
            return
        record = transform_record(record)
        provisional_communities = record.pop('provisional_communities', None)
        record.commit()
        # Create provisional communities.
        if provisional_communities:
            for c_id in provisional_communities:
                try:
                    c = Community.get(c_id)
                    if c:
                        InclusionRequest.create(c, record, notify=False)
                    else:
                        if logger:
                            logger.warning("Community {0} does not exists "
                                           "(record {1}).".format(
                                               c_id, str(record.id)))
                except InclusionRequestExistsError:
                    if logger:
                        logger.warning("Inclusion request exists.")
        # Register DOI
        doi = record.get('doi')
        if doi:
            is_internal = doi.startswith('10.5281')
            PersistentIdentifier.create(
                pid_type='doi',
                pid_value=doi,
                pid_provider='datacite' if is_internal else None,
                object_type='rec',
                object_uuid=record_uuid,
                status=(PIDStatus.REGISTERED
                        if is_internal else PIDStatus.RESERVED),
            )
        db.session.commit()
    except NoResultFound:
        if logger:
            logger.info("Deleted record - no migration required.")
    except Exception:
        db.session.rollback()
        pid = PersistentIdentifier.get_by_object('recid', 'rec', record_uuid)
        pid.status = PIDStatus.RESERVED
        db.session.commit()
        raise
Example #11
0
def test_community_delete_task(app, db, communities):
    """Test the community deletion task."""
    (comm1, comm2, comm3) = communities
    communities_key = app.config["COMMUNITIES_RECORD_KEY"]
    rec1 = Record.create({'title': 'Foobar'})
    InclusionRequest.create(community=comm1, record=rec1, notify=False)

    assert InclusionRequest.get(comm1.id, rec1.id)

    comm1.accept_record(rec1)
    assert 'comm1' in rec1[communities_key]

    comm1.delete()
    assert comm1.is_deleted
Example #12
0
    def _create_inclusion_requests(comms, record):
        """Create inclusion requests for communities.

        :param comms: Community IDs for which the inclusion requests might
                      should be created (if they don't exist already).
        :type comms: list of str
        :param record: Record corresponding to this deposit.
        :type record: `invenio_records.api.Record`
        """
        for comm_id in comms:
            comm_api = ZenodoCommunity(comm_id)
            # Check if InclusionRequest exists for any version already
            pending_irs = comm_api.get_comm_irs(record)
            if pending_irs.count() == 0 and not comm_api.has_record(record):
                comm = Community.get(comm_id)
                InclusionRequest.create(comm, record)
Example #13
0
File: api.py Project: xlsdnx/zenodo
    def _create_inclusion_requests(comms, record):
        """Create inclusion requests for communities.

        :param comms: Community IDs for which the inclusion requests might
                      should be created (if they don't exist already).
        :type comms: list of str
        :param record: Record corresponding to this deposit.
        :type record: `invenio_records.api.Record`
        """
        for comm_id in comms:
            comm_api = ZenodoCommunity(comm_id)
            # Check if InclusionRequest exists for any version already
            pending_irs = comm_api.get_comm_irs(record)
            if pending_irs.count() == 0 and not comm_api.has_record(record):
                comm = Community.get(comm_id)
                InclusionRequest.create(comm, record)
Example #14
0
    def _prepare_edit(self, record):
        """Prepare deposit for editing.

        Extend the deposit's communities metadata by the pending inclusion
        requests.
        """
        data = super(ZenodoDeposit, self)._prepare_edit(record)
        data.setdefault('communities', []).extend(
            [c.id_community for c in
             InclusionRequest.get_by_record(record.id)])
        data['communities'] = sorted(list(set(data['communities'])))

        # Remove the OpenAIRE subtype if the record is no longer pending,
        # nor in the relevant community
        oa_type = data['resource_type'].get('openaire_subtype')
        if oa_type and not is_valid_openaire_type(data['resource_type'],
                data['communities']):
            del data['resource_type']['openaire_subtype']
        if not data['communities']:
            del data['communities']

        # If non-Zenodo DOI unlock the bucket to allow file-editing
        if not is_doi_locally_managed(data['doi']):
            self.files.bucket.locked = False
        return data
Example #15
0
def test_email_formatting(app, db, communities, user):
    """Test formatting of the email message with the default template."""
    with app.extensions['mail'].record_messages() as outbox:
        (comm1, comm2, comm3) = communities
        rec1 = Record.create({
            'title': 'Foobar and Bazbar',
            'description': 'On Foobar, Bazbar and <b>more</b>.'
        })

        # Request
        InclusionRequest.create(community=comm1, record=rec1, user=user)

        # Check emails being sent
        assert len(outbox) == 1
        sent_msg = outbox[0]
        assert sent_msg.recipients == [user.email]
        assert comm1.title in sent_msg.body
def test_model_init(app):
    """Test basic model initialization and actions."""
    with app.app_context():
        # Init the User and the Community
        user1 = create_test_user()
        comm1 = Community(id='comm1', id_user=user1.id)
        db.session.add(comm1)
        db.session.commit()
        communities_key = app.config["COMMUNITIES_RECORD_KEY"]
        # Create a record and accept it into the community by creating an
        # InclusionRequest and then calling the accept action
        rec1 = Record.create({'title': 'Foobar'})
        InclusionRequest.create(community=comm1, record=rec1)
        assert InclusionRequest.query.count() == 1
        comm1.accept_record(rec1)
        assert 'comm1' in rec1[communities_key]
        assert InclusionRequest.query.count() == 0

        # Likewise, reject a record from the community
        rec2 = Record.create({'title': 'Bazbar'})
        InclusionRequest.create(community=comm1, record=rec2)
        assert InclusionRequest.query.count() == 1
        comm1.reject_record(rec2)
        assert communities_key not in rec2  # dict key should not be created
        assert InclusionRequest.query.count() == 0

        # Add record to another community
        comm2 = Community(id='comm2', id_user=user1.id)
        db.session.add(comm2)
        db.session.commit()
        InclusionRequest.create(community=comm2, record=rec1)
        comm2.accept_record(rec1)
        assert communities_key in rec1
        assert len(rec1[communities_key]) == 2
        assert comm1.id in rec1[communities_key]
        assert comm2.id in rec1[communities_key]

        # Accept/reject a record to/from a community without inclusion request
        rec3 = Record.create({'title': 'Spam'})
        pytest.raises(InclusionRequestMissingError, comm1.accept_record, rec3)
        pytest.raises(InclusionRequestMissingError, comm1.reject_record, rec3)

        # Create two inclusion requests
        comm3 = Community(id='comm3', id_user=user1.id)
        db.session.add(comm3)
        db.session.commit()
        InclusionRequest.create(community=comm3, record=rec1)
        pytest.raises(InclusionRequestExistsError, InclusionRequest.create,
                      community=comm3, record=rec1)

        # Try to accept a record to a community twice (should raise)
        # (comm1 is already in rec1)
        pytest.raises(InclusionRequestObsoleteError, InclusionRequest.create,
                      community=comm1, record=rec1)
def test_model_init(app, db, communities):
    """Test basic model initialization and actions."""
    (comm1, comm2, comm3) = communities
    communities_key = app.config["COMMUNITIES_RECORD_KEY"]
    # Create a record and accept it into the community by creating an
    # InclusionRequest and then calling the accept action
    rec1 = Record.create({'title': 'Foobar'})
    InclusionRequest.create(community=comm1, record=rec1)
    assert InclusionRequest.query.count() == 1
    comm1.accept_record(rec1)
    assert 'comm1' in rec1[communities_key]
    assert InclusionRequest.query.count() == 0

    # Likewise, reject a record from the community
    rec2 = Record.create({'title': 'Bazbar'})
    InclusionRequest.create(community=comm1, record=rec2)
    assert InclusionRequest.query.count() == 1
    comm1.reject_record(rec2)
    assert communities_key not in rec2  # dict key should not be created
    assert InclusionRequest.query.count() == 0

    # Add record to another community
    InclusionRequest.create(community=comm2, record=rec1)
    comm2.accept_record(rec1)
    assert communities_key in rec1
    assert len(rec1[communities_key]) == 2
    assert comm1.id in rec1[communities_key]
    assert comm2.id in rec1[communities_key]

    # Accept/reject a record to/from a community without inclusion request
    rec3 = Record.create({'title': 'Spam'})
    pytest.raises(InclusionRequestMissingError, comm1.accept_record, rec3)
    pytest.raises(InclusionRequestMissingError, comm1.reject_record, rec3)

    # Create two inclusion requests
    InclusionRequest.create(community=comm3, record=rec1)
    db.session.commit()
    db.session.flush()
    pytest.raises(InclusionRequestExistsError,
                  InclusionRequest.create,
                  community=comm3,
                  record=rec1)

    # Try to accept a record to a community twice (should raise)
    # (comm1 is already in rec1)
    pytest.raises(InclusionRequestObsoleteError,
                  InclusionRequest.create,
                  community=comm1,
                  record=rec1)
Example #18
0
    def _prepare_edit(self, record):
        """Prepare deposit for editing.

        Extend the deposit's communities metadata by the pending inclusion
        requests.
        """
        data = super(ZenodoDeposit, self)._prepare_edit(record)
        data.setdefault('communities', []).extend(
            [c.id_community for c in
             InclusionRequest.get_by_record(record.id)])
        data['communities'] = sorted(list(set(data['communities'])))
        if not data['communities']:
            del data['communities']
        return data
Example #19
0
    def _prepare_edit(self, record):
        """Prepare deposit for editing.

        Extend the deposit's communities metadata by the pending inclusion
        requests.
        """
        data = super(ZenodoDeposit, self)._prepare_edit(record)
        data.setdefault('communities', []).extend([
            c.id_community for c in InclusionRequest.get_by_record(record.id)
        ])
        data['communities'] = sorted(list(set(data['communities'])))
        if not data['communities']:
            del data['communities']
        return data
def test_add_remove_corner_cases(app, db, communities, disable_request_email):
    """Test corner cases for community adding and removal."""
    (comm1, comm2, comm3) = communities
    communities_key = app.config["COMMUNITIES_RECORD_KEY"]
    # Create a record and create an inclusion request,
    # meanwhile adding a record manually outside the workflow
    rec1 = Record.create({'title': 'Foobar'})
    InclusionRequest.create(community=comm1, record=rec1)
    rec1[communities_key] = ['comm1', ]  # Add community manually
    assert InclusionRequest.query.count() == 1

    # Accepting record which was added manually outside the normal workflow
    comm1.accept_record(rec1)  # Should still work
    assert rec1[communities_key] == ['comm1', ]
    assert InclusionRequest.query.count() == 0
    assert comm1.oaiset.has_record(rec1)

    # Removing record which was removed manually outside the normal workflow
    rec1[communities_key] = []  # Remove community manually
    comm1.remove_record(rec1)  # Should still work
    assert communities_key in rec1
    assert len(rec1[communities_key]) == 0
    assert not comm1.oaiset.has_record(rec1)
Example #21
0
File: api.py Project: zenodo/zenodo
    def _prepare_edit(self, record):
        """Prepare deposit for editing.

        Extend the deposit's communities metadata by the pending inclusion
        requests.
        """
        data = super(ZenodoDeposit, self)._prepare_edit(record)
        data.setdefault('communities', []).extend(
            [c.id_community for c in
             InclusionRequest.get_by_record(record.id)])
        data['communities'] = sorted(list(set(data['communities'])))

        # Remove the OpenAIRE subtype if the record is no longer pending,
        # nor in the relevant community
        oa_type = data['resource_type'].get('openaire_subtype')
        if oa_type and not is_valid_openaire_type(data['resource_type'],
                data['communities']):
            del data['resource_type']['openaire_subtype']
        if not data['communities']:
            del data['communities']
        return data
Example #22
0
def suggest():
    """Index page with uploader and list of existing depositions.

    :param community_id: ID of the community to curate.
    """
    community = None
    record = None
    url = request.referrer

    if "url" in request.values and request.values["url"]:
        url = request.values["url"]
    if not "community" in request.values:
        flash(u"Error, no {} given".format(
                        current_app.config["COMMUNITIES_NAME"]),
              "danger")
        return redirect(url)
    community_id = request.values["community"]
    community = Community.get(community_id)
    if not community:
        flash(u"Error, unknown {} {}".format(
                    current_app.config["COMMUNITIES_NAME"], community_id),
              "danger")
        return redirect(url)
    if not _get_permission("communities-read", community).can() \
            and not DynamicPermission(ActionNeed('admin-access')).can():
        flash(u"Error, you don't have permissions on the {} {}".format(
            current_app.config["COMMUNITIES_NAME"],
            community_id), "danger")
        return redirect(url)
    if not "recpid" in request.values:
        flash(u"Error, no record given", "danger")
        return redirect(url)
    recid = request.values["recpid"]
    resolver = Resolver(
            pid_type='recid', object_type='rec', getter=Record.get_record)
    try:
        pid, record = resolver.resolve(recid)
    except Exception:
        flash(u"Error, unkown record {}".format(recid), "danger")
        return redirect(url)
    # if the user has the curate permission on this community,
    # we automatically add the record
    if _get_permission("communities-curate", community).can():
        try:
            community.add_record(record)
        except:  # the record is already in the community
            flash(u"The record already exists in the {} {}.".format(
                current_app.config["COMMUNITIES_NAME"],
                community.title), "warning")
        else:
            record.commit()
            flash(u"The record has been added to the {} {}.".format(
                current_app.config["COMMUNITIES_NAME"],
                community.title))
    # otherwise we only suggest it and it will appear in the curate list
    else:
        try:
            InclusionRequest.create(community=community,
                                    record=record,
                                    user=current_user)
        except InclusionRequestObsoleteError:  # the record is already in the community
            flash(u"The record already exists in the {} {}.".format(
            current_app.config["COMMUNITIES_NAME"],
            community.title), "warning")
        except InclusionRequestExistsError:
            flash(u"The record has already been suggested "
                  u"to the {} {}.".format(
                        current_app.config["COMMUNITIES_NAME"],
                        community.title), "warning")
        else:
            flash(u"The record has been suggested "
                  u"to the {} {}.".format(
                                current_app.config["COMMUNITIES_NAME"],
                                community.title))
    db.session.commit()
    RecordIndexer().index_by_id(record.id)
    return redirect(url)