-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
moderation: added request type and service
- Loading branch information
1 parent
7908655
commit c22ab3d
Showing
11 changed files
with
255 additions
and
0 deletions.
There are no files selected for viewing
11 changes: 11 additions & 0 deletions
11
invenio_requests/customizations/user_moderation/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright (C) 2023 CERN. | ||
# | ||
# Invenio-Requests is free software; you can redistribute it and/or modify | ||
# it under the terms of the MIT License; see LICENSE file for more details. | ||
"""User moderation request type.""" | ||
|
||
from .user_moderation import UserModeration | ||
|
||
__all__ = ("UserModeration",) |
56 changes: 56 additions & 0 deletions
56
invenio_requests/customizations/user_moderation/user_moderation.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright (C) 2023 CERN. | ||
# | ||
# Invenio-Requests is free software; you can redistribute it and/or modify | ||
# it under the terms of the MIT License; see LICENSE file for more details. | ||
"""User moderation requests.""" | ||
|
||
from invenio_i18n import lazy_gettext as _ | ||
|
||
from invenio_requests.customizations import RequestType, actions | ||
|
||
|
||
class BlockUserAction(actions.DeclineAction): | ||
"""Represents a decline action used to block an user.""" | ||
|
||
def execute(self, identity, uow): | ||
"""Executes block action.""" | ||
# TODO add specific user block actions | ||
super().execute(identity, uow) | ||
|
||
|
||
class ApproveUserAction(actions.AcceptAction): | ||
"""Represents an accept action used to aprove an user.""" | ||
|
||
def execute(self, identity, uow): | ||
"""Executes aprove action.""" | ||
# TODO add specific user block actions | ||
super().execute(identity, uow) | ||
|
||
|
||
class UserModeration(RequestType): | ||
"""Request to moderate an user.""" | ||
|
||
type_id = "user-moderation" | ||
name = _("User moderation") | ||
|
||
creator_can_be_none = False | ||
topic_can_be_none = False | ||
allowed_creator_ref_types = ["user"] | ||
allowed_receiver_ref_types = ["user"] | ||
allowed_topic_ref_types = ["user"] | ||
|
||
# TODO missing permissions | ||
# AdminNeed = RoleNeed("admin") | ||
# needs_context = {"user.role": AdminNeed, "user.role": AdminNeed} | ||
|
||
available_actions = { | ||
"delete": actions.DeleteAction, | ||
"submit": actions.SubmitAction, | ||
"create": actions.CreateAction, | ||
"cancel": actions.CancelAction, | ||
# Custom implemented actions | ||
"accept": ApproveUserAction, | ||
"decline": BlockUserAction, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright (C) 2023 CERN. | ||
# | ||
# Invenio-Requests is free software; you can redistribute it and/or modify | ||
# it under the terms of the MIT License; see LICENSE file for more details. | ||
"""User moderation requests service.""" | ||
|
||
from .service import UserModerationRequestService | ||
|
||
__all__ = ("UserModerationRequestService",) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright (C) 2023 CERN. | ||
# | ||
# Invenio-Requests is free software; you can redistribute it and/or modify | ||
# it under the terms of the MIT License; see LICENSE file for more details. | ||
"""User moderation requests service errors.""" | ||
from invenio_i18n import lazy_gettext as _ | ||
|
||
|
||
class InvalidCreator(Exception): | ||
"""Reauest creator is invalid.""" | ||
|
||
description = _("Invalid creator for user moderation request.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright (C) 2023 CERN. | ||
# | ||
# Invenio-Requests is free software; you can redistribute it and/or modify | ||
# it under the terms of the MIT License; see LICENSE file for more details. | ||
"""User moderation service.""" | ||
|
||
from invenio_access.permissions import system_identity, system_user_id | ||
from invenio_i18n import gettext as _ | ||
|
||
from invenio_requests.customizations.user_moderation.user_moderation import ( | ||
UserModeration, | ||
) | ||
from invenio_requests.resolvers.registry import ResolverRegistry | ||
from invenio_requests.services.user_moderation.errors import InvalidCreator | ||
|
||
|
||
class UserModerationRequestService: | ||
"""Service for User Moderation requests.""" | ||
|
||
def __init__(self, requests_service): | ||
"""Service initialisation as a sub-service of requests.""" | ||
self.requests_service = requests_service | ||
|
||
@property | ||
def request_type_cls(self): | ||
"""User moderation request type.""" | ||
return UserModeration | ||
|
||
# /users/moderation action="block" | ||
|
||
# service.moderate(identity, user, action) | ||
# get user request | ||
# request_service.execute_action(identity, action=action) | ||
|
||
def request_moderation( | ||
self, identity, creator, topic, data=None, uow=None, **kwargs | ||
): | ||
"""Creates a UserModeration request and submits it.""" | ||
if creator != system_user_id: | ||
raise InvalidCreator("Moderation request creator can only be system.") | ||
|
||
data = data or {} | ||
|
||
# For user moderation, topic is the user to be moderated | ||
topic = ResolverRegistry.resolve_entity_proxy({"user": topic}).resolve() | ||
|
||
receiver = {"user": system_user_id} | ||
|
||
creator = {"user": creator} | ||
|
||
request_item = self.requests_service.create( | ||
identity, | ||
data, | ||
self.request_type_cls, | ||
receiver, | ||
creator, | ||
topic=topic, | ||
) | ||
|
||
return self.requests_service.execute_action( | ||
identity=identity, | ||
id_=request_item.id, | ||
action="submit", | ||
data=data, | ||
) | ||
|
||
def search_moderation_requests(self, identity, params=None): | ||
"""Searchs for user moderation requests. | ||
Returns only requests that concern the current user. | ||
""" | ||
params = params or {} | ||
|
||
# Search for UserModeration requests only | ||
q = f"type:{self.request_type_cls.type_id}" | ||
return self.requests_service.search_user_requests(identity, q=q, params=params) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
tests/services/user_moderation/test_user_moderation_service.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright (C) 2023 CERN. | ||
# | ||
# Invenio-Requests is free software; you can redistribute it and/or modify | ||
# it under the terms of the MIT License; see LICENSE file for more details. | ||
"""Test user moderation service.""" | ||
|
||
import pytest | ||
from flask_principal import Need | ||
from invenio_access.permissions import system_identity, system_user_id | ||
from invenio_access.utils import get_identity | ||
|
||
from invenio_requests.proxies import current_user_moderation_service | ||
from invenio_requests.services.user_moderation.errors import InvalidCreator | ||
|
||
|
||
def test_request_moderation(app, users, identity_simple): | ||
"""Tests the service for request moderation.""" | ||
|
||
user = users[0] | ||
|
||
service = current_user_moderation_service | ||
|
||
# Use system identity | ||
request_item = service.request_moderation( | ||
system_identity, creator=system_user_id, topic=user.id | ||
) | ||
assert request_item | ||
# Request moderation creates and submits the moderation request | ||
assert request_item._request.status == "submitted" | ||
|
||
# User identity is not allowed to submit moderation requests | ||
with pytest.raises(Exception): | ||
service.request_moderation( | ||
identity_simple, creator=system_user_id, topic=user.id | ||
) | ||
|
||
# Only system user id can be the creator | ||
with pytest.raises(InvalidCreator): | ||
service.request_moderation(system_identity, creator=user.id, topic=user.id) | ||
|
||
|
||
def test_search_moderation(app, users, submit_request): | ||
"""Tests the search for request moderation.""" | ||
|
||
user = users[1] | ||
|
||
service = current_user_moderation_service | ||
|
||
request_item = service.request_moderation( | ||
system_identity, creator=system_user_id, topic=user.id | ||
) | ||
assert request_item | ||
|
||
# Retrieve user requests (user has to be authenticated user) | ||
user_identity = get_identity(user) | ||
user_identity.provides.add(Need(method="system_role", value="authenticated_user")) | ||
|
||
# Create a generic request to test the user moderation search filter | ||
request = submit_request(user_identity, receiver=users[2]) | ||
assert request | ||
|
||
# Should only return one request (user moderation) | ||
search = service.search_moderation_requests(user_identity) | ||
assert search.total == 1 | ||
|
||
hits = search.to_dict()["hits"]["hits"] | ||
hit = hits[0] | ||
assert hit["topic"]["user"] == str(user.id) | ||
assert hit["type"] == service.request_type_cls.type_id |