From 9e270b6e45399878e07f676944b5a07d07aace39 Mon Sep 17 00:00:00 2001 From: Istvan Soos Date: Thu, 29 Aug 2024 14:00:56 +0200 Subject: [PATCH] Form redirect + redirecting on report/appeal submission. --- app/lib/frontend/handlers/pubapi.dart | 3 +- app/lib/frontend/handlers/report.dart | 31 +++++++++++++++++-- app/lib/frontend/templates/report.dart | 18 +++++++++++ app/test/frontend/golden/report_page.html | 2 +- .../frontend/golden/report_page_appeal.html | 2 +- app/test/frontend/templates_test.dart | 2 ++ pkg/pub_integration/test/report_test.dart | 15 +++++---- pkg/web_app/lib/src/admin_pages.dart | 18 ++++++++--- 8 files changed, 73 insertions(+), 18 deletions(-) diff --git a/app/lib/frontend/handlers/pubapi.dart b/app/lib/frontend/handlers/pubapi.dart index 90bb03779..63a70971f 100644 --- a/app/lib/frontend/handlers/pubapi.dart +++ b/app/lib/frontend/handlers/pubapi.dart @@ -585,7 +585,6 @@ class PubApi { @EndPoint.post('/api/report') Future postReport(Request request, ReportForm body) async { - final message = await processReportPageHandler(request, body); - return Message(message: message); + return await processReportPageHandler(request, body); } } diff --git a/app/lib/frontend/handlers/report.dart b/app/lib/frontend/handlers/report.dart index 3a3c73c71..13578e5f5 100644 --- a/app/lib/frontend/handlers/report.dart +++ b/app/lib/frontend/handlers/report.dart @@ -5,6 +5,7 @@ import 'dart:async'; import 'package:_pub_shared/data/account_api.dart'; +import 'package:_pub_shared/data/package_api.dart'; import 'package:clock/clock.dart'; import 'package:pub_dev/admin/backend.dart'; import 'package:pub_dev/shared/configuration.dart'; @@ -31,6 +32,23 @@ const _reportRateLimitWindowAsText = 'last 10 minutes'; /// Handles GET /report Future reportPageHandler(shelf.Request request) async { + final feedback = request.requestedUri.queryParameters['feedback']; + if (feedback != null) { + switch (feedback) { + case 'report-submitted': + return htmlResponse(renderReportFeedback( + title: 'Report submitted', + message: 'The report has been submitted successfully.', + )); + case 'appeal-submitted': + return htmlResponse(renderReportFeedback( + title: 'Appeal submitted', + message: 'The appeal has been submitted successfully.', + )); + } + return notFoundHandler(request); + } + final caseId = request.requestedUri.queryParameters['appeal']; final mc = await _loadAndVerifyCase(caseId); @@ -47,12 +65,21 @@ Future reportPageHandler(shelf.Request request) async { final url = request.requestedUri.queryParameters['url']; _verifyUrl(url); + final kind = caseId == null ? 'report' : 'appeal'; + final onSuccessGotoUrl = request.requestedUri.replace( + path: '/report', + queryParameters: { + 'feedback': '$kind-submitted', + }, + ).toString(); + return htmlResponse( renderReportPage( sessionData: requestContext.sessionData, subject: subject, url: url, caseId: caseId, + onSuccessGotoUrl: onSuccessGotoUrl, ), headers: CacheControl.explicitlyPrivate.headers, ); @@ -130,7 +157,7 @@ Future _verifyCaseSubject( } /// Handles POST /api/report -Future processReportPageHandler( +Future processReportPageHandler( shelf.Request request, ReportForm form) async { final sourceIp = request.sourceIp; if (sourceIp != null) { @@ -226,5 +253,5 @@ Future processReportPageHandler( bodyText: bodyText, )); - return 'The $kind was submitted successfully.'; + return Message(message: 'The $kind was submitted successfully.'); } diff --git a/app/lib/frontend/templates/report.dart b/app/lib/frontend/templates/report.dart index cacad00eb..da27197ae 100644 --- a/app/lib/frontend/templates/report.dart +++ b/app/lib/frontend/templates/report.dart @@ -16,12 +16,29 @@ const _subjectKindLabels = { ModerationSubjectKind.publisher: 'publisher', }; +/// Renders the feedback page with a simple paragraph of [message]. +String renderReportFeedback({ + required String title, + required String message, +}) { + return renderLayoutPage( + PageType.standalone, + d.fragment([ + d.h1(text: title), + d.p(text: message), + ]), + title: title, + noIndex: true, + ); +} + /// Renders the create publisher page. String renderReportPage({ SessionData? sessionData, required ModerationSubject subject, required String? url, required String? caseId, + required String onSuccessGotoUrl, }) { final isAppeal = caseId != null; final title = isAppeal ? 'Appeal a resolution' : 'Report a problem'; @@ -33,6 +50,7 @@ String renderReportPage({ id: 'report-page-form', attributes: { 'data-form-api-endpoint': '/api/report', + 'data-form-success-goto': onSuccessGotoUrl, }, children: [ d.input(type: 'hidden', name: 'subject', value: subject.fqn), diff --git a/app/test/frontend/golden/report_page.html b/app/test/frontend/golden/report_page.html index 5dec14c06..4030cb31e 100644 --- a/app/test/frontend/golden/report_page.html +++ b/app/test/frontend/golden/report_page.html @@ -107,7 +107,7 @@

-
+

Report a problem

diff --git a/app/test/frontend/golden/report_page_appeal.html b/app/test/frontend/golden/report_page_appeal.html index 956b34047..ab77ad2b2 100644 --- a/app/test/frontend/golden/report_page_appeal.html +++ b/app/test/frontend/golden/report_page_appeal.html @@ -107,7 +107,7 @@

-
+

Appeal a resolution

diff --git a/app/test/frontend/templates_test.dart b/app/test/frontend/templates_test.dart index 893fa9f0c..b366c7fc9 100644 --- a/app/test/frontend/templates_test.dart +++ b/app/test/frontend/templates_test.dart @@ -818,6 +818,7 @@ void main() { subject: ModerationSubject.package('oxygen'), url: 'https://pub.dev/packages/oxygen/example', caseId: null, + onSuccessGotoUrl: 'https://pub.dev/report?feedback=report-submitted', ); expectGoldenFile(html, 'report_page.html'); }); @@ -830,6 +831,7 @@ void main() { subject: ModerationSubject.package('oxygen'), url: null, caseId: 'fake-case-id', + onSuccessGotoUrl: 'https://pub.dev/report?feedback=appeal-submitted', ); expectGoldenFile(html, 'report_page_appeal.html'); }); diff --git a/pkg/pub_integration/test/report_test.dart b/pkg/pub_integration/test/report_test.dart index 2334ba263..d9cb54e76 100644 --- a/pkg/pub_integration/test/report_test.dart +++ b/pkg/pub_integration/test/report_test.dart @@ -65,10 +65,10 @@ void main() { await page.waitFocusAndType('#report-email', 'reporter@pub.dev'); await page.waitFocusAndType( '#report-message', 'Huston, we have a problem.'); - await page.waitAndClick('#report-submit', waitForOneResponse: true); - expect(await page.content, - contains('The report was submitted successfully.')); - await page.waitAndClickOnDialogOk(); + await page.waitAndClick('#report-submit'); + await page.waitForNavigation(); + expect( + await page.content, contains('has been submitted successfully')); }, ); @@ -197,10 +197,9 @@ void main() { await page.waitFocusAndType( '#report-message', 'Huston, I have a different idea.'); - await page.waitAndClick('#report-submit', waitForOneResponse: true); - expect(await page.content, - contains('The appeal was submitted successfully.')); - await page.waitAndClickOnDialogOk(); + await page.waitAndClick('#report-submit'); + await page.waitForNavigation(); + expect(await page.content, contains('has been submitted successfully')); }); final appealEmail = await supportUser.readLatestEmail(); diff --git a/pkg/web_app/lib/src/admin_pages.dart b/pkg/web_app/lib/src/admin_pages.dart index 1f6773383..f1c019f5c 100644 --- a/pkg/web_app/lib/src/admin_pages.dart +++ b/pkg/web_app/lib/src/admin_pages.dart @@ -31,6 +31,7 @@ void initAdminPages() { void _initGenericForm() { for (final form in document.querySelectorAll('[data-form-api-endpoint]')) { final endpoint = form.dataset['form-api-endpoint']!; + final onSuccessGotoUrl = form.dataset['form-success-goto']; for (final button in form.querySelectorAll('[data-form-api-button]')) { button.onClick.listen((event) async { @@ -52,10 +53,19 @@ void _initGenericForm() { fn: () => api_client.sendJson(verb: 'POST', path: endpoint, body: body), successMessage: null, - onSuccess: (result) async { - final message = - result == null ? null : result['message']?.toString(); - await modalMessage('Success', text(message ?? 'OK.')); + onSuccess: (r) async { + final result = r ?? {}; + // Goto a new location to display the feedback message. + if (onSuccessGotoUrl != null) { + window.location.href = onSuccessGotoUrl; + return; + } + + // We shall display a minimal feedback the message is omitted. + final message = result['message']?.toString() ?? + 'Success. The page will reload.'; + await modalMessage('Success', text(message)); + window.location.reload(); }, );