Skip to content
Closed
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
4 changes: 2 additions & 2 deletions app/lib/frontend/handlers/pubapi.client.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions app/lib/frontend/handlers/pubapi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -584,8 +584,7 @@ class PubApi {
listAdvisoriesForPackage(request, package);

@EndPoint.post('/api/report')
Future<Message> postReport(Request request, ReportForm body) async {
final message = await processReportPageHandler(request, body);
return Message(message: message);
Future<FormResponse> postReport(Request request, ReportForm body) async {
return await processReportPageHandler(request, body);
}
}
32 changes: 30 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 Down Expand Up @@ -35,6 +36,23 @@ Future<shelf.Response> reportPageHandler(shelf.Request request) async {
return notFoundHandler(request);
}

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 Down Expand Up @@ -134,7 +152,7 @@ Future<void> _verifyCaseSubject(
}

/// Handles POST /api/report
Future<String> processReportPageHandler(
Future<FormResponse> processReportPageHandler(
shelf.Request request, ReportForm form) async {
if (!requestContext.experimentalFlags.isReportPageEnabled) {
throw NotFoundException('Experimental flag is not enabled.');
Expand Down Expand Up @@ -234,5 +252,15 @@ Future<String> processReportPageHandler(
bodyText: bodyText,
));

return 'The $kind was submitted successfully.';
final redirectTo = request.requestedUri.replace(
path: '/report',
queryParameters: {
'feedback': '$kind-submitted',
},
).toString();

return FormResponse(
message: null, // no modal feedback
redirectTo: redirectTo,
);
}
16 changes: 16 additions & 0 deletions app/lib/frontend/templates/report.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@ 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,
Expand Down
17 changes: 17 additions & 0 deletions pkg/_pub_shared/lib/data/package_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,23 @@ class Message {
Map<String, dynamic> toJson() => _$MessageToJson(this);
}

/// A message wrapper for pub client API compatibility.
@JsonSerializable(includeIfNull: false)
class FormResponse {
final String? message;
final String? redirectTo;

FormResponse({
required this.message,
required this.redirectTo,
});

factory FormResponse.fromJson(Map<String, dynamic> json) =>
_$FormResponseFromJson(json);

Map<String, dynamic> toJson() => _$FormResponseToJson(this);
}

/// Used in `pub` client for finding which versions exist.
/// (`listVersions` method in pubapi)
@JsonSerializable(includeIfNull: false)
Expand Down
19 changes: 19 additions & 0 deletions pkg/_pub_shared/lib/data/package_api.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pkg/_pub_shared/lib/src/pubapi.client.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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
22 changes: 17 additions & 5 deletions pkg/web_app/lib/src/admin_pages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,23 @@ 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.'));
window.location.reload();
onSuccess: (r) async {
final result = r ?? <String, dynamic>{};
final redirectTo = result['redirectTo']?.toString();

// We shall display a minimal feedback when both the redirect and the message is omitted.
final message = result['message']?.toString() ??
(redirectTo == null ? 'Success. The page will reload.' : null);

if (message != null) {
await modalMessage('Success', text(message));
}

if (redirectTo != null) {
window.location.href = redirectTo;
} else {
window.location.reload();
}
},
);
});
Expand Down