diff --git a/assets/src/bundles/add_forge/index.js b/assets/src/bundles/add_forge/index.js --- a/assets/src/bundles/add_forge/index.js +++ b/assets/src/bundles/add_forge/index.js @@ -9,3 +9,4 @@ export * from './create-request'; export * from './moderation-dashboard'; +export * from './request-dashboard'; diff --git a/assets/src/bundles/add_forge/request-dashboard.js b/assets/src/bundles/add_forge/request-dashboard.js new file mode 100644 --- /dev/null +++ b/assets/src/bundles/add_forge/request-dashboard.js @@ -0,0 +1,124 @@ +/** + * 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 {handleFetchError, csrfPost} from 'utils/functions'; + +export function onRequestDashboardLoad(requestId) { + $(document).ready(() => { + populateRequestDetails(requestId); + + $('#contactForgeAdmin').click((event) => { + contactForgeAdmin(event); + }); + + $('#updateRequestForm').submit(async function(event) { + event.preventDefault(); + try { + const response = await csrfPost($(this).attr('action'), + {'Content-Type': 'application/x-www-form-urlencoded'}, + $(this).serialize()); + handleFetchError(response); + $('#userMessage').text('The request status has been updated '); + $('#userMessage').removeClass('badge-danger'); + $('#userMessage').addClass('badge-success'); + populateRequestDetails(requestId); + } catch (response) { + // const responseText = await response.json(); + $('#userMessage').text('Sorry; Updating the request failed'); + $('#userMessage').removeClass('badge-success'); + $('#userMessage').addClass('badge-danger'); + } + }); + }); +} + +async function populateRequestDetails(requestId) { + try { + const response = await fetch(Urls.api_1_add_forge_request_get(requestId)); + handleFetchError(response); + const data = await response.json(); + $('#requestStatus').text(data.request.status); + $('#requestType').text(data.request.forge_type); + $('#requestURL').text(data.request.forge_url); + $('#requestEmail').text(data.request.forge_contact_email); + // FIXME, set the correct email address in send button + // $('#requestEmail').(data.request.forge_contact_email); + populateRequestHistory(data.history); + populateDecisionSelectOption(data.request.status); + } catch (response) { + $('#fetchError').removeClass('d-none'); + $('#requestDetails').addClass('d-none'); + } +} + +function populateRequestHistory(history) { + history.forEach((each) => { + $('#swh-request-history').append( + `
  • + On ${each.date} by ${each.actor} (${each.actor_role}) + New status: ${each.new_status}
  • ` + ); + }); +} + +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'], + 'DENIED': [] + }; + + const statusLabel = { + 'PENDING': 'pending', + 'WAITING_FOR_FEEDBACK': 'waiting for feedback', + 'FEEDBACK_TO_HANDLE': 'feedback to handle', + 'ACCEPTED': 'accepted', + 'SCHEDULED': 'scheduled', + 'FIRST_LISTING_DONE': 'first listing done', + 'FIRST_ORIGIN_LOADED': 'first origin loaded', + 'REJECTED': 'rejected', + 'SUSPENDED': 'suspended', + 'DENIED': 'denied' + }; + + // Determine the possible next status out of the current one + const nextStatuses = nextStatusesFor[currentStatus]; + + function addStatusOption(status, index) { + // Push the next possible status option + const label = statusLabel[status]; + $('#decisionOptions').append( + `` + ); + } + // Remove all the options and add ones + $('#decisionOptions').children().remove(); + nextStatuses.forEach(addStatusOption); +} + +function contactForgeAdmin(event) { + // Open the mailclient with pre-filled text + const mailTo = $('#contactForgeAdmin').attr('emailTo'); + const subject = $('#contactForgeAdmin').attr('emailSubject'); + const emailText = $('#swh-input-forge-comment').val(); + window.location = `mailto: ${mailTo}?subject=${subject}&body=${emailText}`; +} diff --git a/cypress/fixtures/add-forge-now-request.json b/cypress/fixtures/add-forge-now-request.json new file mode 100644 --- /dev/null +++ b/cypress/fixtures/add-forge-now-request.json @@ -0,0 +1,23 @@ +{ + "request":{ + "id":1, + "status":"PENDING", + "submission_date":"2022-03-17T13:35:24.324848Z", + "submitter_name":"admin", + "submitter_email":"admin@swh-web.org", + "forge_type":"bitbucket", + "forge_url":"test.com", + "forge_contact_email":"test@example.com", + "forge_contact_name":"test user", + "forge_contact_comment":"test comment" + },"history":[ + { + "id":1, + "text":"", + "actor":"admin", + "actor_role":"SUBMITTER", + "date":"2022-03-17T13:35:24.326190Z", + "new_status":"PENDING" + } + ] +} diff --git a/cypress/integration/add-forge-now-request-dashboard.spec.js b/cypress/integration/add-forge-now-request-dashboard.spec.js new file mode 100644 --- /dev/null +++ b/cypress/integration/add-forge-now-request-dashboard.spec.js @@ -0,0 +1,86 @@ +/** + * 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 + */ + +const requestId = 1; + +describe('Test add forge now request dashboard load', function() { + + beforeEach(function() { + const url = this.Urls.add_forge_now_request_dashboard(requestId); + cy.adminLogin(); + cy.intercept(`${this.Urls.api_1_add_forge_request_get(requestId)}**`, + {fixture: 'add-forge-now-request'}).as('forgeAddRequest'); + cy.visit(url); + }); + + // it('should not let non moderator access page', function() { + // cy.userLogin(); + // cy.visit(this.Urls.add_forge_now_request_dashboard(requestId)); + // }); + + it('should load add forge request details', function() { + cy.wait('@forgeAddRequest'); + cy.get('#requestStatus') + .should('contain', 'PENDING'); + + cy.get('#requestType') + .should('contain', 'bitbucket'); + + cy.get('#requestURL') + .should('contain', 'test.com'); + + cy.get('#requestEmail') + .should('contain', 'test@example.com'); + }); + + it('should not show any error message', function() { + cy.get('#fetchError') + .should('have.class', 'd-none'); + cy.get('#requestDetails') + .should('not.have.class', 'd-none'); + }); + + it('should show error message for an api error', function() { + const invalidRequestId = 2; + const url = this.Urls.add_forge_now_request_dashboard(invalidRequestId); + cy.visit(url); + cy.get('#fetchError') + .should('not.have.class', 'd-none'); + cy.get('#requestDetails') + .should('have.class', 'd-none'); + }); + + it('should load add forge request history', function() { + cy.get('#swh-request-history') + .children() + .should('have.length', 1); + + cy.get('#swh-request-history') + .children() + .should('contain', 'New status: PENDING'); + }); + + // it('should load right email template ', function() { + // }); + + // it('should open mailclient with right text', function() { + // // make sure the email address is right + // }); + + it('should load possible next status', function() { + // 3 possible status for a request in pending state + cy.get('#decisionOptions') + .children() + .should('have.length', 3); + }); + + it('should update the forge request', function() { + }); + + it('should update change the request details', function() { + }); +}); 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 @@ -28,3 +28,17 @@ "add_forge_now/requests-moderation.html", {"heading": "Add forge now requests moderation"}, ) + + +@admin_route( + r"add-forge/request/(?P.+)/", + view_name="add-forge-now-request-dashboard", +) +@user_passes_test(_can_access_moderation, login_url=settings.LOGIN_URL) +def add_forge_now_request_dashboard(request, request_id): + """Moderation dashboard to allow listing current requests. + + """ + return render( + request, "add_forge_now/request-dashboard.html", {"request_id": request_id}, + ) diff --git a/swh/web/templates/add_forge_now/request-dashboard.html b/swh/web/templates/add_forge_now/request-dashboard.html new file mode 100644 --- /dev/null +++ b/swh/web/templates/add_forge_now/request-dashboard.html @@ -0,0 +1,137 @@ +{% extends "../layout.html" %} + +{% comment %} +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 +{% endcomment %} + +{% load render_bundle from webpack_loader %} +{% load static %} + +{% block header %} +{% render_bundle 'add_forge' %} +{% endblock %} + +{% block title %}Add forge request – Software Heritage archive{% endblock %} + +{% block navbar-content %} +

    Add forge now request dashboard

    + +{% endblock %} + +{% block content %} +
    +
    +
    +

    Error fetching information about the request

    +
    +
    +
    +
    +
    + Request Info +
    +
      +
    • +
      +
      Status
      +
      + +
    • +
    • +
      +
      Type
      +
      + +
    • +
    • +
      +
      Forge URL
      +
      + +
    • +
    • +
      +
      Forge contact email
      +
      + +
    • +
    +
    +
    +
    +
    +
    + Request History +
    +
      +
    +
    +
    + +
    +
    + Message Forge administrator (Editable) +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + {% csrf_token %} +
    +
    + + +
    +
    + +
    +
    + + + + Enter any comment related to your decision. + +
    +
    +
    + +
    + +
    +
    +

    + +

    +
    +
    +
    +
    +
    +
    +
    +
    + + +{% endblock %}