Skip to content

Commit

Permalink
transfer record from one primary community to another
Browse files Browse the repository at this point in the history
  • Loading branch information
Ducica committed Jan 16, 2025
1 parent 676561b commit 339480f
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 8 deletions.
7 changes: 7 additions & 0 deletions oarepo_requests/resolvers/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

from oarepo_requests.resolvers.ui import resolve
import logging

if TYPE_CHECKING:
from invenio_requests.records import Request
log = logging.getLogger(__name__)


# todo consider - we are not using this strictly in the ui context - so how should we separate these things in the future
def resolve_entity(entity: str, obj: Request, ctx: dict[str, Any]) -> dict:
"""Resolve the entity and put it into the context cache.
Expand All @@ -19,12 +21,16 @@ def resolve_entity(entity: str, obj: Request, ctx: dict[str, Any]) -> dict:
:return: The resolved entity
"""
entity_field_value = getattr(obj, entity)
print(entity_field_value, "entity_field_value", flush=True)
if not entity_field_value:
return {}

reference_dict: dict = entity_field_value.reference_dict
print(reference_dict, "reference_dict", flush=True)

key = entity_context_key(reference_dict)
print(key, "key", flush=True)

if key in ctx:
return ctx[key]
try:
Expand All @@ -38,6 +44,7 @@ def resolve_entity(entity: str, obj: Request, ctx: dict[str, Any]) -> dict:
)
entity = {"links": {}}
ctx[key] = entity
print(entity, "entity", flush=True)
return entity


Expand Down
9 changes: 5 additions & 4 deletions oarepo_requests/resolvers/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ def resolve(identity: Identity, reference: dict[str, str]) -> UIResolvedReferenc
:param reference: Reference to resolve.
"""
reference_type, reference_value = next(iter(reference.items()))
print(reference_type, "reference_type", flush=True)
print(reference_value, "reference_value", flush=True)

# use cache to avoid multiple resolve for the same reference within one request
# the runtime error is risen when we are outside the request context - in this case we just skip the cache
Expand All @@ -64,16 +66,14 @@ def resolve(identity: Identity, reference: dict[str, str]) -> UIResolvedReferenc

entity_resolvers = current_oarepo_requests.entity_reference_ui_resolvers

if reference_type == 'multiple':
if reference_type == "multiple":
# TODO(mirekys): add test coverage
resolved = []
reference_values_list = list(json.loads(reference_value))

for reference_values_item in reference_values_list:
for key, value in reference_values_item.items():
resolved.append(entity_resolvers[key].resolve_one(
identity, value
))
resolved.append(entity_resolvers[key].resolve_one(identity, value))
elif reference_type in entity_resolvers:
resolved = entity_resolvers[reference_type].resolve_one(
identity, reference_value
Expand Down Expand Up @@ -473,6 +473,7 @@ def _search_one(
service: DraftsService = get_matching_service_for_refdict(
{self.reference_type: _id}
)
print(service, "draftservice", flush=True)
return service.read_draft(identity, _id).data


Expand Down
80 changes: 80 additions & 0 deletions oarepo_requests/resources/draft/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,58 @@

from __future__ import annotations

import json
from typing import Any, Dict, Optional, Union

from flask import g
from flask_resources import (
HTTPJSONException,
create_error_handler,
)
from flask_resources.serializers.json import JSONEncoder
from oarepo_communities.errors import (
CommunityAlreadyIncludedException,
TargetCommunityNotProvidedException,
)
from oarepo_runtime.i18n import lazy_gettext as _

from oarepo_requests.resources.record.config import RecordRequestsResourceConfig


class CustomHTTPJSONException(HTTPJSONException):
"""Custom HTTP Exception delivering JSON error responses with an error_type."""

def __init__(
self,
code: Optional[int] = None,
errors: Optional[Union[dict[str, any], list]] = None,
error_type: Optional[str] = None,
**kwargs: Any,
) -> None:
"""Initialize CustomHTTPJSONException."""
super().__init__(code=code, errors=errors, **kwargs)
self.error_type = error_type # Save the error_type passed in the constructor

def get_body(self, environ: any = None, scope: any = None) -> str:
"""Get the request body."""
body = {"status": self.code, "message": self.get_description(environ)}

errors = self.get_errors()
if errors:
body["errors"] = errors

# Add error_type to the response body
if self.error_type:
body["error_type"] = self.error_type

# TODO: Revisit how to integrate error monitoring services. See issue #56
# Temporarily kept for expediency and backward-compatibility
if self.code and (self.code >= 500) and hasattr(g, "sentry_event_id"):
body["error_id"] = str(g.sentry_event_id)

return json.dumps(body, cls=JSONEncoder)


class DraftRecordRequestsResourceConfig(RecordRequestsResourceConfig):
"""Configuration of the draft record requests resource."""

Expand All @@ -20,3 +69,34 @@ class DraftRecordRequestsResourceConfig(RecordRequestsResourceConfig):
"list-requests-draft": "/<pid_value>/draft/requests",
"request-type-draft": "/<pid_value>/draft/requests/<request_type>",
}

error_handlers = {
CommunityAlreadyIncludedException: create_error_handler(
lambda e: CustomHTTPJSONException(
code=400,
description="The community is already included in the record.",
errors=[
{
"field": "payload.community",
"messages": [
_("This is already a primary community of this record.")
],
}
],
error_type="cf_validation_error",
)
),
TargetCommunityNotProvidedException: create_error_handler(
lambda e: CustomHTTPJSONException(
code=400,
description="Target community not provided in the migration request.",
errors=[
{
"field": "payload.community",
"messages": [_("Target community is a required field.")],
}
],
error_type="cf_validation_error",
)
),
}
1 change: 0 additions & 1 deletion oarepo_requests/services/oarepo/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ def create(

if data is None:
data = {}

if hasattr(type_, "can_create"):
error = type_.can_create(identity, data, receiver, topic, creator)
else:
Expand Down
7 changes: 5 additions & 2 deletions oarepo_requests/ui/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
from invenio_records_resources.services.errors import PermissionDeniedError
from invenio_requests import current_request_type_registry
from oarepo_runtime.services.custom_fields import CustomFields, InlinedCustomFields
from oarepo_ui.resources.components import AllowedHtmlTagsComponent
from oarepo_ui.resources.components import (
AllowedHtmlTagsComponent,
AllowedCommunitiesComponent,
)
from oarepo_ui.resources.config import FormConfigResourceConfig, UIResourceConfig
from oarepo_ui.resources.links import UIRecordLink

from oarepo_requests.ui.components import (
ActionLabelsComponent,
FormConfigCustomFieldsComponent,
Expand Down Expand Up @@ -71,6 +73,7 @@ class RequestsFormConfigResourceConfig(FormConfigResourceConfig):
FormConfigCustomFieldsComponent,
FormConfigRequestTypePropertiesComponent,
ActionLabelsComponent,
AllowedCommunitiesComponent,
]
request_view_args = {"request_type": RequestTypeSchema()}
routes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export const requestButtonsDefaultIconConfig = {
edit_published_record: { icon: "pencil", labelPosition: "left" },
assign_doi: { icon: "address card", labelPosition: "left" },
created: { icon: "paper plane", labelPosition: "left" },
initiate_community_migration: { icon: "exchange", labelPosition: "left" },
confirm_community_migration: { icon: "exchange", labelPosition: "left" },
submitted: { icon: "clock", labelPosition: "left" },
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,26 @@ import ReactDOM from "react-dom";
import { RecordRequests } from "./components";
import { encodeUnicodeBase64 } from "@js/oarepo_ui";
import { i18next } from "@translations/oarepo_requests_ui/i18next";
import { setIn } from "formik";

const recordRequestsAppDiv = document.getElementById("record-requests");

if (recordRequestsAppDiv) {
const record = JSON.parse(recordRequestsAppDiv.dataset.record);

const onActionError = ({ e, formik, modalControl }) => {
if (e?.response?.data?.errors) {
if (
e?.response?.data?.error_type === "cf_validation_error" &&
e?.response?.data?.errors
) {
let errorsObj = {};
console.log(e?.response?.data?.errors);
for (const error of e.response.data.errors) {
errorsObj = setIn(errorsObj, error.field, error.messages.join(" "));
}
console.log(errorsObj);
formik?.setErrors(errorsObj);
} else if (e?.response?.data?.errors) {
const errorData = e.response.data;
const jsonErrors = JSON.stringify(errorData);
const base64EncodedErrors = encodeUnicodeBase64(jsonErrors);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
.ui.modal {
&.requests-request-modal {
.actions {
position: relative;
z-index: -1;
}
.field {
margin-bottom: 1rem !important;
}
Expand Down

0 comments on commit 339480f

Please sign in to comment.