diff --git a/app/lib/admin/actions/actions.dart b/app/lib/admin/actions/actions.dart index dc3a460f7..833ea85fa 100644 --- a/app/lib/admin/actions/actions.dart +++ b/app/lib/admin/actions/actions.dart @@ -17,10 +17,13 @@ import 'moderation_case_info.dart'; import 'moderation_case_list.dart'; import 'moderation_case_resolve.dart'; import 'moderation_case_update.dart'; +import 'package_info.dart'; +import 'package_version_info.dart'; import 'package_version_retraction.dart'; import 'publisher_block.dart'; import 'publisher_create.dart'; import 'publisher_delete.dart'; +import 'publisher_info.dart'; import 'publisher_members_list.dart'; import 'publisher_package_remove.dart'; import 'task_bump_priority.dart'; @@ -94,10 +97,13 @@ final class AdminAction { moderationCaseList, moderationCaseResolve, moderationCaseUpdate, + packageInfo, + packageVersionInfo, packageVersionRetraction, publisherBlock, publisherCreate, publisherDelete, + publisherInfo, publisherMembersList, publisherPackageRemove, taskBumpPriority, diff --git a/app/lib/admin/actions/package_info.dart b/app/lib/admin/actions/package_info.dart new file mode 100644 index 000000000..8b855260a --- /dev/null +++ b/app/lib/admin/actions/package_info.dart @@ -0,0 +1,42 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:pub_dev/package/backend.dart'; + +import 'actions.dart'; + +final packageInfo = AdminAction( + name: 'package-info', + summary: 'Gets the package information.', + description: ''' +Loads and displays the package information. +''', + options: { + 'package': 'The package to be loaded.', + }, + invoke: (options) async { + final package = options['package']; + InvalidInputException.check( + package != null && package.isNotEmpty, + '`package` must be given', + ); + + final p = await packageBackend.lookupPackage(package!); + if (p == null) { + throw NotFoundException.resource(package); + } + + return { + 'package': { + 'name': p.name, + 'created': p.created?.toIso8601String(), + 'publisherId': p.publisherId, + 'latestVersion': p.latestVersion, + 'isModerated': p.isModerated, + if (p.moderatedAt != null) + 'moderatedAt': p.moderatedAt?.toIso8601String(), + }, + }; + }, +); diff --git a/app/lib/admin/actions/package_version_info.dart b/app/lib/admin/actions/package_version_info.dart new file mode 100644 index 000000000..9ec24c1b1 --- /dev/null +++ b/app/lib/admin/actions/package_version_info.dart @@ -0,0 +1,48 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:pub_dev/package/backend.dart'; + +import 'actions.dart'; + +final packageVersionInfo = AdminAction( + name: 'package-version-info', + summary: 'Gets the package version information.', + description: ''' +Loads and displays the package version information. +''', + options: { + 'package': 'The package to be loaded.', + 'version': 'The version to be loaded.', + }, + invoke: (options) async { + final package = options['package']; + InvalidInputException.check( + package != null && package.isNotEmpty, + '`package` must be given', + ); + + final version = options['version']; + InvalidInputException.check( + version != null && version.isNotEmpty, + '`version` must be given', + ); + + final pv = await packageBackend.lookupPackageVersion(package!, version!); + if (pv == null) { + throw NotFoundException.resource('$package/$version'); + } + + return { + 'package-version': { + 'package': pv.package, + 'version': pv.version, + 'created': pv.created?.toIso8601String(), + 'isModerated': pv.isModerated, + if (pv.moderatedAt != null) + 'moderatedAt': pv.moderatedAt?.toIso8601String(), + }, + }; + }, +); diff --git a/app/lib/admin/actions/publisher_info.dart b/app/lib/admin/actions/publisher_info.dart new file mode 100644 index 000000000..f0418d6dd --- /dev/null +++ b/app/lib/admin/actions/publisher_info.dart @@ -0,0 +1,41 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:pub_dev/publisher/backend.dart'; + +import 'actions.dart'; + +final publisherInfo = AdminAction( + name: 'publisher-info', + summary: 'Gets the publisher information.', + description: ''' +Loads and displays the publisher information. +''', + options: { + 'publisher': 'The publisherId to be loaded.', + }, + invoke: (options) async { + final publisherId = options['publisher']; + InvalidInputException.check( + publisherId != null && publisherId.isNotEmpty, + '`publisher` must be given', + ); + + final p = await publisherBackend.getPublisher(publisherId!); + if (p == null) { + throw NotFoundException.resource(publisherId); + } + + return { + 'publisher': { + 'publisherId': p.publisherId, + 'created': p.created?.toIso8601String(), + 'contactEmail': p.contactEmail, + 'isModerated': p.isModerated, + if (p.moderatedAt != null) + 'moderatedAt': p.moderatedAt?.toIso8601String(), + }, + }; + }, +); diff --git a/app/test/admin/package_actions_test.dart b/app/test/admin/package_actions_test.dart new file mode 100644 index 000000000..a0b441742 --- /dev/null +++ b/app/test/admin/package_actions_test.dart @@ -0,0 +1,33 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:_pub_shared/data/admin_api.dart'; +import 'package:test/test.dart'; + +import '../shared/test_models.dart'; +import '../shared/test_services.dart'; + +void main() { + // TODO: move package-related tests from api_actions_test.dart + group('package admin actions', () { + testWithProfile('info request', fn: () async { + final client = createPubApiClient(authToken: siteAdminToken); + final rs = await client.adminInvokeAction( + 'package-info', + AdminInvokeActionArguments(arguments: { + 'package': 'oxygen', + }), + ); + expect(rs.output, { + 'package': { + 'name': 'oxygen', + 'created': isNotEmpty, + 'publisherId': null, + 'latestVersion': '1.2.0', + 'isModerated': false, + } + }); + }); + }); +} diff --git a/app/test/admin/package_version_actions_test.dart b/app/test/admin/package_version_actions_test.dart new file mode 100644 index 000000000..4b4d03655 --- /dev/null +++ b/app/test/admin/package_version_actions_test.dart @@ -0,0 +1,33 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:_pub_shared/data/admin_api.dart'; +import 'package:test/test.dart'; + +import '../shared/test_models.dart'; +import '../shared/test_services.dart'; + +void main() { + // TODO: move package-version-related tests from api_actions_test.dart + group('package version admin actions', () { + testWithProfile('info request', fn: () async { + final client = createPubApiClient(authToken: siteAdminToken); + final rs = await client.adminInvokeAction( + 'package-version-info', + AdminInvokeActionArguments(arguments: { + 'package': 'oxygen', + 'version': '1.2.0', + }), + ); + expect(rs.output, { + 'package-version': { + 'package': 'oxygen', + 'version': '1.2.0', + 'created': isNotEmpty, + 'isModerated': false, + } + }); + }); + }); +} diff --git a/app/test/admin/publisher_actions_test.dart b/app/test/admin/publisher_actions_test.dart new file mode 100644 index 000000000..d21ae36cb --- /dev/null +++ b/app/test/admin/publisher_actions_test.dart @@ -0,0 +1,32 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:_pub_shared/data/admin_api.dart'; +import 'package:test/test.dart'; + +import '../shared/test_models.dart'; +import '../shared/test_services.dart'; + +void main() { + // TODO: move publisher-related tests from api_actions_test.dart + group('publisher admin actions', () { + testWithProfile('info request', fn: () async { + final client = createPubApiClient(authToken: siteAdminToken); + final rs = await client.adminInvokeAction( + 'publisher-info', + AdminInvokeActionArguments(arguments: { + 'publisher': 'example.com', + }), + ); + expect(rs.output, { + 'publisher': { + 'publisherId': 'example.com', + 'created': isNotEmpty, + 'contactEmail': 'admin@pub.dev', + 'isModerated': false + }, + }); + }); + }); +}