diff --git a/swh/web/add_forge_now/views.py b/swh/web/add_forge_now/views.py new file mode 100644 --- /dev/null +++ b/swh/web/add_forge_now/views.py @@ -0,0 +1,87 @@ +# Copyright (C) 2022 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU Affero General Public License version 3, or any later version +# See top-level LICENSE file for more information + +from typing import Any, Dict + +from django.conf.urls import url +from django.core.paginator import Paginator +from django.db.models import Q +from django.http.request import HttpRequest +from django.http.response import HttpResponse, JsonResponse + +from swh.web.api.views.add_forge_now import ( + AddForgeNowRequestPublicSerializer, + AddForgeNowRequestSerializer, +) +from swh.web.auth.utils import ADD_FORGE_MODERATOR_PERMISSION + +from .models import Request as AddForgeRequest + + +def add_forge_request_list_datatables(request: HttpRequest) -> HttpResponse: + """Dedicated endpoint used by datatables to display the add-forge + requests in the Web UI. + """ + + draw = int(request.GET.get("draw", 0)) + + add_forge_requests = AddForgeRequest.objects.all() + + table_data: Dict[str, Any] = { + "recordsTotal": add_forge_requests.count(), + "draw": draw, + } + + search_value = request.GET.get("search[value]") + + column_order = request.GET.get("order[0][column]") + field_order = request.GET.get(f"columns[{column_order}][name]", "id") + order_dir = request.GET.get("order[0][dir]", "desc") + + if field_order: + if order_dir == "desc": + field_order = "-" + field_order + add_forge_requests = add_forge_requests.order_by(field_order) + + per_page = int(request.GET.get("length", 10)) + page_num = int(request.GET.get("start", 0)) // per_page + 1 + + if search_value: + add_forge_requests = add_forge_requests.filter( + Q(forge_type__icontains=search_value) + | Q(forge_url__icontains=search_value) + | Q(status__icontains=search_value) + ) + + if ( + int(request.GET.get("user_requests_only", "0")) + and request.user.is_authenticated + ): + add_forge_requests = add_forge_requests.filter( + submitter_name=request.user.username + ) + + paginator = Paginator(add_forge_requests, per_page) + page = paginator.page(page_num) + + if request.user.has_perm(ADD_FORGE_MODERATOR_PERMISSION): + requests = AddForgeNowRequestSerializer(page.object_list, many=True).data + else: + requests = AddForgeNowRequestPublicSerializer(page.object_list, many=True).data + + results = [dict(request) for request in requests] + + table_data["recordsFiltered"] = add_forge_requests.count() + table_data["data"] = results + return JsonResponse(table_data) + + +urlpatterns = [ + url( + r"^add-forge/request/list/datatables$", + add_forge_request_list_datatables, + name="add-forge-request-list-datatables", + ), +] diff --git a/swh/web/api/views/add_forge_now.py b/swh/web/api/views/add_forge_now.py --- a/swh/web/api/views/add_forge_now.py +++ b/swh/web/api/views/add_forge_now.py @@ -9,7 +9,6 @@ from django.core.exceptions import ObjectDoesNotExist from django.core.paginator import Paginator from django.db import transaction -from django.db.models import Q from django.forms import CharField, ModelForm from django.http import HttpResponseBadRequest from django.http.request import HttpRequest @@ -24,11 +23,10 @@ from swh.web.add_forge_now.models import RequestStatus as AddForgeNowRequestStatus from swh.web.api.apidoc import api_doc, format_docstring from swh.web.api.apiurls import api_route +from swh.web.auth.utils import ADD_FORGE_MODERATOR_PERMISSION from swh.web.common.exc import BadInputExc from swh.web.common.utils import reverse -MODERATOR_ROLE = "swh.web.add_forge_now.moderator" - def _block_while_testing(): """Replaced by tests to check concurrency behavior @@ -196,7 +194,7 @@ "You must be authenticated to update a new add-forge request" ) - if not request.user.has_perm(MODERATOR_ROLE): + if not request.user.has_perm(ADD_FORGE_MODERATOR_PERMISSION): return HttpResponseForbidden("You are not a moderator") add_forge_request = ( @@ -254,7 +252,7 @@ ) @api_doc("/add-forge/request/list") @format_docstring() -def api_add_forge_request_list(request: Union[HttpRequest, Request]): +def api_add_forge_request_list(request: Request): """ .. http:get:: /api/1/add-forge/request/list/ @@ -270,45 +268,11 @@ :statuscode 200: always """ - datatables = int(request.GET.get("draw", 0)) - - if datatables: - # datatables request handling - add_forge_requests = AddForgeRequest.objects.all() - - table_data: Dict[str, Any] = {} - table_data["recordsTotal"] = add_forge_requests.count() - table_data["draw"] = int(request.GET["draw"]) - - search_value = request.GET.get("search[value]") - - column_order = request.GET.get("order[0][column]") - field_order = request.GET.get(f"columns[{column_order}][name]") - order_dir = request.GET.get("order[0][dir]") + add_forge_requests = AddForgeRequest.objects.order_by("-id") - if field_order: - if order_dir == "desc": - field_order = "-" + field_order - add_forge_requests = add_forge_requests.order_by(field_order) - else: - add_forge_requests = add_forge_requests.order_by("-id") - - per_page = int(request.GET["length"]) - page_num = int(request.GET["start"]) // per_page + 1 - - if search_value: - add_forge_requests = add_forge_requests.filter( - Q(forge_type__icontains=search_value) - | Q(forge_url__icontains=search_value) - | Q(status__icontains=search_value) - ) - else: - # standard Web API request handling - add_forge_requests = AddForgeRequest.objects.order_by("-id") - - page_num = int(request.GET.get("page", 1)) - per_page = int(request.GET.get("per_page", 10)) - per_page = min(per_page, 1000) + page_num = int(request.GET.get("page", 1)) + per_page = int(request.GET.get("per_page", 10)) + per_page = min(per_page, 1000) if ( int(request.GET.get("user_requests_only", "0")) @@ -321,40 +285,30 @@ paginator = Paginator(add_forge_requests, per_page) page = paginator.page(page_num) - if request.user.has_perm(MODERATOR_ROLE): + if request.user.has_perm(ADD_FORGE_MODERATOR_PERMISSION): requests = AddForgeNowRequestSerializer(page.object_list, many=True).data else: requests = AddForgeNowRequestPublicSerializer(page.object_list, many=True).data results = [dict(request) for request in requests] - if datatables: - # datatables response - table_data["recordsFiltered"] = add_forge_requests.count() - table_data["data"] = results - return table_data - else: - # standard Web API response - response: Dict[str, Any] = {"results": results, "headers": {}} - - if page.has_previous(): - response["headers"]["link-prev"] = reverse( - "api-1-add-forge-request-list", - query_params={ - "page": page.previous_page_number(), - "per_page": per_page, - }, - request=request, - ) + response: Dict[str, Any] = {"results": results, "headers": {}} - if page.has_next(): - response["headers"]["link-next"] = reverse( - "api-1-add-forge-request-list", - query_params={"page": page.next_page_number(), "per_page": per_page}, - request=request, - ) + if page.has_previous(): + response["headers"]["link-prev"] = reverse( + "api-1-add-forge-request-list", + query_params={"page": page.previous_page_number(), "per_page": per_page,}, + request=request, + ) + + if page.has_next(): + response["headers"]["link-next"] = reverse( + "api-1-add-forge-request-list", + query_params={"page": page.next_page_number(), "per_page": per_page}, + request=request, + ) - return response + return response @api_route( @@ -387,7 +341,9 @@ request=add_forge_request ).order_by("id") - if request.user.is_authenticated and request.user.has_perm(MODERATOR_ROLE): + if request.user.is_authenticated and request.user.has_perm( + ADD_FORGE_MODERATOR_PERMISSION + ): data = AddForgeNowRequestSerializer(add_forge_request).data history = AddForgeNowRequestHistorySerializer(request_history, many=True).data else: diff --git a/swh/web/auth/utils.py b/swh/web/auth/utils.py --- a/swh/web/auth/utils.py +++ b/swh/web/auth/utils.py @@ -19,6 +19,7 @@ API_SAVE_ORIGIN_PERMISSION = "swh.web.api.save_origin" ADMIN_LIST_DEPOSIT_PERMISSION = "swh.web.admin.list_deposits" MAILMAP_PERMISSION = "swh.web.mailmap" +ADD_FORGE_MODERATOR_PERMISSION = "swh.web.add_forge_now.moderator" def _get_fernet(password: bytes, salt: bytes) -> Fernet: diff --git a/swh/web/tests/add_forge_now/test_views.py b/swh/web/tests/add_forge_now/test_views.py new file mode 100644 --- /dev/null +++ b/swh/web/tests/add_forge_now/test_views.py @@ -0,0 +1,203 @@ +# Copyright (C) 2022 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU Affero General Public License version 3, or any later version +# See top-level LICENSE file for more information + +import json + +import pytest + +from swh.web.common.utils import reverse +from swh.web.tests.api.views.test_add_forge_now import create_add_forge_request +from swh.web.tests.utils import check_http_get_response + +NB_FORGE_TYPE = 2 +NB_FORGES_PER_TYPE = 20 + + +def create_add_forge_requests(client, regular_user, regular_user2): + requests = [] + for i in range(NB_FORGES_PER_TYPE): + request = { + "forge_type": "gitlab", + "forge_url": f"https://gitlab.example{i:02d}.org", + "forge_contact_email": f"admin@gitlab.example{i:02d}.org", + "forge_contact_name": f"gitlab.example{i:02d}.org admin", + "forge_contact_comment": "user marked as owner in forge members", + } + create_add_forge_request( + client, regular_user, data=request, + ) + requests.append(request) + + request = { + "forge_type": "gitea", + "forge_url": f"https://gitea.example{i:02d}.org", + "forge_contact_email": f"admin@gitea.example{i:02d}.org", + "forge_contact_name": f"gitea.example{i:02d}.org admin", + "forge_contact_comment": "user marked as owner in forge members", + } + create_add_forge_request( + client, regular_user2, data=request, + ) + requests.append(request) + return requests + + +@pytest.mark.django_db(transaction=True, reset_sequences=True) +def test_add_forge_request_list_datatables_no_parameters( + client, regular_user, regular_user2 +): + create_add_forge_requests(client, regular_user, regular_user2) + + url = reverse("add-forge-request-list-datatables") + resp = check_http_get_response(client, url, status_code=200) + data = json.loads(resp.content) + + length = 10 + assert data["draw"] == 0 + assert data["recordsFiltered"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert data["recordsTotal"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert len(data["data"]) == length + # default ordering is by descending id + assert data["data"][0]["id"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert data["data"][-1]["id"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - length + 1 + assert "submitter_name" not in data["data"][0] + + +@pytest.mark.django_db(transaction=True, reset_sequences=True) +def test_add_forge_request_list_datatables( + client, regular_user, regular_user2, add_forge_moderator +): + create_add_forge_requests(client, regular_user, regular_user2) + + length = 10 + + url = reverse( + "add-forge-request-list-datatables", + query_params={"draw": 1, "length": length, "start": 0}, + ) + + client.force_login(regular_user) + resp = check_http_get_response(client, url, status_code=200) + data = json.loads(resp.content) + + assert data["draw"] == 1 + assert data["recordsFiltered"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert data["recordsTotal"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert len(data["data"]) == length + # default ordering is by descending id + assert data["data"][0]["id"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert data["data"][-1]["id"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - length + 1 + assert "submitter_name" not in data["data"][0] + + client.force_login(add_forge_moderator) + resp = check_http_get_response(client, url, status_code=200) + data = json.loads(resp.content) + + assert data["draw"] == 1 + assert data["recordsFiltered"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert data["recordsTotal"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert len(data["data"]) == length + # default ordering is by descending id + assert data["data"][0]["id"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert data["data"][-1]["id"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - length + 1 + assert "submitter_name" in data["data"][0] + + +@pytest.mark.django_db(transaction=True, reset_sequences=True) +def test_add_forge_request_list_datatables_ordering( + client, regular_user, regular_user2 +): + requests = create_add_forge_requests(client, regular_user, regular_user2) + requests_sorted = list(sorted(requests, key=lambda d: d["forge_url"])) + forge_urls_asc = [request["forge_url"] for request in requests_sorted] + forge_urls_desc = list(reversed(forge_urls_asc)) + + length = 10 + + for direction in ("asc", "desc"): + for i in range(4): + url = reverse( + "add-forge-request-list-datatables", + query_params={ + "draw": 1, + "length": length, + "start": i * length, + "order[0][column]": 2, + "order[0][dir]": direction, + "columns[2][name]": "forge_url", + }, + ) + + client.force_login(regular_user) + resp = check_http_get_response(client, url, status_code=200) + data = json.loads(resp.content) + + assert data["draw"] == 1 + assert data["recordsFiltered"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert data["recordsTotal"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert len(data["data"]) == length + + page_forge_urls = [request["forge_url"] for request in data["data"]] + if direction == "asc": + expected_forge_urls = forge_urls_asc[i * length : (i + 1) * length] + else: + expected_forge_urls = forge_urls_desc[i * length : (i + 1) * length] + assert page_forge_urls == expected_forge_urls + + +@pytest.mark.django_db(transaction=True, reset_sequences=True) +def test_add_forge_request_list_datatables_search(client, regular_user, regular_user2): + create_add_forge_requests(client, regular_user, regular_user2) + + url = reverse( + "add-forge-request-list-datatables", + query_params={ + "draw": 1, + "length": NB_FORGES_PER_TYPE, + "start": 0, + "search[value]": "gitlab", + }, + ) + + client.force_login(regular_user) + resp = check_http_get_response(client, url, status_code=200) + data = json.loads(resp.content) + + assert data["draw"] == 1 + assert data["recordsFiltered"] == NB_FORGES_PER_TYPE + assert data["recordsTotal"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert len(data["data"]) == NB_FORGES_PER_TYPE + + page_forge_type = [request["forge_type"] for request in data["data"]] + assert page_forge_type == ["gitlab"] * NB_FORGES_PER_TYPE + + +@pytest.mark.django_db(transaction=True, reset_sequences=True) +def test_add_forge_request_list_datatables_user_requests( + client, regular_user, regular_user2 +): + create_add_forge_requests(client, regular_user, regular_user2) + + url = reverse( + "add-forge-request-list-datatables", + query_params={ + "draw": 1, + "length": NB_FORGES_PER_TYPE * NB_FORGE_TYPE, + "start": 0, + "user_requests_only": 1, + }, + ) + + client.force_login(regular_user2) + resp = check_http_get_response(client, url, status_code=200) + data = json.loads(resp.content) + + assert data["draw"] == 1 + assert data["recordsFiltered"] == NB_FORGES_PER_TYPE + assert data["recordsTotal"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE + assert len(data["data"]) == NB_FORGES_PER_TYPE + + page_forge_type = [request["forge_type"] for request in data["data"]] + assert page_forge_type == ["gitea"] * NB_FORGES_PER_TYPE diff --git a/swh/web/tests/api/views/test_add_forge_now.py b/swh/web/tests/api/views/test_add_forge_now.py --- a/swh/web/tests/api/views/test_add_forge_now.py +++ b/swh/web/tests/api/views/test_add_forge_now.py @@ -12,13 +12,11 @@ import pytest from swh.web.add_forge_now.models import Request -from swh.web.api.views.add_forge_now import MODERATOR_ROLE from swh.web.common.utils import reverse from swh.web.tests.utils import ( check_api_get_responses, check_api_post_response, check_http_post_response, - create_django_permission, ) @@ -132,12 +130,6 @@ assert len(requests) == 1 -@pytest.fixture -def moderator_user(regular_user2): - regular_user2.user_permissions.add(create_django_permission(MODERATOR_ROLE)) - return regular_user2 - - @pytest.mark.django_db(transaction=True, reset_sequences=True) def test_add_forge_request_update_anonymous_user(api_client): url = reverse("api-1-add-forge-request-update", url_args={"id": 1}) @@ -152,34 +144,34 @@ @pytest.mark.django_db(transaction=True, reset_sequences=True) -def test_add_forge_request_update_non_existent(api_client, moderator_user): - api_client.force_login(moderator_user) +def test_add_forge_request_update_non_existent(api_client, add_forge_moderator): + api_client.force_login(add_forge_moderator) url = reverse("api-1-add-forge-request-update", url_args={"id": 1}) check_api_post_response(api_client, url, status_code=400) -def _create_add_forge_request(api_client, regular_user, data=ADD_FORGE_DATA): +def create_add_forge_request(api_client, regular_user, data=ADD_FORGE_DATA): api_client.force_login(regular_user) url = reverse("api-1-add-forge-request-create") return check_api_post_response(api_client, url, data=data, status_code=201,) @pytest.mark.django_db(transaction=True, reset_sequences=True) -def test_add_forge_request_update_empty(api_client, regular_user, moderator_user): - _create_add_forge_request(api_client, regular_user) +def test_add_forge_request_update_empty(api_client, regular_user, add_forge_moderator): + create_add_forge_request(api_client, regular_user) - api_client.force_login(moderator_user) + api_client.force_login(add_forge_moderator) url = reverse("api-1-add-forge-request-update", url_args={"id": 1}) check_api_post_response(api_client, url, status_code=400) @pytest.mark.django_db(transaction=True, reset_sequences=True) def test_add_forge_request_update_missing_field( - api_client, regular_user, moderator_user + api_client, regular_user, add_forge_moderator ): - _create_add_forge_request(api_client, regular_user) + create_add_forge_request(api_client, regular_user) - api_client.force_login(moderator_user) + api_client.force_login(add_forge_moderator) url = reverse("api-1-add-forge-request-update", url_args={"id": 1}) check_api_post_response(api_client, url, data={}, status_code=400) check_api_post_response( @@ -188,10 +180,10 @@ @pytest.mark.django_db(transaction=True, reset_sequences=True) -def test_add_forge_request_update(api_client, regular_user, moderator_user): - _create_add_forge_request(api_client, regular_user) +def test_add_forge_request_update(api_client, regular_user, add_forge_moderator): + create_add_forge_request(api_client, regular_user) - api_client.force_login(moderator_user) + api_client.force_login(add_forge_moderator) url = reverse("api-1-add-forge-request-update", url_args={"id": 1}) check_api_post_response( @@ -208,11 +200,11 @@ @pytest.mark.django_db(transaction=True, reset_sequences=True) def test_add_forge_request_update_invalid_new_status( - api_client, regular_user, moderator_user + api_client, regular_user, add_forge_moderator ): - _create_add_forge_request(api_client, regular_user) + create_add_forge_request(api_client, regular_user) - api_client.force_login(moderator_user) + api_client.force_login(add_forge_moderator) url = reverse("api-1-add-forge-request-update", url_args={"id": 1}) check_api_post_response( api_client, @@ -224,7 +216,7 @@ @pytest.mark.django_db(transaction=True, reset_sequences=True) def test_add_forge_request_update_status_concurrent( - api_client, regular_user, moderator_user, mocker + api_client, regular_user, add_forge_moderator, mocker ): _block_while_testing = mocker.patch( @@ -232,9 +224,9 @@ ) _block_while_testing.side_effect = lambda: time.sleep(1) - _create_add_forge_request(api_client, regular_user) + create_add_forge_request(api_client, regular_user) - api_client.force_login(moderator_user) + api_client.force_login(add_forge_moderator) url = reverse("api-1-add-forge-request-update", url_args={"id": 1}) worker_ended = False @@ -275,7 +267,7 @@ assert resp.data == [] - _create_add_forge_request(api_client, regular_user) + create_add_forge_request(api_client, regular_user) resp = check_api_get_responses(api_client, url, status_code=200) @@ -289,7 +281,7 @@ assert resp.data == [add_forge_request] - _create_add_forge_request(api_client, regular_user, data=ADD_OTHER_FORGE_DATA) + create_add_forge_request(api_client, regular_user, data=ADD_OTHER_FORGE_DATA) resp = check_api_get_responses(api_client, url, status_code=200) @@ -305,13 +297,15 @@ @pytest.mark.django_db(transaction=True, reset_sequences=True) -def test_add_forge_request_list_moderator(api_client, regular_user, moderator_user): +def test_add_forge_request_list_moderator( + api_client, regular_user, add_forge_moderator +): url = reverse("api-1-add-forge-request-list") - _create_add_forge_request(api_client, regular_user) - _create_add_forge_request(api_client, regular_user, data=ADD_OTHER_FORGE_DATA) + create_add_forge_request(api_client, regular_user) + create_add_forge_request(api_client, regular_user, data=ADD_OTHER_FORGE_DATA) - api_client.force_login(moderator_user) + api_client.force_login(add_forge_moderator) resp = check_api_get_responses(api_client, url, status_code=200) add_forge_request = { @@ -339,8 +333,8 @@ def test_add_forge_request_list_pagination( api_client, regular_user, api_request_factory ): - _create_add_forge_request(api_client, regular_user) - _create_add_forge_request(api_client, regular_user, data=ADD_OTHER_FORGE_DATA) + create_add_forge_request(api_client, regular_user) + create_add_forge_request(api_client, regular_user, data=ADD_OTHER_FORGE_DATA) url = reverse("api-1-add-forge-request-list", query_params={"per_page": 1}) @@ -375,8 +369,8 @@ def test_add_forge_request_list_submitter_filtering( api_client, regular_user, regular_user2 ): - _create_add_forge_request(api_client, regular_user) - _create_add_forge_request(api_client, regular_user2, data=ADD_OTHER_FORGE_DATA) + create_add_forge_request(api_client, regular_user) + create_add_forge_request(api_client, regular_user2, data=ADD_OTHER_FORGE_DATA) api_client.force_login(regular_user) url = reverse( @@ -387,159 +381,15 @@ assert len(resp.data) == 1 -NB_FORGE_TYPE = 2 -NB_FORGES_PER_TYPE = 20 - - -def _create_add_forge_requests(api_client, regular_user, regular_user2): - requests = [] - for i in range(NB_FORGES_PER_TYPE): - request = { - "forge_type": "gitlab", - "forge_url": f"https://gitlab.example{i:02d}.org", - "forge_contact_email": f"admin@gitlab.example{i:02d}.org", - "forge_contact_name": f"gitlab.example{i:02d}.org admin", - "forge_contact_comment": "user marked as owner in forge members", - } - _create_add_forge_request( - api_client, regular_user, data=request, - ) - requests.append(request) - - request = { - "forge_type": "gitea", - "forge_url": f"https://gitea.example{i:02d}.org", - "forge_contact_email": f"admin@gitea.example{i:02d}.org", - "forge_contact_name": f"gitea.example{i:02d}.org admin", - "forge_contact_comment": "user marked as owner in forge members", - } - _create_add_forge_request( - api_client, regular_user2, data=request, - ) - requests.append(request) - return requests - - -@pytest.mark.django_db(transaction=True, reset_sequences=True) -def test_add_forge_request_list_datatables( - api_client, regular_user, regular_user2, moderator_user -): - _create_add_forge_requests(api_client, regular_user, regular_user2) - - length = 10 - - url = reverse( - "api-1-add-forge-request-list", - query_params={"draw": 1, "length": length, "start": 0}, - ) - - api_client.force_login(regular_user) - resp = check_api_get_responses(api_client, url, status_code=200) - - assert resp.data["draw"] == 1 - assert resp.data["recordsFiltered"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - assert resp.data["recordsTotal"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - assert len(resp.data["data"]) == length - # default ordering is by descending id - assert resp.data["data"][0]["id"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - assert ( - resp.data["data"][-1]["id"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - length + 1 - ) - assert "submitter_name" not in resp.data["data"][0] - - api_client.force_login(moderator_user) - resp = check_api_get_responses(api_client, url, status_code=200) - - assert resp.data["draw"] == 1 - assert resp.data["recordsFiltered"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - assert resp.data["recordsTotal"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - assert len(resp.data["data"]) == length - # default ordering is by descending id - assert resp.data["data"][0]["id"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - assert ( - resp.data["data"][-1]["id"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - length + 1 - ) - assert "submitter_name" in resp.data["data"][0] - - -@pytest.mark.django_db(transaction=True, reset_sequences=True) -def test_add_forge_request_list_datatables_ordering( - api_client, regular_user, regular_user2, moderator_user -): - requests = _create_add_forge_requests(api_client, regular_user, regular_user2) - requests_sorted = list(sorted(requests, key=lambda d: d["forge_url"])) - forge_urls_asc = [request["forge_url"] for request in requests_sorted] - forge_urls_desc = list(reversed(forge_urls_asc)) - - length = 10 - - for direction in ("asc", "desc"): - for i in range(4): - url = reverse( - "api-1-add-forge-request-list", - query_params={ - "draw": 1, - "length": length, - "start": i * length, - "order[0][column]": 2, - "order[0][dir]": direction, - "columns[2][name]": "forge_url", - }, - ) - - api_client.force_login(regular_user) - resp = check_api_get_responses(api_client, url, status_code=200) - - assert resp.data["draw"] == 1 - assert resp.data["recordsFiltered"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - assert resp.data["recordsTotal"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - assert len(resp.data["data"]) == length - - page_forge_urls = [request["forge_url"] for request in resp.data["data"]] - if direction == "asc": - expected_forge_urls = forge_urls_asc[i * length : (i + 1) * length] - else: - expected_forge_urls = forge_urls_desc[i * length : (i + 1) * length] - assert page_forge_urls == expected_forge_urls - - -@pytest.mark.django_db(transaction=True, reset_sequences=True) -def test_add_forge_request_list_datatables_search( - api_client, regular_user, regular_user2, moderator_user -): - _create_add_forge_requests(api_client, regular_user, regular_user2) - - url = reverse( - "api-1-add-forge-request-list", - query_params={ - "draw": 1, - "length": NB_FORGES_PER_TYPE, - "start": 0, - "search[value]": "gitlab", - }, - ) - - api_client.force_login(regular_user) - resp = check_api_get_responses(api_client, url, status_code=200) - - assert resp.data["draw"] == 1 - assert resp.data["recordsFiltered"] == NB_FORGES_PER_TYPE - assert resp.data["recordsTotal"] == NB_FORGE_TYPE * NB_FORGES_PER_TYPE - assert len(resp.data["data"]) == NB_FORGES_PER_TYPE - - page_forge_type = [request["forge_type"] for request in resp.data["data"]] - assert page_forge_type == ["gitlab"] * NB_FORGES_PER_TYPE - - @pytest.mark.django_db(transaction=True, reset_sequences=True) -def test_add_forge_request_get(api_client, regular_user, moderator_user): - resp = _create_add_forge_request(api_client, regular_user) +def test_add_forge_request_get(api_client, regular_user, add_forge_moderator): + resp = create_add_forge_request(api_client, regular_user) submission_date = resp.data["submission_date"] url = reverse("api-1-add-forge-request-update", url_args={"id": 1}) - api_client.force_login(moderator_user) + api_client.force_login(add_forge_moderator) check_api_post_response( api_client, url, @@ -578,14 +428,14 @@ @pytest.mark.django_db(transaction=True, reset_sequences=True) -def test_add_forge_request_get_moderator(api_client, regular_user, moderator_user): - resp = _create_add_forge_request(api_client, regular_user) +def test_add_forge_request_get_moderator(api_client, regular_user, add_forge_moderator): + resp = create_add_forge_request(api_client, regular_user) submission_date = resp.data["submission_date"] url = reverse("api-1-add-forge-request-update", url_args={"id": 1}) - api_client.force_login(moderator_user) + api_client.force_login(add_forge_moderator) check_api_post_response( api_client, url, @@ -618,7 +468,7 @@ { "id": 2, "text": "waiting for message", - "actor": moderator_user.username, + "actor": add_forge_moderator.username, "actor_role": "MODERATOR", "date": resp.data["history"][1]["date"], "new_status": "WAITING_FOR_FEEDBACK", diff --git a/swh/web/tests/conftest.py b/swh/web/tests/conftest.py --- a/swh/web/tests/conftest.py +++ b/swh/web/tests/conftest.py @@ -36,7 +36,7 @@ from swh.storage.algos.origin import origin_get_latest_visit_status from swh.storage.algos.revisions_walker import get_revisions_walker from swh.storage.algos.snapshot import snapshot_get_all_branches, snapshot_get_latest -from swh.web.auth.utils import OIDC_SWH_WEB_CLIENT_ID +from swh.web.auth.utils import ADD_FORGE_MODERATOR_PERMISSION, OIDC_SWH_WEB_CLIENT_ID from swh.web.common import converters from swh.web.common.origin_save import get_scheduler_load_task_types from swh.web.common.typing import OriginVisitInfo @@ -49,6 +49,7 @@ random_sha1, random_sha256, ) +from swh.web.tests.utils import create_django_permission # Used to skip some tests ctags_json_missing = ( @@ -1214,3 +1215,12 @@ @pytest.fixture def regular_user2(): return User.objects.create_user(username="janedoe", password="") + + +@pytest.fixture +def add_forge_moderator(): + moderator = User.objects.create_user(username="add-forge moderator", password="") + moderator.user_permissions.add( + create_django_permission(ADD_FORGE_MODERATOR_PERMISSION) + ) + return moderator diff --git a/swh/web/urls.py b/swh/web/urls.py --- a/swh/web/urls.py +++ b/swh/web/urls.py @@ -60,6 +60,7 @@ name="browse-swhid", ), url(r"^", include("swh.web.misc.urls")), + url(r"^", include("swh.web.add_forge_now.views")), url(r"^", include("swh.web.auth.views")), url(r"^logout/$", LogoutView.as_view(template_name="logout.html"), name="logout"), ]