Skip to content

Commit

Permalink
Merge pull request #44 from oarepo/krist/be-415-new-version-request
Browse files Browse the repository at this point in the history
Krist/be 415 new version request
  • Loading branch information
SilvyPuzzlewell authored Aug 26, 2024
2 parents de63fe5 + 7e4245c commit ce26c0f
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 41 deletions.
26 changes: 6 additions & 20 deletions oarepo_requests/actions/edit_topic.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,16 @@
from oarepo_runtime.datastreams.utils import get_record_service_for_record

from .generic import OARepoAcceptAction
from .generic import AddTopicLinksOnPayloadMixin, OARepoAcceptAction


class EditTopicAcceptAction(OARepoAcceptAction):
class EditTopicAcceptAction(AddTopicLinksOnPayloadMixin, OARepoAcceptAction):
self_link = "draft_record:links:self"
self_html_link = "draft_record:links:self_html"

def apply(self, identity, request_type, topic, uow, *args, **kwargs):
topic_service = get_record_service_for_record(topic)
if not topic_service:
raise KeyError(f"topic {topic} service not found")
edit_topic = topic_service.edit(identity, topic["id"], uow=uow)

# add links to the draft (edited) record
edit_topic_dict = edit_topic.to_dict()

if "payload" not in self.request:
self.request["payload"] = {}

# invenio does not allow non-string values in the payload, so using colon notation here
# client will need to handle this and convert to links structure
# can not use dot notation as marshmallow tries to be too smart and does not serialize dotted keys
self.request["payload"]["draft_record:links:self"] = edit_topic_dict[
"links"
]["self"]
self.request["payload"]["draft_record:links:self_html"] = (
edit_topic_dict["links"]["self_html"]
)

return edit_topic._record

return super().apply(identity, request_type, edit_topic, uow, *args, **kwargs)
18 changes: 18 additions & 0 deletions oarepo_requests/actions/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,24 @@ def execute(self, identity, uow, *args, **kwargs):
)


class AddTopicLinksOnPayloadMixin:
self_link = None
self_html_link = None

def apply(self, identity, request_type, topic, uow, *args, **kwargs):
topic_dict = topic.to_dict()

if "payload" not in self.request:
self.request["payload"] = {}

# invenio does not allow non-string values in the payload, so using colon notation here
# client will need to handle this and convert to links structure
# can not use dot notation as marshmallow tries to be too smart and does not serialize dotted keys
self.request["payload"][self.self_link] = topic_dict["links"]["self"]
self.request["payload"][self.self_html_link] = topic_dict["links"]["self_html"]
return topic._record


class OARepoSubmitAction(OARepoGenericActionMixin, actions.SubmitAction):
""""""

Expand Down
18 changes: 18 additions & 0 deletions oarepo_requests/actions/new_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from oarepo_runtime.datastreams.utils import get_record_service_for_record

from .generic import AddTopicLinksOnPayloadMixin, OARepoAcceptAction


class NewVersionAcceptAction(AddTopicLinksOnPayloadMixin, OARepoAcceptAction):
self_link = "draft_record:links:self"
self_html_link = "draft_record:links:self_html"

def apply(self, identity, request_type, topic, uow, *args, **kwargs):
topic_service = get_record_service_for_record(topic)
if not topic_service:
raise KeyError(f"topic {topic} service not found")
new_version_topic = topic_service.new_version(identity, topic["id"], uow=uow)

return super().apply(
identity, request_type, new_version_topic, uow, *args, **kwargs
)
25 changes: 7 additions & 18 deletions oarepo_requests/actions/publish_draft.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from oarepo_runtime.datastreams.utils import get_record_service_for_record

from .generic import OARepoAcceptAction
from .generic import AddTopicLinksOnPayloadMixin, OARepoAcceptAction


class PublishDraftAcceptAction(OARepoAcceptAction):
class PublishDraftAcceptAction(AddTopicLinksOnPayloadMixin, OARepoAcceptAction):
self_link = "published_record:links:self"
self_html_link = "published_record:links:self_html"

def apply(self, identity, request_type, topic, uow, *args, **kwargs):
topic_service = get_record_service_for_record(topic)
if not topic_service:
Expand All @@ -14,20 +17,6 @@ def apply(self, identity, request_type, topic, uow, *args, **kwargs):
identity, id_, uow=uow, expand=False, *args, **kwargs
)

# add links to the published record
published_topic_dict = published_topic.to_dict()

if "payload" not in self.request:
self.request["payload"] = {}

# invenio does not allow non-string values in the payload, so using colon notation here
# client will need to handle this and convert to links structure
# can not use dot notation as marshmallow tries to be too smart and does not serialize dotted keys
self.request["payload"]["published_record:links:self"] = published_topic_dict[
"links"
]["self"]
self.request["payload"]["published_record:links:self_html"] = (
published_topic_dict["links"]["self_html"]
return super().apply(
identity, request_type, published_topic, uow, *args, **kwargs
)

return published_topic._record
3 changes: 1 addition & 2 deletions oarepo_requests/types/edit_record.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import marshmallow as ma
from oarepo_runtime.i18n import lazy_gettext as _

from oarepo_requests.actions.edit_topic import EditTopicAcceptAction

from .generic import NonDuplicableOARepoRequestType
from .ref_types import ModelRefTypes

import marshmallow as ma


class EditPublishedRecordRequestType(NonDuplicableOARepoRequestType):
type_id = "edit_published_record"
Expand Down
34 changes: 34 additions & 0 deletions oarepo_requests/types/new_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import marshmallow as ma
from oarepo_runtime.i18n import lazy_gettext as _

from ..actions.new_version import NewVersionAcceptAction
from .generic import NonDuplicableOARepoRequestType
from .ref_types import ModelRefTypes


class NewVersionRequestType(
NonDuplicableOARepoRequestType
): # NewVersionFromPublishedRecord? or just new_version
type_id = "new_version"
name = _("New Version")
payload_schema = {
"draft_record.links.self": ma.fields.Str(
attribute="draft_record:links:self",
data_key="draft_record:links:self",
),
"draft_record.links.self_html": ma.fields.Str(
attribute="draft_record:links:self_html",
data_key="draft_record:links:self_html",
),
}

@classmethod
@property
def available_actions(cls):
return {
**super().available_actions,
"accept": NewVersionAcceptAction,
}

description = _("Request requesting creation of new version of a published record.")
allowed_topic_ref_types = ModelRefTypes(published=True, draft=False)
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ invenio_requests.types =
delete_published_record = oarepo_requests.types.delete_record:DeletePublishedRecordRequestType
edit_published_record = oarepo_requests.types.edit_record:EditPublishedRecordRequestType
publish_draft = oarepo_requests.types.publish_draft:PublishDraftRequestType
new_version = oarepo_requests.types.new_version:NewVersionRequestType
invenio_requests.entity_resolvers =
auto_approve = oarepo_requests.resolvers.autoapprove:AutoApproveResolver
oarepo_workflows.state_changed_notifiers =
Expand Down
16 changes: 16 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ class DefaultRequests(WorkflowRequestPolicy):
recipients=[AutoApprove()],
transitions=WorkflowTransitions(),
)
new_version = WorkflowRequest(
requesters=[IfInState("published", [RecordOwners()])],
recipients=[AutoApprove()],
transitions=WorkflowTransitions(),
)


class UserGenerator(RecipientGeneratorMixin, Generator):
Expand Down Expand Up @@ -247,6 +252,17 @@ def ret_data(record_id):
return ret_data


@pytest.fixture()
def new_version_data_function():
def ret_data(record_id):
return {
"request_type": "new_version",
"topic": {"thesis": record_id},
}

return ret_data


@pytest.fixture()
def delete_record_data_function():
def ret_data(record_id):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,12 @@ def test_allowed_request_types_on_published_resource(
},
"type_id": "edit_published_record",
},
{
"links": {
"actions": {
"create": f'https://127.0.0.1:5000/api/thesis/{published1["id"]}/requests/new_version'
}
},
"type_id": "new_version",
},
]
5 changes: 5 additions & 0 deletions tests/test_requests/test_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def test_edit_autoaccept(
creator_client = logged_client(creator)

record1 = record_factory(creator.identity)
id_ = record1["id"]

resp_request_create = creator_client.post(
urls["BASE_URL_REQUESTS"],
Expand All @@ -33,6 +34,9 @@ def test_edit_autoaccept(
assert not request["is_open"]
assert request["is_closed"]

assert "draft_record:links:self" in request["payload"]
assert "draft_record:links:self_html" in request["payload"]

ThesisRecord.index.refresh()
ThesisDraft.index.refresh()
# edit action worked?
Expand All @@ -43,3 +47,4 @@ def test_edit_autoaccept(
]["hits"]
assert len(search) == 1
assert search[0]["links"]["self"].endswith("/draft")
assert search[0]["id"] == id_
49 changes: 49 additions & 0 deletions tests/test_requests/test_new_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from thesis.records.api import ThesisDraft, ThesisRecord

from tests.test_requests.utils import link_api2testclient


def test_new_version_autoaccept(
vocab_cf,
logged_client,
users,
urls,
new_version_data_function,
record_factory,
search_clear,
):
creator = users[0]
creator_client = logged_client(creator)

record1 = record_factory(creator.identity)

resp_request_create = creator_client.post(
urls["BASE_URL_REQUESTS"],
json=new_version_data_function(record1["id"]),
)
resp_request_submit = creator_client.post(
link_api2testclient(resp_request_create.json["links"]["actions"]["submit"]),
)
# is request accepted and closed?
request = creator_client.get(
f'{urls["BASE_URL_REQUESTS"]}{resp_request_create.json["id"]}',
).json

assert request["status"] == "accepted"
assert not request["is_open"]
assert request["is_closed"]

assert "draft_record:links:self" in request["payload"]
assert "draft_record:links:self_html" in request["payload"]

ThesisRecord.index.refresh()
ThesisDraft.index.refresh()
# new_version action worked?
search = creator_client.get(
f'user{urls["BASE_URL"]}',
).json[
"hits"
]["hits"]
assert len(search) == 2
assert search[0]["id"] != search[1]["id"]
assert search[0]["parent"]["id"] == search[1]["parent"]["id"]
2 changes: 1 addition & 1 deletion tests/test_ui/test_ui_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_record_delete_request_present(
with logged_client(users[0]).get(f"/thesis/{topic['id']}") as c:
assert c.status_code == 200
data = json.loads(c.text)
assert len(data["creatable_request_types"]) == 2
assert len(data["creatable_request_types"]) == 3
assert data["creatable_request_types"]["edit_published_record"] == {
"description": "Request re-opening of published record",
"links": {
Expand Down

0 comments on commit ce26c0f

Please sign in to comment.