Example #1
0
def create_sequence_relation(previous_rec, next_rec, relation_type):
    """Create sequence relations."""
    rr = RecordRelationsSequence()
    click.echo("Creating relations: {0} - {1}".format(previous_rec["pid"],
                                                      next_rec["pid"]))
    rel = Relation(relation_type)
    if not rel.relation_exists(previous_rec.pid, next_rec.pid):
        rr.add(
            previous_rec=previous_rec,
            next_rec=next_rec,
            relation_type=relation_type,
        )
Example #2
0
        def delete(payload):
            try:
                relation_type = payload.pop("relation_type")
            except KeyError as key:
                return abort(400, "The `{}` is a required field".format(key))

            rt = Relation.get_relation_by_name(relation_type)

            if rt in current_app.config["PARENT_CHILD_RELATION_TYPES"]:
                modified, first, second = self._delete_parent_child_relation(
                    record, rt, payload)
            elif rt in current_app.config["SIBLINGS_RELATION_TYPES"]:
                modified, first, second = self._delete_sibling_relation(
                    record, rt, payload)
            else:
                raise RecordRelationsError("Invalid relation type `{}`".format(
                    rt.name))

            db.session.commit()

            records_to_index.append(first)
            records_to_index.append(second)

            # if the record is the modified, return the modified version
            if (modified.pid == record.pid
                    and modified._pid_type == record._pid_type):
                return modified
            return record
Example #3
0
def create_sequence_relation(previous_rec, next_rec, relation_type):
    """Create sequence relations."""
    relations_logger = logging.getLogger("relations_logger")
    rr = RecordRelationsSequence()
    click.echo("Creating relations: {0} - {1}".format(previous_rec["pid"],
                                                      next_rec["pid"]))
    rel = Relation(relation_type)
    if not rel.relation_exists(previous_rec.pid, next_rec.pid):
        rr.add(
            previous_rec=previous_rec,
            next_rec=next_rec,
            relation_type=relation_type,
        )
        relations_logger.info("Created: {0} - {1}".format(
            previous_rec["pid"], next_rec["pid"]),
                              extra=dict(legacy_id=None,
                                         status="SUCCESS",
                                         new_pid=previous_rec["pid"]))
Example #4
0
def find_related_record(relation):
    """Find related document record or first volume of series."""
    document_class = current_app_ils.document_record_cls
    series_class = current_app_ils.series_record_cls
    document_legacy_pid_type = \
        current_app.config["CDS_ILS_RECORD_LEGACY_PID_TYPE"]
    try:
        related_sibling = get_record_by_legacy_recid(
            document_class,
            document_legacy_pid_type,
            relation["related_recid"],
        )
        return related_sibling
    except PIDDoesNotExistError as e:
        # If there is no document it means it can be related to a
        # multipart. If this is the case we relate it to the first
        # document of the multipart
        series_legacy_pid = current_app.config[
            "CDS_ILS_SERIES_LEGACY_PID_TYPE"]
        try:
            # Search for the series with related legacy_recid from
            # the document
            related_series = get_record_by_legacy_recid(
                series_class,
                series_legacy_pid,
                relation["related_recid"],
            )
            multipart_relation = Relation.get_relation_by_name(
                "multipart_monograph")
            pcr = ParentChildRelation(multipart_relation)
            volumes = pcr.get_children_of(related_series.pid)

            if len(volumes) > 0:
                # Selects the first volume as the one to be related
                # with the document
                related_sibling = document_class.get_record_by_pid(
                    volumes[0].pid_value)
                return related_sibling
            else:
                click.secho(
                    "No document related volume found with legacy_recid: {}".
                    format(relation["related_recid"]),
                    fg="red",
                )
                raise RelationMigrationError(
                    f"No related volume record found "
                    f"with legacy_recid {relation['related_recid']}")
        except PIDDoesNotExistError as e:
            click.secho(
                "No record found with legacy_recid: {}".format(
                    relation["related_recid"]),
                fg="red",
            )
            raise RelationMigrationError(
                f"No related record found "
                f"with legacy_recid {relation['related_recid']}")
Example #5
0
def migrate_document_siblings_relation(raise_exceptions=False):
    """Create siblings relations."""
    document_class = current_app_ils.document_record_cls

    search = search_documents_with_siblings_relations()
    results = search.params(scroll='4h').scan()

    for document in results:

        current_document_record = document_class.get_record_by_pid(
            document.pid)
        relations = current_document_record["_migration"]["related"]
        for relation in relations:
            try:
                # clean the found sibling
                related_sibling = None
                extra_metadata = {}
                related_sibling = find_related_record(relation)
                if not related_sibling:
                    continue

                # validate relation type
                relation_type = Relation.get_relation_by_name(
                    relation["relation_type"])

                if relation_type.name == EDITION_RELATION.name:
                    validate_edition_field(current_document_record,
                                           related_sibling, relation)

                if relation_type.name == OTHER_RELATION.name:
                    extra_metadata.update(
                        {"note": relation["relation_description"]})
                # create relation
                if related_sibling and related_sibling["pid"] != document.pid:
                    create_sibling_relation(
                        current_document_record,
                        related_sibling,
                        relation_type,
                        **extra_metadata,
                    )
                    db.session.commit()
            except Exception as exc:
                click.secho(str(exc), fg="red")
                handler = relation_exception_handlers.get(exc.__class__)
                if handler:
                    handler(
                        exc,
                        new_pid=current_document_record["pid"],
                        legacy_id=current_document_record.get("legacy_recid"))
                else:
                    if raise_exceptions:
                        raise exc
        current_document_record["_migration"]["has_related"] = False
        current_document_record.commit()
        db.session.commit()
Example #6
0
    def delete_record(self):
        """Deletes the eitems of the record."""
        document_indexer = current_app_ils.document_indexer
        series_class = current_app_ils.series_record_cls
        document_class = current_app_ils.document_record_cls

        self._validate_provider()

        exact_match, partial_matches = self._match_document()
        partial_matches = self.find_partial_matches(partial_matches,
                                                    exact_match)

        if exact_match:
            matched_document = document_class.get_record_by_pid(exact_match)

            eitem = self.delete_eitem(matched_document)
            db.session.commit()
            current_search.flush_and_refresh(index="*")
            document_has_only_serial_relations = \
                len(matched_document.relations.keys()) \
                and 'serial' in matched_document.relations.keys()

            if not matched_document.has_references() \
                    or document_has_only_serial_relations:

                # remove serial relations
                rr = RecordRelationsParentChild()
                serial_relations = matched_document.relations.get('serial', [])
                relation_type = Relation.get_relation_by_name("serial")
                for relation in serial_relations:
                    serial = series_class.get_record_by_pid(
                        relation["pid_value"])
                    rr.remove(serial, matched_document, relation_type)

            pid = matched_document.pid
            # will fail if any relations / references present
            matched_document.delete()
            # mark all PIDs as DELETED
            all_pids = PersistentIdentifier.query.filter(
                PersistentIdentifier.object_type == pid.object_type,
                PersistentIdentifier.object_uuid == pid.object_uuid,
            ).all()
            for rec_pid in all_pids:
                if not rec_pid.is_deleted():
                    rec_pid.delete()

            db.session.commit()
            document_indexer.delete(matched_document)
            return self.report(document=matched_document,
                               action="delete",
                               partial_matches=partial_matches,
                               eitem=eitem)

        return self.report(partial_matches=partial_matches)
Example #7
0
def migrate_document_siblings_relation():
    """Create siblings relations."""
    document_class = current_app_ils.document_record_cls
    series_class = current_app_ils.series_record_cls

    search = search_documents_with_siblings_relations()
    results = search.scan()

    extra_metadata = {}
    for document in results:
        relations = document["_migration"]["related"]

        for relation in relations:
            related_sibling = None
            try:
                related_sibling = get_record_by_legacy_recid(
                    document_class, relation["related_recid"])
            except PIDDoesNotExistError as e:
                pass

            # try to find sibling in series
            if related_sibling is None:
                try:
                    related_sibling = get_record_by_legacy_recid(
                        series_class, relation["related_recid"])
                except PIDDoesNotExistError as e:
                    continue

            # validate relation type
            relation_type = Relation.get_relation_by_name(
                relation["relation_type"])

            if relation_type == OTHER_RELATION.name:
                extra_metadata.update(
                    {"note": relation["relation_description"]})
            # create relation
            if related_sibling and related_sibling["pid"] != document.pid:
                current_document_record = document_class.get_record_by_pid(
                    document.pid)

                try:
                    create_sibling_relation(
                        current_document_record,
                        related_sibling,
                        relation_type,
                        **extra_metadata,
                    )
                    db.session.commit()
                except RecordRelationsError as e:
                    click.secho(e.description, fg="red")
                    continue
Example #8
0
 def import_serial_relation(self, series_record, document_record,
                            json_series):
     """Create serial relation type."""
     try:
         rr = RecordRelationsParentChild()
         serial_relation = Relation.get_relation_by_name("serial")
         volume = json_series.get("volume", None)
         rr.add(
             series_record,
             document_record,
             relation_type=serial_relation,
             volume=volume,
         )
     except RecordRelationsError as e:
         click.secho(str(e), fg="red")
Example #9
0
def migrate_series_relations():
    """Create relations for series."""
    series_class = current_app_ils.series_record_cls
    search = search_series_with_relations()
    results = search.scan()

    for series in results:
        relations = series["_migration"]["related"]

        for relation in relations:
            related_series = get_record_by_legacy_recid(
                series_class, relation["related_recid"])

            # validate relation type
            relation_type = Relation.get_relation_by_name(
                relation["relation_type"])

            # create relation
            current_series_record = series_class.get_record_by_pid(series.pid)
            try:
                if relation_type in SIBLINGS_RELATION_TYPES:
                    create_sibling_relation(
                        current_series_record,
                        related_series,
                        relation_type,
                        note=relation["relation_description"],
                    )

                elif relation_type in SEQUENCE_RELATION_TYPES:
                    if relation["sequence_order"] == "previous":
                        create_sequence_relation(
                            current_series_record,
                            related_series,
                            relation_type,
                        )
                    else:
                        create_sequence_relation(
                            related_series,
                            current_series_record,
                            relation_type,
                        )
                db.session.commit()
            except RecordRelationsError as e:
                click.secho(e.description, fg="red")
                continue
Example #10
0
        def create(payload):
            try:
                relation_type = payload.pop("relation_type")
            except KeyError as key:
                return abort(400, "The `{}` is a required field".format(key))

            rt = Relation.get_relation_by_name(relation_type)
            if rt in PARENT_CHILD_RELATION_TYPES:
                modified, first, second = self._create_parent_child_relation(
                    record, rt, payload
                )
            elif rt in SIBLINGS_RELATION_TYPES:
                modified, first, second = self._create_sibling_relation(
                    record, rt, payload
                )
            elif rt in SEQUENCE_RELATION_TYPES:
                first, second = self._create_sequence_relation(
                    record, rt, payload
                )
                modified = second
            else:
                raise RecordRelationsError(
                    "Invalid relation type `{}`".format(rt.name)
                )

            db.session.commit()

            records_to_index.append(first)
            records_to_index.append(second)

            def is_modified(x, r):
                return x.pid == r.pid and x._pid_type == r._pid_type

            # NOTE: modified can be a record or a list of records, if one
            # matches our record return the modified one.

            _modified = modified if isinstance(modified, list) else [modified]

            for mod_record in _modified:
                if is_modified(mod_record, record):
                    return mod_record
            return record
def test_max_one_multipart(testdata):
    doc = testdata["documents"][0]
    series1 = testdata["series"][0]
    rr = RecordRelationsParentChild()
    res = rr.add(
        series1,
        doc,
        Relation.get_relation_by_name("multipart_monograph"),
    )

    assert res

    series2 = testdata["series"][1]

    with pytest.raises(RecordRelationsError) as error:
        rr = RecordRelationsParentChild()
        res = rr.add(
            series2,
            doc,
            "multipart_monograph",
        )

    assert isinstance(error.value, RecordRelationsError)