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 @@ -7,6 +7,7 @@ from typing import Union from django.core.exceptions import ObjectDoesNotExist +from django.core.paginator import Paginator from django.db import transaction from django.forms import CharField, ModelForm from django.http import HttpResponseBadRequest @@ -22,6 +23,7 @@ from swh.web.api.apidoc import api_doc, format_docstring from swh.web.api.apiurls import api_route from swh.web.common.exc import BadInputExc +from swh.web.common.utils import reverse MODERATOR_ROLE = "swh.web.add_forge_now.moderator" @@ -223,3 +225,65 @@ data = AddForgeNowRequestSerializer(add_forge_request).data return Response(data=data, status=200) + + +@api_route( + r"/add-forge/request/list", "api-1-add-forge-request-list", methods=["GET"], +) +@api_doc("/add-forge/request/list") +@format_docstring() +def api_add_forge_request_list(request: Union[HttpRequest, Request]): + """ + .. http:get:: /api/1/add-forge/request/list/ + + List requests to add forges to the list of those crawled regularly + by Software Heritage. + + {common_headers} + {resheader_link} + + :query int page: optional page number + :query int per_page: optional number of elements per page (bounded to 1000) + + :statuscode 200: always + """ + + add_forge_requests = AddForgeRequest.objects.order_by("-id") + + 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 + ) + + page_num = int(request.GET.get("page", 1)) + per_page = int(request.GET.get("per_page", 10)) + per_page = min(per_page, 1000) + + paginator = Paginator(add_forge_requests, per_page) + page = paginator.page(page_num) + + if request.user.has_perm(MODERATOR_ROLE): + results = AddForgeNowRequestSerializer(page.object_list, many=True).data + else: + results = AddForgeNowRequestPublicSerializer(page.object_list, many=True).data + + response = {"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, + ) + + 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 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 @@ -15,6 +15,7 @@ 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, @@ -261,3 +262,121 @@ ) thread.join() assert worker_ended + + +@pytest.mark.django_db(transaction=True, reset_sequences=True) +def test_add_forge_request_list_anonymous(api_client, regular_user): + url = reverse("api-1-add-forge-request-list") + + resp = check_api_get_responses(api_client, url, status_code=200) + + assert resp.data == [] + + _create_add_forge_request(api_client, regular_user) + + resp = check_api_get_responses(api_client, url, status_code=200) + + add_forge_request = { + "forge_url": ADD_FORGE_DATA["forge_url"], + "forge_type": ADD_FORGE_DATA["forge_type"], + "status": "PENDING", + "submission_date": resp.data[0]["submission_date"], + } + + assert resp.data == [add_forge_request] + + _create_add_forge_request(api_client, regular_user, data=ADD_OTHER_FORGE_DATA) + + resp = check_api_get_responses(api_client, url, status_code=200) + + other_forge_request = { + "forge_url": ADD_OTHER_FORGE_DATA["forge_url"], + "forge_type": ADD_OTHER_FORGE_DATA["forge_type"], + "status": "PENDING", + "submission_date": resp.data[0]["submission_date"], + } + + assert resp.data == [other_forge_request, add_forge_request] + + +@pytest.mark.django_db(transaction=True, reset_sequences=True) +def test_add_forge_request_list_moderator(api_client, regular_user, moderator_user): + 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) + + api_client.force_login(moderator_user) + resp = check_api_get_responses(api_client, url, status_code=200) + + add_forge_request = { + **ADD_FORGE_DATA, + "status": "PENDING", + "submission_date": resp.data[1]["submission_date"], + "submitter_name": regular_user.username, + "submitter_email": regular_user.email, + "id": 1, + } + + other_forge_request = { + **ADD_OTHER_FORGE_DATA, + "status": "PENDING", + "submission_date": resp.data[0]["submission_date"], + "submitter_name": regular_user.username, + "submitter_email": regular_user.email, + "id": 2, + } + + assert resp.data == [other_forge_request, add_forge_request] + + +@pytest.mark.django_db(transaction=True, reset_sequences=True) +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) + + url = reverse("api-1-add-forge-request-list", query_params={"per_page": 1}) + + resp = check_api_get_responses(api_client, url, 200) + + assert len(resp.data) == 1 + + request = api_request_factory.get(url) + + next_url = reverse( + "api-1-add-forge-request-list", + query_params={"page": 2, "per_page": 1}, + request=request, + ) + + assert resp["Link"] == f'<{next_url}>; rel="next"' + + resp = check_api_get_responses(api_client, next_url, 200) + + assert len(resp.data) == 1 + + prev_url = reverse( + "api-1-add-forge-request-list", + query_params={"page": 1, "per_page": 1}, + request=request, + ) + + assert resp["Link"] == f'<{prev_url}>; rel="previous"' + + +@pytest.mark.django_db(transaction=True, reset_sequences=True) +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) + + api_client.force_login(regular_user) + url = reverse( + "api-1-add-forge-request-list", query_params={"user_requests_only": 1} + ) + resp = check_api_get_responses(api_client, url, status_code=200) + + assert len(resp.data) == 1