コード例 #1
0
    def _validate_sequence_creation_payload(self, record, payload):
        """Validate the payload when creating a new sequence relation."""
        try:
            next_pid_value = payload.pop("next_pid_value")
            next_pid_type = payload.pop("next_pid_type")
            previous_pid_value = payload.pop("previous_pid_value")
            previous_pid_type = payload.pop("previous_pid_type")
        except KeyError as key:
            raise RecordRelationsError(
                "The `{}` is a required field".format(key))

        if (record["pid"] != next_pid_value
                and record["pid"] != previous_pid_value):
            raise RecordRelationsError(
                "Cannot create a relation for other record than one with PID "
                "`{}`".format(record["pid"]))

        if next_pid_value == previous_pid_value:
            raise RecordRelationsError(
                "Cannot create a sequence with the same next PID `{}`"
                "and previous PID `{}`".format(next_pid_value,
                                               previous_pid_value))

        return (
            next_pid_value,
            next_pid_type,
            previous_pid_value,
            previous_pid_type,
            payload,
        )
コード例 #2
0
    def _validate_relation_between_records(self, first, second, relation_name):
        """Validate relation between type of records."""
        from invenio_app_ils.documents.api import Document
        from invenio_app_ils.series.api import Series

        # records must be of the same type
        same_document = isinstance(first, Document) and isinstance(
            second, Document)
        same_series = (isinstance(first, Series)
                       and isinstance(second, Series) and
                       first["mode_of_issuance"] == second["mode_of_issuance"])
        valid_edition_relation = relation_name == "edition" and (
            (isinstance(first, Document) and isinstance(second, Series)
             and second["mode_of_issuance"] == "MULTIPART_MONOGRAPH") or
            (isinstance(second, Document) and isinstance(first, Series)
             and first["mode_of_issuance"] == "MULTIPART_MONOGRAPH"))

        valid_edition_fields = relation_name == "edition" and \
            first.get('edition', False) and second.get('edition', False)

        valid_language_fields = relation_name == 'language' and \
            first.get('languages', False) and second.get('languages', False)

        valid_other_fields = relation_name == "other"

        equal_editions = relation_name == 'edition' and first.get('edition') \
            == second.get('edition')

        equal_languages = relation_name == 'language' and \
            first.get('languages') == second.get('languages')

        if not (same_document or same_series or valid_edition_relation):
            raise RecordRelationsError(
                "Cannot create relation `{}` between PID `{}` and  PID `{}`,"
                " they are different record types".format(
                    relation_name, first.pid.pid_value, second.pid.pid_value))

        if not (valid_edition_fields or valid_language_fields
                or valid_other_fields):
            raise RecordRelationsError(
                "Cannot create relation `{}` "
                "between PID `{}` and  PID `{}`,"
                " one of the records is missing {} fields".format(
                    relation_name, first.pid.pid_value, second.pid.pid_value,
                    relation_name))

        if equal_editions or equal_languages:
            raise RecordRelationsError("Cannot create relation `{}` "
                                       "between PID `{}` and  PID `{}`,"
                                       " records have equal {} fields".format(
                                           relation_name, first.pid.pid_value,
                                           second.pid.pid_value,
                                           relation_name))

        return True
コード例 #3
0
    def _validate_relation_between_records(self, parent, child, relation_name):
        """Validate relation between type of records."""
        from invenio_app_ils.documents.api import Document
        from invenio_app_ils.series.api import Series

        # when child is Document, parent is any type of Series
        is_series_doc = isinstance(child, Document) and isinstance(
            parent, Series
        )
        # when child is Multipart Monograph, parent is only Serials
        is_serial_mm = (
            isinstance(child, Series)
            and isinstance(parent, Series)
            and child["mode_of_issuance"] == "MULTIPART_MONOGRAPH"
            and parent["mode_of_issuance"] == "SERIAL"
        )

        if not (is_series_doc or is_serial_mm):
            raise RecordRelationsError(
                "Cannot create a relation `{}` between PID `{}` as parent and "
                "PID `{}` as child.".format(
                    relation_name, parent.pid.pid_value, child.pid.pid_value
                )
            )
        return True
コード例 #4
0
 def get_relation_by_name(name):
     """Get the relation_type by name."""
     for relation in current_app.config["ILS_PIDRELATIONS_TYPES"]:
         if relation.name == name:
             return relation
     raise RecordRelationsError(
         "A relation type with name `{}` does not exist".format(name))
コード例 #5
0
ファイル: views.py プロジェクト: topless/invenio-app-ils
    def _create_sibling_relation(self, record, relation_type, payload):
        """Create a Siblings relation from current record to the given PID.

        Expected payload:

            {
                pid_value: <pid_value>,
                pid_type: <pid_type>,
                relation_type: "<relation name>",
                [note: "<note>"]
            }
        """
        pid_value, pid_type, metadata = self._validate_siblings_creation_payload(
            payload
        )

        if pid_value == record["pid"] and pid_type == record._pid_type:
            raise RecordRelationsError(
                "Cannot create a relation for PID `{}` with itself".format(
                    pid_value
                )
            )

        second = IlsRecord.get_record_by_pid(pid_value, pid_type=pid_type)

        rr = RecordRelationsSiblings()
        modified_record = rr.add(
            first=record,
            second=second,
            relation_type=relation_type,
            **metadata
        )
        return modified_record, record, second
コード例 #6
0
    def _validate_relation_between_records(self, first, second, relation_name):
        """Validate relation between type of records."""
        from invenio_app_ils.documents.api import Document
        from invenio_app_ils.series.api import Series

        # records must be of the same type
        same_document = isinstance(first, Document) and isinstance(
            second, Document
        )
        same_series = (
            isinstance(first, Series)
            and isinstance(second, Series)
            and first["mode_of_issuance"] == second["mode_of_issuance"]
        )
        valid_edition = relation_name == "edition" and (
            (
                isinstance(first, Document)
                and isinstance(second, Series)
                and second["mode_of_issuance"] == "MULTIPART_MONOGRAPH"
            )
            or (
                isinstance(second, Document)
                and isinstance(first, Series)
                and first["mode_of_issuance"] == "MULTIPART_MONOGRAPH"
            )
        )

        if not (same_document or same_series or valid_edition):
            raise RecordRelationsError(
                "Cannot create a relation `{}` between PID `{}` and  PID `{}`,"
                " they are different record types".format(
                    relation_name, first.pid.pid_value, second.pid.pid_value
                )
            )
        return True
コード例 #7
0
    def _validate_relation_between_records(
        self, previous_rec, next_rec, relation_name
    ):
        """Validate relation between type of records."""
        from invenio_app_ils.series.api import Series

        # records must be of the same type, Sequences support only Series
        allowed_types = [Series]

        for record_type in allowed_types:
            if isinstance(previous_rec, record_type) and isinstance(
                next_rec, record_type
            ):
                return True

        raise RecordRelationsError(
            "Cannot create a relation `{}` between PID `{}` with type {} "
            " and PID `{}` with type {}.".format(
                relation_name,
                previous_rec.pid.pid_value,
                previous_rec.pid.pid_type,
                next_rec.pid.pid_value,
                next_rec.pid.pid_type,
            )
        )
コード例 #8
0
 def _validate_relation_type(self, relation_type):
     """Validate the given relation type."""
     if relation_type not in self.relation_types:
         rel_names = ",".join([rt.name for rt in self.relation_types])
         raise RecordRelationsError(
             "Relation type must be one of `{}`".format(rel_names)
         )
コード例 #9
0
ファイル: views.py プロジェクト: oplarshad/invenio-app-ils
        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
コード例 #10
0
ファイル: api.py プロジェクト: topless/invenio-app-ils
    def remove(self, pid):
        """Remove the only possible relation of this given PID.

        If the given PID is a child, or only one relation exists, the relation
        involving PID is simply removed.

        When the given PID is a parent of many relations, then it is deleted
        and a new parent is chosen as when adding new relations.

        Example:
            1 -> 2 <rel-type-1>
            1 -> 3 <rel-type-1>
            1 -> 4 <rel-type-1>
            1 -> 5 <rel-type-1>

            remove(1)

            2 -> 3 <rel-type-1>
            2 -> 4 <rel-type-1>
            2 -> 5 <rel-type-1>

        """
        # get all relations where first is a parent or a child, or second is
        # a parent or a child (any relation where first or second are involved)
        all_relations = self.get_any_relation_of(pid)
        if not all_relations:
            return

        # if there is only one relation involving the given PID, or it is a
        # parent with only one relation or it is a child
        if len(all_relations) == 1:
            # only of relation exists for the given PID, simply delete it
            with db.session.begin_nested():
                db.session.delete(all_relations[0])
        else:
            # given PID is a parent and there are multiple relations with this
            # parent. Elect a new parent and adjust all relations attached to
            # it
            pids_to_relate = set()
            for rel in all_relations:
                pids_to_relate.add(rel.parent)
                pids_to_relate.add(rel.child)

            try:
                # remove the PID for the relation to delete
                pids_to_relate.remove(pid)
            except KeyError:
                raise RecordRelationsError(
                    "Error deleting relation_type `{}` for PID `{}`: the PID "
                    "is not found in all relations of this type.".format(
                        self.relation_type.name, pid.pid_value
                    )
                )

            self._recreate_relations_with_random_parent(
                all_relations, pids_to_relate
            )
コード例 #11
0
ファイル: views.py プロジェクト: oplarshad/invenio-app-ils
    def _validate_siblings_creation_payload(self, payload):
        """Validate the payload when creating a new siblings relation."""
        try:
            pid = payload.pop("pid")
            pid_type = payload.pop("pid_type")
        except KeyError as key:
            raise RecordRelationsError(
                "The `{}` is a required field".format(key))

        return pid, pid_type, payload
コード例 #12
0
ファイル: views.py プロジェクト: oplarshad/invenio-app-ils
    def _validate_parent_child_creation_payload(self, payload):
        """Validate the payload when creating a new parent-child relation."""
        try:
            parent_pid = payload.pop("parent_pid")
            parent_pid_type = payload.pop("parent_pid_type")
            child_pid = payload.pop("child_pid")
            child_pid_type = payload.pop("child_pid_type")
        except KeyError as key:
            raise RecordRelationsError(
                "The `{}` is a required field".format(key))

        return parent_pid, parent_pid_type, child_pid, child_pid_type, payload
コード例 #13
0
    def add(self, parent_pid, child_pid):
        """Add a new relation between parent and child."""
        if self.relation_exists(parent_pid, child_pid):
            raise RecordRelationsError(
                "The relation `{}` between PID `{}` and PID `{}` already "
                "exists".format(
                    self.relation_type.name,
                    parent_pid.pid_value,
                    child_pid.pid_value,
                ))

        with db.session.begin_nested():
            return PIDRelation.create(parent_pid, child_pid,
                                      self.relation_type.id)
コード例 #14
0
    def add(self, previous_pid, next_pid):
        """Add a new relation between previous and next pid."""
        if self.relation_exists(previous_pid, next_pid):
            raise RecordRelationsError(
                "The relation `{}` between parent PID `{}` and child PID `{}` "
                "already exists".format(
                    self.relation_type.name,
                    previous_pid.pid_value,
                    next_pid.pid_value,
                ))

        with db.session.begin_nested():
            return PIDRelation.create(previous_pid, next_pid,
                                      self.relation_type.id)
コード例 #15
0
    def _validate_relation_between_records(self, parent, child, relation_type):
        """Validate relation between type of records."""
        from invenio_app_ils.documents.api import Document
        from invenio_app_ils.series.api import Series

        if relation_type.name == "multipart_monograph":
            pcr = ParentChildRelation(relation_type)
            relations = pcr.get_relations_by_child(child.pid)
            if len(relations) > 0:
                raise RecordRelationsError(
                    "Cannot create a relation `{}` between PID `{}` as parent"
                    " and PID `{}` as child. Record `{}` has already a"
                    " multipart monograph.".format(
                        relation_type.name,
                        parent.pid.pid_value,
                        child.pid.pid_value,
                        child.pid.pid_value,
                    ))

        # when child is Document, parent is any type of Series
        is_series_doc = isinstance(child, Document) and isinstance(
            parent, Series)
        # when child is Multipart Monograph, parent is only Serials
        is_serial_mm = (isinstance(child, Series)
                        and isinstance(parent, Series)
                        and child["mode_of_issuance"] == "MULTIPART_MONOGRAPH"
                        and parent["mode_of_issuance"] == "SERIAL")

        if not (is_series_doc or is_serial_mm):
            raise RecordRelationsError(
                "Cannot create a relation `{}` between PID `{}` as parent and "
                "PID `{}` as child.".format(
                    relation_type.name,
                    parent.pid.pid_value,
                    child.pid.pid_value,
                ))
        return True
コード例 #16
0
 def add_extra_metadata_to(cls, record, relation_name, pid_value, pid_type,
                           **kwargs):
     """Add a new extra metadata dict for the given PID and type."""
     metadata = record.setdefault(cls.field_name(), {})
     relation_metadata = metadata.setdefault(relation_name, [])
     for m in relation_metadata:
         if (m.get("pid_value", "") == pid_value
                 and m.get("pid_type", "") == pid_type):
             raise RecordRelationsError(
                 "The record PID `{}` has already metadata for the relation"
                 " `{}` and record PID `{}`".format(record.pid.pid_value,
                                                    relation_name,
                                                    pid_value))
     obj = RecordRelationsExtraMetadata.build_metadata_object(
         pid_value, pid_type, **kwargs)
     relation_metadata.append(obj)
     record.commit()
コード例 #17
0
    def remove(self, previous_pid, next_pid):
        """Delete the relation for the given PIDs."""
        relation = PIDRelation.query.filter_by(
            parent_id=previous_pid.id,
            child_id=next_pid.id,
            relation_type=self.relation_type.id,
        ).one_or_none()

        if not relation:
            raise RecordRelationsError(
                "The relation `{}` between PID `{}` and PID `{}` does not "
                "exists".format(
                    self.relation_type.name,
                    previous_pid.pid_value,
                    next_pid.pid_value,
                ))

        with db.session.begin_nested():
            db.session.delete(relation)
コード例 #18
0
ファイル: views.py プロジェクト: topless/invenio-app-ils
        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