diff --git a/assets/src/bundles/add_forge/request-dashboard.js b/assets/src/bundles/add_forge/request-dashboard.js --- a/assets/src/bundles/add_forge/request-dashboard.js +++ b/assets/src/bundles/add_forge/request-dashboard.js @@ -5,15 +5,15 @@ * See top-level LICENSE file for more information */ -import {handleFetchError, csrfPost, getHumanReadableDate} from 'utils/functions'; -import emailTempate from './forge-admin-email.ejs'; +import {csrfPost, getHumanReadableDate, handleFetchError} from 'utils/functions'; import requestHistoryItem from './add-request-history-item.ejs'; +import emailTempate from './forge-admin-email.ejs'; let forgeRequest; -export function onRequestDashboardLoad(requestId) { +export function onRequestDashboardLoad(requestId, nextStatusesFor) { $(document).ready(() => { - populateRequestDetails(requestId); + populateRequestDetails(requestId, nextStatusesFor); $('#contactForgeAdmin').click((event) => { contactForgeAdmin(event); @@ -29,7 +29,7 @@ $('#userMessage').text('The request status has been updated '); $('#userMessage').removeClass('badge-danger'); $('#userMessage').addClass('badge-success'); - populateRequestDetails(requestId); + populateRequestDetails(requestId, nextStatusesFor); } catch (response) { $('#userMessage').text('Sorry; Updating the request failed'); $('#userMessage').removeClass('badge-success'); @@ -39,7 +39,7 @@ }); } -async function populateRequestDetails(requestId) { +async function populateRequestDetails(requestId, nextStatusesFor) { try { const response = await fetch(Urls.api_1_add_forge_request_get(requestId)); handleFetchError(response); @@ -60,7 +60,7 @@ $('#contactForgeAdmin').attr('emailCc', forgeRequest.inbound_email_address); $('#contactForgeAdmin').attr('emailSubject', `Software Heritage archival notification for ${forgeRequest.forge_domain}`); populateRequestHistory(data.history); - populateDecisionSelectOption(forgeRequest.status); + populateDecisionSelectOption(forgeRequest.status, nextStatusesFor); } catch (e) { if (e instanceof Response) { // The fetch request failed (in handleFetchError), show the error message @@ -86,27 +86,7 @@ }); } -export function populateDecisionSelectOption(currentStatus) { - const nextStatusesFor = { - 'PENDING': ['WAITING_FOR_FEEDBACK', 'REJECTED', 'SUSPENDED'], - 'WAITING_FOR_FEEDBACK': ['FEEDBACK_TO_HANDLE'], - 'FEEDBACK_TO_HANDLE': [ - 'WAITING_FOR_FEEDBACK', - 'ACCEPTED', - 'REJECTED', - 'SUSPENDED' - ], - 'ACCEPTED': ['SCHEDULED'], - 'SCHEDULED': [ - 'FIRST_LISTING_DONE', - 'FIRST_ORIGIN_LOADED' - ], - 'FIRST_LISTING_DONE': ['FIRST_ORIGIN_LOADED'], - 'FIRST_ORIGIN_LOADED': [], - 'REJECTED': [], - 'SUSPENDED': ['PENDING'], - 'UNSUCCESSFUL': [] - }; +export function populateDecisionSelectOption(currentStatus, nextStatusesFor) { // Determine the possible next status out of the current one const nextStatuses = nextStatusesFor[currentStatus]; diff --git a/swh/web/add_forge_now/models.py b/swh/web/add_forge_now/models.py --- a/swh/web/add_forge_now/models.py +++ b/swh/web/add_forge_now/models.py @@ -6,7 +6,7 @@ from __future__ import annotations import enum -from typing import List +from typing import Dict, List from urllib.parse import urlparse from django.db import models @@ -38,30 +38,40 @@ def choices(cls): return tuple((variant.name, variant.value) for variant in cls) - def allowed_next_statuses(self) -> List[RequestStatus]: - next_statuses = { - self.PENDING: [self.WAITING_FOR_FEEDBACK, self.REJECTED, self.SUSPENDED], - self.WAITING_FOR_FEEDBACK: [self.FEEDBACK_TO_HANDLE], - self.FEEDBACK_TO_HANDLE: [ - self.WAITING_FOR_FEEDBACK, - self.ACCEPTED, - self.REJECTED, - self.SUSPENDED, - self.UNSUCCESSFUL, + @classmethod + def next_statuses(cls) -> Dict[RequestStatus, List[RequestStatus]]: + return { + cls.PENDING: [cls.WAITING_FOR_FEEDBACK, cls.REJECTED, cls.SUSPENDED], + cls.WAITING_FOR_FEEDBACK: [cls.FEEDBACK_TO_HANDLE], + cls.FEEDBACK_TO_HANDLE: [ + cls.WAITING_FOR_FEEDBACK, + cls.ACCEPTED, + cls.REJECTED, + cls.SUSPENDED, + cls.UNSUCCESSFUL, ], - self.ACCEPTED: [self.SCHEDULED], - self.SCHEDULED: [ - self.FIRST_LISTING_DONE, + cls.ACCEPTED: [cls.SCHEDULED], + cls.SCHEDULED: [ + cls.FIRST_LISTING_DONE, # in case of race condition between lister and loader: - self.FIRST_ORIGIN_LOADED, + cls.FIRST_ORIGIN_LOADED, ], - self.FIRST_LISTING_DONE: [self.FIRST_ORIGIN_LOADED], - self.FIRST_ORIGIN_LOADED: [], - self.REJECTED: [], - self.SUSPENDED: [self.PENDING], - self.UNSUCCESSFUL: [], + cls.FIRST_LISTING_DONE: [cls.FIRST_ORIGIN_LOADED], + cls.FIRST_ORIGIN_LOADED: [], + cls.REJECTED: [], + cls.SUSPENDED: [cls.PENDING], + cls.UNSUCCESSFUL: [], } - return next_statuses[self] # type: ignore + + @classmethod + def next_statuses_str(cls) -> Dict[str, List[str]]: + return { + key.name: [value.name for value in values] + for key, values in cls.next_statuses().items() + } + + def allowed_next_statuses(self) -> List[RequestStatus]: + return self.next_statuses()[self] class RequestActorRole(enum.Enum): diff --git a/swh/web/admin/add_forge_now.py b/swh/web/admin/add_forge_now.py --- a/swh/web/admin/add_forge_now.py +++ b/swh/web/admin/add_forge_now.py @@ -7,6 +7,7 @@ from django.contrib.auth.decorators import user_passes_test from django.shortcuts import render +from swh.web.add_forge_now.models import RequestStatus from swh.web.admin.adminurls import admin_route from swh.web.auth.utils import is_add_forge_now_moderator @@ -35,5 +36,9 @@ return render( request, "add_forge_now/request-dashboard.html", - {"request_id": request_id, "heading": "Add forge now request dashboard"}, + { + "request_id": request_id, + "heading": "Add forge now request dashboard", + "next_statuses_for": RequestStatus.next_statuses_str(), + }, ) diff --git a/swh/web/templates/add_forge_now/request-dashboard.html b/swh/web/templates/add_forge_now/request-dashboard.html --- a/swh/web/templates/add_forge_now/request-dashboard.html +++ b/swh/web/templates/add_forge_now/request-dashboard.html @@ -9,6 +9,7 @@ {% load render_bundle from webpack_loader %} {% load static %} +{% load swh_templatetags %} {% block header %} {% render_bundle 'add_forge' %} @@ -116,6 +117,6 @@ {% endblock %}