Skip to content

Commit

Permalink
Merge pull request #100 from oarepo/miroslavsimek/fe-303-implicitne-n…
Browse files Browse the repository at this point in the history
…ezobrazene-zadosti-na-schvaleni-na-dashboardu

Added ?all=true filter that returns all requests user has access to
  • Loading branch information
mesemus authored Dec 12, 2024
2 parents ab9b866 + abe9f28 commit 86e5854
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 45 deletions.
24 changes: 23 additions & 1 deletion oarepo_requests/invenio_patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@

from __future__ import annotations

from functools import cached_property
from functools import cached_property, partial
from typing import TYPE_CHECKING, Any, Callable

from flask_resources import JSONSerializer, ResponseHandler
from invenio_records_resources.resources.records.headers import etag_headers
from invenio_records_resources.services.records.params import FilterParam
from invenio_records_resources.services.records.params.base import ParamInterpreter
from invenio_requests.resources.events.config import RequestCommentsResourceConfig
from invenio_requests.resources.requests.config import (
RequestSearchRequestArgsSchema,
Expand Down Expand Up @@ -53,6 +54,25 @@ def apply(self, identity: Identity, search: Query, params: dict[str, str]) -> Qu
return search


class RequestAllAvailableFilterParam(ParamInterpreter):
"""A no-op filter that returns all requests that are readable by the current user."""

def __init__(self, param_name, config):
"""Initialize the filter."""
self.param_name = param_name
super().__init__(config)

@classmethod
def factory(cls, param=None):
"""Create a new filter parameter."""
return partial(cls, param)

def apply(self, identity, search, params):
"""Apply the filter to the search - does nothing."""
params.pop(self.param_name, None)
return search


class RequestNotOwnerFilterParam(FilterParam):
"""Filter requests that are not owned by the current user.
Expand Down Expand Up @@ -89,6 +109,7 @@ class EnhancedRequestSearchOptions(RequestSearchOptions):
params_interpreters_cls = RequestSearchOptions.params_interpreters_cls + [
RequestOwnerFilterParam.factory("mine", "created_by.user"),
RequestNotOwnerFilterParam.factory("assigned", "created_by.user"),
RequestAllAvailableFilterParam.factory("all"),
IsClosedParam.factory("is_closed"),
]

Expand All @@ -98,6 +119,7 @@ class ExtendedRequestSearchRequestArgsSchema(RequestSearchRequestArgsSchema):

mine = fields.Boolean()
assigned = fields.Boolean()
all = fields.Boolean()
is_closed = fields.Boolean()


Expand Down
7 changes: 4 additions & 3 deletions oarepo_requests/resources/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ def _reference_map_from_list(obj_list: list[dict]) -> dict[str, set]:
for reference_type in reference_types:
if reference_type in hit:
reference = hit[reference_type]
reference_map[list(reference.keys())[0]].add(
list(reference.values())[0]
)
if reference:
reference_map[list(reference.keys())[0]].add(
list(reference.values())[0]
)
return reference_map


Expand Down
18 changes: 18 additions & 0 deletions oarepo_requests/services/ui_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from __future__ import annotations

import datetime
from types import SimpleNamespace
from typing import TYPE_CHECKING, Any, cast

Expand Down Expand Up @@ -110,9 +111,26 @@ class UIRequestSchemaMixin:
status_code = ma.fields.String()
"""Status code of the request."""

@ma.pre_dump
def _convert_dates_for_localized(self, data: dict, **kwargs: Any) -> dict:
if isinstance(data.get("created"), str):
data["created"] = datetime.datetime.fromisoformat(data["created"])

if isinstance(data.get("updated"), str):
data["updated"] = datetime.datetime.fromisoformat(data["updated"])

if isinstance(data.get("expires_at"), str):
data["expires_at"] = datetime.datetime.fromisoformat(data["expires_at"])

return data

@ma.pre_dump
def _add_type_details(self, data: dict, **kwargs: Any) -> dict:
"""Add details taken from the request type to the serialized request."""
if isinstance(data.get("created"), str):
data["created"] = datetime.datetime.fromisoformat(data["created"])
if isinstance(data.get("updated"), str):
data["updated"] = datetime.datetime.fromisoformat(data["updated"])
type = data["type"]
type_obj = current_request_type_registry.lookup(type, quiet=True)
if hasattr(type_obj, "description"):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,48 @@ export const SideRequestInfo = ({ request }) => {
const statusIcon = getRequestStatusIcon(request?.status_code);
return (
<List horizontal relaxed divided size="small">
<List.Item>
<List.Header as="h3">{i18next.t("Creator")}</List.Header>
<List.Content>
<Icon name="user circle outline" />
<span>
{_has(request, "links.created_by_html") ? (
<a
href={request.links.created_by_html}
target="_blank"
rel="noreferrer"
>
{request.created_by.label}
</a>
) : (
request.created_by?.label
)}
</span>
</List.Content>
</List.Item>
<List.Item>
<List.Header as="h3">{i18next.t("Receiver")}</List.Header>
<List.Content>
<Icon name="mail outline" />
<span>
{_has(request, "links.receiver_html") ? (
<a
href={request.links.receiver_html}
target="_blank"
rel="noreferrer"
>
{request?.receiver?.label}
</a>
) : (
request?.receiver?.label
)}
</span>
</List.Content>
</List.Item>
{request?.created_by &&
<List.Item>
<List.Header as="h3">{i18next.t("Creator")}</List.Header>
<List.Content>
<Icon name="user circle outline" />
<span>
{_has(request, "links.created_by_html") ? (
<a
href={request.links.created_by_html}
target="_blank"
rel="noreferrer"
>
{request.created_by.label}
</a>
) : (
request.created_by?.label
)}
</span>
</List.Content>
</List.Item>
}
{request?.receiver &&
<List.Item>
<List.Header as="h3">{i18next.t("Receiver")}</List.Header>
<List.Content>
<Icon name="mail outline" />
<span>
{_has(request, "links.receiver_html") ? (
<a
href={request.links.receiver_html}
target="_blank"
rel="noreferrer"
>
{request?.receiver?.label}
</a>
) : (
request?.receiver?.label
)}
</span>
</List.Content>
</List.Item>
}
<List.Item>
<List.Header as="h3">{i18next.t("Status")}</List.Header>
<List.Content>
Expand All @@ -68,8 +72,8 @@ export const SideRequestInfo = ({ request }) => {
<a href={request.links.topic_html} target="_blank" rel="noreferrer">
{request?.topic?.label
? _truncate(request?.topic?.label, {
length: 350,
})
length: 350,
})
: i18next.t("Request topic")}
</a>
</List.Content>
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = oarepo-requests
version = 2.3.9
version = 2.3.10
description =
authors = Ronald Krist <[email protected]>
readme = README.md
Expand Down
6 changes: 6 additions & 0 deletions tests/test_requests/test_param_interpreters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
#
import json
from tests.test_requests.utils import link2testclient


Expand Down Expand Up @@ -77,6 +78,11 @@ def test_owner_param_interpreter(
assert search_user2_only.json["hits"]["hits"][0]["created_by"] == {"user": "2"}
assert search_user2_only.json["hits"]["hits"][0]["type"] == "another_topic_updating"

# mine requests should be in all=true as well
search_user1_only = user1_client.get(f'{urls["BASE_URL_REQUESTS"]}?all=true')
print(json.dumps(search_user1_only.json))
for hit in search_user1_only.json["hits"]["hits"]:
assert hit['created_by'] == {"user": "1"} or hit['receiver'] == {"user": "1"}

def test_open_param_interpreter(
logged_client,
Expand Down

0 comments on commit 86e5854

Please sign in to comment.