Source code for swh.web.add_forge_now.views

# Copyright (C) 2022-2026  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
from typing import Any, Dict, List

from django.contrib.auth.decorators import user_passes_test
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.core.paginator import Paginator
from django.db.models import Q
from django.http.request import HttpRequest
from django.http.response import HttpResponse, HttpResponseForbidden, JsonResponse
from django.shortcuts import render

from swh.web.add_forge_now.api_views import (
    AddForgeNowRequestActorRole,
    AddForgeNowRequestForm,
    AddForgeNowRequestHistory,
    AddForgeNowRequestPublicSerializer,
    AddForgeNowRequestSerializer,
    AddForgeNowRequestStatus,
)
from swh.web.add_forge_now.models import Request as AddForgeRequest
from swh.web.add_forge_now.models import RequestHistory
from swh.web.auth.utils import is_add_forge_now_moderator
from swh.web.utils import datatables_order_params, datatables_pagination_params


[docs] 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]") field_order = datatables_order_params(request, "id", "desc") add_forge_requests = add_forge_requests.order_by(*field_order) per_page, page_num = datatables_pagination_params(request) 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 is_add_forge_now_moderator(request.user): requests = AddForgeNowRequestSerializer(page.object_list, many=True).data else: requests = AddForgeNowRequestPublicSerializer(page.object_list, many=True).data results = [dict(req) for req in requests] table_data["recordsFiltered"] = add_forge_requests.count() table_data["data"] = results return JsonResponse(table_data)
FORGE_TYPES: List[str] = [ "bitbucket", "cgit", "forgejo", "gitea", "gitiles", "gitlab", "gitweb", "gogs", "heptapod", "stagit", ]
[docs] def create_request_create(request): """View to create a new 'add_forge_now' request.""" submit_status = "" alert_level = "" status_code = 200 if request.method == "POST": if not request.user.is_authenticated: return HttpResponseForbidden( "You must be authenticated to update a new add-forge request" ) add_forge_request = AddForgeRequest() form = AddForgeNowRequestForm(request.POST, instance=add_forge_request) if form.errors: status_code = 400 alert_level = "danger" submit_status = json.dumps(form.errors) else: try: existing_request = AddForgeRequest.objects.get( forge_url=add_forge_request.forge_url ) except ObjectDoesNotExist: pass else: status_code = 409 submit_status = ( f"Request for forge already exists (id {existing_request.id})" ) alert_level = "danger" if not submit_status: assert isinstance(request.user, User) add_forge_request.submitter_name = request.user.username add_forge_request.submitter_email = request.user.email form.save() request_history = AddForgeNowRequestHistory() request_history.request = add_forge_request request_history.new_status = AddForgeNowRequestStatus.PENDING.name request_history.actor = request.user.username request_history.actor_role = AddForgeNowRequestActorRole.SUBMITTER.name request_history.save() add_forge_request.last_modified_date = request_history.date add_forge_request.save() submit_status = "Your request has been submitted" alert_level = "success" return render( request, "add-forge-creation-form.html", { "forge_types": FORGE_TYPES, "submit_status": submit_status, "alert_level": alert_level, }, status=status_code, )
[docs] def create_request_list(request): """View to list existing 'add_forge_now' requests.""" user_requests = [] if request.user.is_authenticated and "no_js" in request.GET: user_requests = AddForgeRequest.objects.filter( submitter_name=request.user.username ).order_by("-submission_date") return render( request, "add-forge-list.html", { "user_requests": [ AddForgeNowRequestPublicSerializer(user_request).data for user_request in user_requests ] }, )
[docs] def create_request_help(request): """View to explain 'add_forge_now'.""" return render( request, "add-forge-help.html", )
[docs] @user_passes_test(is_add_forge_now_moderator) def create_request_message_source(request: HttpRequest, id: int) -> HttpResponse: """View to retrieve the message source for a given request history entry""" try: history_entry = RequestHistory.objects.select_related("request").get( pk=id, message_source__isnull=False ) assert history_entry.message_source is not None except RequestHistory.DoesNotExist: return HttpResponse(status=404) response = HttpResponse( bytes(history_entry.message_source), content_type="text/email" ) filename = f"add-forge-now-{history_entry.request.forge_domain}-message{id}.eml" response["Content-Disposition"] = f'attachment; filename="{filename}"' return response