Skip to content

Commit e78fe2b

Browse files
committed
refactor: lift entity references up to 'records-resources'
* also bump the records-resources dependency
1 parent 7eb8536 commit e78fe2b

File tree

23 files changed

+64
-678
lines changed

23 files changed

+64
-678
lines changed

invenio_requests/config.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# -*- coding: utf-8 -*-
22
#
33
# Copyright (C) 2021 CERN.
4-
# Copyright (C) 2021 TU Wien.
4+
# Copyright (C) 2021 - 2022 TU Wien.
55
#
66
# Invenio-Requests is free software; you can redistribute it and/or modify it
77
# under the terms of the MIT License; see LICENSE file for more details.
88

99
"""Invenio module for generic and customizable requests."""
1010

11-
from .customizations import DefaultRequestType
12-
from .resolvers.default import UserResolver
11+
from invenio_records_resources.references.resolvers import UserResolver
12+
1313
from .services.permissions import PermissionPolicy
1414

1515
REQUESTS_PERMISSION_POLICY = PermissionPolicy

invenio_requests/customizations/base/request_types.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22
#
3-
# Copyright (C) 2021 TU Wien.
3+
# Copyright (C) 2021 - 2022 TU Wien.
44
# Copyright (C) 2021 CERN.
55
#
66
# Invenio-Requests is free software; you can redistribute it and/or modify
@@ -16,6 +16,7 @@
1616

1717
import base32_lib as base32
1818
import marshmallow as ma
19+
from invenio_records_resources.services.references import EntityReferenceBaseSchema
1920

2021
from ...proxies import current_requests
2122

@@ -99,12 +100,10 @@ class RequestType:
99100
def _create_marshmallow_schema(cls):
100101
"""Create a marshmallow schema for this request type."""
101102
# Avoid circular imports
102-
from invenio_requests.services.schemas import (
103-
EntityReferenceBaseSchema as RefBaseSchema,
104-
)
105103
from invenio_requests.services.schemas import RequestSchema
106104

107105
# The reference fields always need to be added
106+
RefBaseSchema = EntityReferenceBaseSchema
108107
additional_fields = {
109108
"created_by": ma.fields.Nested(
110109
RefBaseSchema.create_from_dict(cls.allowed_creator_ref_types),

invenio_requests/records/api.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22
#
3-
# Copyright (C) 2021 TU Wien.
3+
# Copyright (C) 2021 - 2022 TU Wien.
44
# Copyright (C) 2021 Northwestern University.
55
#
66
# Invenio-Requests is free software; you can redistribute it and/or modify
@@ -17,16 +17,16 @@
1717
from invenio_records_resources.records.systemfields import IndexField
1818
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
1919

20-
from ..customizations.base.states import RequestState
20+
from ..customizations.base.states import RequestState as State
2121
from .dumpers import CalculatedFieldDumperExt
2222
from .models import RequestEventModel, RequestMetadata
2323
from .systemfields import (
24+
EntityReferenceField,
2425
ExpiredStateCalculatedField,
2526
IdentityField,
26-
ReferencedEntityField,
27+
RequestStateCalculatedField,
2728
RequestStatusField,
2829
RequestTypeField,
29-
StateCalculatedField,
3030
)
3131
from .systemfields.entity_reference import (
3232
check_allowed_creators,
@@ -71,22 +71,22 @@ class Request(Record):
7171
custom request actions are registered.
7272
"""
7373

74-
topic = ReferencedEntityField("topic", check_allowed_topics)
74+
topic = EntityReferenceField("topic", check_allowed_topics)
7575
"""Topic (associated object) of the request."""
7676

77-
created_by = ReferencedEntityField("created_by", check_allowed_creators)
77+
created_by = EntityReferenceField("created_by", check_allowed_creators)
7878
"""The entity that created the request."""
7979

80-
receiver = ReferencedEntityField("receiver", check_allowed_receivers)
80+
receiver = EntityReferenceField("receiver", check_allowed_receivers)
8181
"""The entity that will receive the request."""
8282

8383
status = RequestStatusField("status")
8484
"""The current status of the request."""
8585

86-
is_closed = StateCalculatedField("status", expected_state=RequestState.CLOSED)
86+
is_closed = RequestStateCalculatedField("status", expected_state=State.CLOSED)
8787
"""Whether or not the current status can be seen as a 'closed' state."""
8888

89-
is_open = StateCalculatedField("status", expected_state=RequestState.OPEN)
89+
is_open = RequestStateCalculatedField("status", expected_state=State.OPEN)
9090
"""Whether or not the current status can be seen as an 'open' state."""
9191

9292
expires_at = ModelField("expires_at")
@@ -142,8 +142,8 @@ class RequestEvent(Record):
142142
check_referenced = partial(
143143
check_allowed_references,
144144
lambda r: True, # for system process for now
145-
lambda r: ["user"] # only users for now
145+
lambda r: ["user"], # only users for now
146146
)
147147

148-
created_by = ReferencedEntityField("created_by", check_referenced)
148+
created_by = EntityReferenceField("created_by", check_referenced)
149149
"""Who created the event."""

invenio_requests/records/jsonschemas/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,3 @@
66
# it under the terms of the MIT License; see LICENSE file for more details.
77

88
"""JSONSchema directory."""
9-
10-
# TODO it'd be nice to re-use the #agent $ref, but that's defined in
11-
# rdm-records
12-
# -> move that $ref to a more generic package? records-resources maybe?

invenio_requests/records/jsonschemas/request_events/event-v1.0.0.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"$ref": "local://definitions-v1.0.0.json#/$schema"
99
},
1010
"created_by": {
11-
"$ref": "local://requests/definitions-v1.0.0.json#/entity_reference"
11+
"$ref": "local://definitions-v1.0.0.json#/entity_reference"
1212
},
1313
"id": {
1414
"$ref": "local://definitions-v1.0.0.json#/identifier"

invenio_requests/records/jsonschemas/requests/definitions-v1.0.0.json

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,6 @@
33
"$id": "local://requests/definitions-v1.0.0.json",
44
"type": "object",
55
"additionalProperties": false,
6-
"entity_reference": {
7-
"description": "Reference to an entity, with the type as key and ID as value",
8-
"type": ["object", "null"],
9-
"additionalProperties": false,
10-
"patternProperties": {
11-
"^[a-z_]+$": {
12-
"type": "string"
13-
}
14-
}
15-
},
166
"anything": {
177
"description": "A very general schema",
188
"type": "object",

invenio_requests/records/jsonschemas/requests/request-v1.0.0.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@
2626
"$ref": "local://requests/definitions-v1.0.0.json#/anything"
2727
},
2828
"topic": {
29-
"$ref": "local://requests/definitions-v1.0.0.json#/entity_reference"
29+
"$ref": "local://definitions-v1.0.0.json#/entity_reference"
3030
},
3131
"receiver": {
32-
"$ref": "local://requests/definitions-v1.0.0.json#/entity_reference"
32+
"$ref": "local://definitions-v1.0.0.json#/entity_reference"
3333
},
3434
"created_by": {
35-
"$ref": "local://requests/definitions-v1.0.0.json#/entity_reference"
35+
"$ref": "local://definitions-v1.0.0.json#/entity_reference"
3636
},
3737
"@v": {
3838
"type": "string"
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
# -*- coding: utf-8 -*-
22
#
3-
# Copyright (C) 2021 TU Wien.
3+
# Copyright (C) 2021 - 2022 TU Wien.
44
#
55
# Invenio-Requests is free software; you can redistribute it and/or modify
66
# it under the terms of the MIT License; see LICENSE file for more details.
77

88
"""Systemfields for request records."""
99

10-
from .calculated import ExpiredStateCalculatedField, StateCalculatedField
11-
from .entity_reference import ReferencedEntityField
10+
from .entity_reference import EntityReferenceField
11+
from .expired_state import ExpiredStateCalculatedField
1212
from .identity import IdentityField
13+
from .request_state import RequestStateCalculatedField
1314
from .request_type import RequestTypeField
1415
from .status import RequestStatusField
1516

1617
__all__ = (
1718
"ExpiredStateCalculatedField",
1819
"IdentityField",
19-
"ReferencedEntityField",
20+
"EntityReferenceField",
21+
"RequestStateCalculatedField",
2022
"RequestStatusField",
2123
"RequestTypeField",
22-
"StateCalculatedField",
2324
)

invenio_requests/records/systemfields/calculated/__init__.py

Lines changed: 0 additions & 19 deletions
This file was deleted.

invenio_requests/records/systemfields/calculated/base.py

Lines changed: 0 additions & 55 deletions
This file was deleted.

invenio_requests/records/systemfields/entity_reference.py

Lines changed: 9 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22
#
3-
# Copyright (C) 2021 TU Wien.
3+
# Copyright (C) 2021 - 2022 TU Wien.
44
#
55
# Invenio-Requests is free software; you can redistribute it and/or modify
66
# it under the terms of the MIT License; see LICENSE file for more details.
@@ -9,87 +9,17 @@
99

1010
from functools import partial
1111

12-
from invenio_records.systemfields import SystemField
12+
from invenio_records_resources.records.systemfields.entity_reference import (
13+
ReferencedEntityField,
14+
check_allowed_references,
15+
)
1316

14-
from ...resolvers.base import EntityProxy
1517
from ...resolvers.registry import ResolverRegistry
1618

17-
18-
class ReferencedEntityField(SystemField):
19-
"""Systemfield for managing the request type."""
20-
21-
def __init__(self, key=None, reference_check_func=None):
22-
"""Constructor."""
23-
super().__init__(key=key)
24-
self._ref_check = reference_check_func
25-
26-
def _check_reference(self, instance, ref_dict):
27-
"""Check if the reference is accepted."""
28-
if self._ref_check is None:
29-
return True
30-
31-
return self._ref_check(instance, ref_dict)
32-
33-
def set_obj(self, instance, obj):
34-
"""Set the referenced entity."""
35-
# allow the setter to be used with a reference dict,
36-
# an entity proxy, or an actual entity
37-
if not isinstance(obj, dict):
38-
if isinstance(obj, EntityProxy):
39-
obj = obj.reference_dict
40-
elif obj is not None:
41-
obj = ResolverRegistry.reference_entity(obj, raise_=True)
42-
43-
# check if the reference is allowed
44-
if not self._check_reference(instance, obj):
45-
raise ValueError(f"Invalid reference for '{self.key}': {obj}")
46-
47-
# set dictionary key and reset the cache
48-
self.set_dictkey(instance, obj)
49-
self._set_cache(instance, None)
50-
51-
def __set__(self, record, value):
52-
"""Set the referenced entity."""
53-
assert record is not None
54-
self.set_obj(record, value)
55-
56-
def obj(self, instance):
57-
"""Get the referenced entity as an `EntityProxy`."""
58-
obj = self._get_cache(instance)
59-
if obj is not None:
60-
return obj
61-
62-
reference_dict = self.get_dictkey(instance)
63-
if reference_dict is None:
64-
# TODO maybe use a `NullProxy` instead?
65-
return None
66-
67-
obj = ResolverRegistry.resolve_entity_proxy(reference_dict)
68-
self._set_cache(instance, obj)
69-
return obj
70-
71-
def __get__(self, record, owner=None):
72-
"""Get the referenced entity as an `EntityProxy`."""
73-
if record is None:
74-
# access by class
75-
return self
76-
77-
return self.obj(record)
78-
79-
80-
def check_allowed_references(get_allows_none, get_allowed_types, request, ref_dict):
81-
"""Check the reference according to rules specific to requests.
82-
83-
In case the ``ref_dict`` is ``None``, it will check if this is allowed for the
84-
reference at hand.
85-
Otherwise, it will check if the reference dict's key (i.e. the TYPE) is allowed.
86-
"""
87-
if ref_dict is None:
88-
return get_allows_none(request)
89-
90-
ref_type = list(ref_dict.keys())[0]
91-
return ref_type in get_allowed_types(request)
92-
19+
EntityReferenceField = partial(
20+
ReferencedEntityField, resolver_registry=ResolverRegistry
21+
)
22+
"""An opinionated ReferenceEntityField with set ResolverRegistry."""
9323

9424
check_allowed_creators = partial(
9525
check_allowed_references,

invenio_requests/records/systemfields/calculated/expired.py renamed to invenio_requests/records/systemfields/expired_state.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22
#
3-
# Copyright (C) 2021 TU Wien.
3+
# Copyright (C) 2021 - 2022 TU Wien.
44
#
55
# Invenio-Requests is free software; you can redistribute it and/or modify
66
# it under the terms of the MIT License; see LICENSE file for more details.
@@ -11,8 +11,7 @@
1111
from datetime import datetime
1212

1313
import pytz
14-
15-
from .base import CalculatedField
14+
from invenio_records_resources.records.systemfields.calculated import CalculatedField
1615

1716

1817
class ExpiredStateCalculatedField(CalculatedField):

0 commit comments

Comments
 (0)