Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions app/lib/frontend/handlers/pubapi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,6 @@ class PubApi {

@EndPoint.post('/api/report')
Future<Message> postReport(Request request, ReportForm body) async {
final message = await processReportPageHandler(request, body);
return Message(message: message);
return await processReportPageHandler(request, body);
}
}
31 changes: 29 additions & 2 deletions app/lib/frontend/handlers/report.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -31,6 +32,23 @@ const _reportRateLimitWindowAsText = 'last 10 minutes';

/// Handles GET /report
Future<shelf.Response> 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);

Expand All @@ -47,12 +65,21 @@ Future<shelf.Response> 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,
);
Expand Down Expand Up @@ -130,7 +157,7 @@ Future<void> _verifyCaseSubject(
}

/// Handles POST /api/report
Future<String> processReportPageHandler(
Future<Message> processReportPageHandler(
shelf.Request request, ReportForm form) async {
final sourceIp = request.sourceIp;
if (sourceIp != null) {
Expand Down Expand Up @@ -226,5 +253,5 @@ Future<String> processReportPageHandler(
bodyText: bodyText,
));

return 'The $kind was submitted successfully.';
return Message(message: 'The $kind was submitted successfully.');
}
18 changes: 18 additions & 0 deletions app/lib/frontend/templates/report.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion app/test/frontend/golden/report_page.html
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ <h3 class="foldable-button">
<div id="banner-container"></div>
<main class="container">
<div class="report-main">
<div id="report-page-form" data-form-api-endpoint="/api/report">
<div id="report-page-form" data-form-api-endpoint="/api/report" data-form-success-goto="https://pub.dev/report?feedback=report-submitted">
<input type="hidden" name="subject" value="package:oxygen"/>
<input type="hidden" name="url" value="https://pub.dev/packages/oxygen/example"/>
<h1>Report a problem</h1>
Expand Down
2 changes: 1 addition & 1 deletion app/test/frontend/golden/report_page_appeal.html
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ <h3 class="foldable-button">
<div id="banner-container"></div>
<main class="container">
<div class="report-main">
<div id="report-page-form" data-form-api-endpoint="/api/report">
<div id="report-page-form" data-form-api-endpoint="/api/report" data-form-success-goto="https://pub.dev/report?feedback=appeal-submitted">
<input type="hidden" name="subject" value="package:oxygen"/>
<input type="hidden" name="caseId" value="fake-case-id"/>
<h1>Appeal a resolution</h1>
Expand Down
2 changes: 2 additions & 0 deletions app/test/frontend/templates_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});
Expand All @@ -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');
});
Expand Down
15 changes: 7 additions & 8 deletions pkg/pub_integration/test/report_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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'));
},
);

Expand Down Expand Up @@ -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();
Expand Down
18 changes: 14 additions & 4 deletions pkg/web_app/lib/src/admin_pages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 ?? <String, dynamic>{};
// 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();
},
);
Expand Down