Skip to content

Commit c95ec11

Browse files
committed
Export more package API endpoints.
1 parent 691a8fd commit c95ec11

File tree

9 files changed

+170
-52
lines changed

9 files changed

+170
-52
lines changed

app/lib/frontend/handlers/custom_api.dart

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import '../../scorecard/backend.dart';
2121
import '../../search/backend.dart';
2222
import '../../search/search_client.dart';
2323
import '../../search/search_service.dart';
24-
import '../../service/download_counts/backend.dart';
2524
import '../../service/topics/count_topics.dart';
2625
import '../../shared/configuration.dart';
2726
import '../../shared/exceptions.dart';
@@ -218,38 +217,7 @@ Future<VersionScore> packageVersionScoreHandler(
218217
{String? version}) async {
219218
checkPackageVersionParams(package, version);
220219
return (await cache.versionScore(package, version).get(() async {
221-
final pkg = await packageBackend.lookupPackage(package);
222-
if (pkg == null) {
223-
throw NotFoundException.resource('package "$package"');
224-
}
225-
final v =
226-
(version == null || version == 'latest') ? pkg.latestVersion! : version;
227-
final pv = await packageBackend.lookupPackageVersion(package, v);
228-
if (pv == null) {
229-
throw NotFoundException.resource('package "$package" version "$version"');
230-
}
231-
232-
var updated = pkg.updated;
233-
final card = await scoreCardBackend.getScoreCardData(package, v);
234-
if (updated == null || card.updated?.isAfter(updated) == true) {
235-
updated = card.updated;
236-
}
237-
238-
final tags = <String>{
239-
...pkg.getTags(),
240-
...pv.getTags(),
241-
...?card.derivedTags,
242-
};
243-
244-
return VersionScore(
245-
grantedPoints: card.grantedPubPoints,
246-
maxPoints: card.maxPubPoints,
247-
likeCount: pkg.likes,
248-
downloadCount30Days:
249-
downloadCountsBackend.lookup30DaysTotalCounts(package),
250-
tags: tags.toList(),
251-
lastUpdated: updated,
252-
);
220+
return await scoreCardBackend.getVersionScore(package, version: version);
253221
}))!;
254222
}
255223

@@ -475,15 +443,7 @@ Future<PkgOptions> getPackageOptionsHandler(
475443
shelf.Request request,
476444
String package,
477445
) async {
478-
checkPackageVersionParams(package);
479-
final p = await packageBackend.lookupPackage(package);
480-
if (p == null) {
481-
throw NotFoundException.resource(package);
482-
}
483-
return PkgOptions(
484-
isDiscontinued: p.isDiscontinued,
485-
isUnlisted: p.isUnlisted,
486-
);
446+
return await packageBackend.getPackageOptions(package);
487447
}
488448

489449
/// Handles `PUT /api/packages/<package>/options`.

app/lib/package/api_export/api_exporter.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:gcloud/service_scope.dart' as ss;
1010
import 'package:gcloud/storage.dart';
1111
import 'package:logging/logging.dart';
1212
import 'package:pub_dev/frontend/handlers/atom_feed.dart';
13+
import 'package:pub_dev/scorecard/backend.dart';
1314
import 'package:pub_dev/service/security_advisories/backend.dart';
1415
import 'package:pub_dev/shared/exceptions.dart';
1516
import 'package:pub_dev/shared/parallel_foreach.dart';
@@ -244,6 +245,22 @@ final class ApiExporter {
244245
versionListing,
245246
forceWrite: forceWrite,
246247
);
248+
await _api.package(package).likes.write(
249+
await packageBackend.getPackageLikesCount(package),
250+
forceWrite: forceWrite,
251+
);
252+
await _api.package(package).options.write(
253+
await packageBackend.getPackageOptions(package),
254+
forceWrite: forceWrite,
255+
);
256+
await _api.package(package).publisher.write(
257+
await packageBackend.getPublisherInfo(package),
258+
forceWrite: forceWrite,
259+
);
260+
await _api.package(package).score.write(
261+
await scoreCardBackend.getVersionScore(package),
262+
forceWrite: forceWrite,
263+
);
247264
await _api.package(package).feedAtomFile.write(
248265
await buildPackageAtomFeedContent(package),
249266
forceWrite: forceWrite,

app/lib/package/api_export/exported_api.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'dart:async';
66
import 'dart:convert';
77
import 'dart:io';
88

9+
import 'package:_pub_shared/data/account_api.dart';
910
import 'package:_pub_shared/data/advisories_api.dart';
1011
import 'package:_pub_shared/data/package_api.dart';
1112
import 'package:clock/clock.dart';
@@ -273,6 +274,20 @@ final class ExportedPackage {
273274
ExportedJsonFile<ListAdvisoriesResponse> get advisories =>
274275
_suffix<ListAdvisoriesResponse>('/advisories');
275276

277+
/// Interface for writing `/api/packages/<package>/likes`.
278+
ExportedJsonFile<PackageLikesCount> get likes =>
279+
_suffix<PackageLikesCount>('/likes');
280+
281+
/// Interface for writing `/api/packages/<package>/options`.
282+
ExportedJsonFile<PkgOptions> get options => _suffix<PkgOptions>('/options');
283+
284+
/// Interface for writing `/api/packages/<package>/publisher`.
285+
ExportedJsonFile<PackagePublisherInfo> get publisher =>
286+
_suffix<PackagePublisherInfo>('/publisher');
287+
288+
/// Interface for writing `/api/packages/<package>/score`.
289+
ExportedJsonFile<VersionScore> get score => _suffix<VersionScore>('/score');
290+
276291
/// Interface for writing `/api/packages/<package>/feed.atom`
277292
ExportedAtomFeedFile get feedAtomFile => ExportedAtomFeedFile._(
278293
_owner,
@@ -406,6 +421,10 @@ final class ExportedPackage {
406421
await Future.wait([
407422
_owner._pool.withResource(() async => await versions.delete()),
408423
_owner._pool.withResource(() async => await advisories.delete()),
424+
_owner._pool.withResource(() async => await likes.delete()),
425+
_owner._pool.withResource(() async => await options.delete()),
426+
_owner._pool.withResource(() async => await publisher.delete()),
427+
_owner._pool.withResource(() async => await score.delete()),
409428
_owner._pool.withResource(() async => await feedAtomFile.delete()),
410429
..._owner._prefixes.map((prefix) async {
411430
await _owner._listBucket(

app/lib/package/backend.dart

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import 'package:meta/meta.dart';
1818
import 'package:pool/pool.dart';
1919
import 'package:pub_dev/package/api_export/api_exporter.dart';
2020
import 'package:pub_dev/package/tarball_storage.dart';
21+
import 'package:pub_dev/scorecard/backend.dart';
2122
import 'package:pub_dev/service/async_queue/async_queue.dart';
2223
import 'package:pub_dev/service/rate_limit/rate_limit.dart';
2324
import 'package:pub_dev/shared/versions.dart';
@@ -419,6 +420,20 @@ class PackageBackend {
419420
return count;
420421
}
421422

423+
/// Returns the package options.
424+
Future<api.PkgOptions> getPackageOptions(String package) async {
425+
checkPackageVersionParams(package);
426+
final p = await packageBackend.lookupPackage(package);
427+
if (p == null) {
428+
throw NotFoundException.resource(package);
429+
}
430+
return api.PkgOptions(
431+
isDiscontinued: p.isDiscontinued,
432+
replacedBy: p.replacedBy,
433+
isUnlisted: p.isUnlisted,
434+
);
435+
}
436+
422437
/// Updates [options] on [package].
423438
Future<void> updateOptions(String package, api.PkgOptions options) async {
424439
final authenticatedUser = await requireAuthenticatedWebUser();
@@ -479,6 +494,7 @@ class PackageBackend {
479494
});
480495
await purgePackageCache(package);
481496
await taskBackend.trackPackage(package);
497+
await apiExporter!.synchronizePackage(package);
482498
}
483499

484500
/// Updates [options] on [package]/[version], assuming the current user
@@ -517,6 +533,9 @@ class PackageBackend {
517533
}
518534
});
519535
await purgePackageCache(package);
536+
await purgeScorecardData(package, version,
537+
isLatest: pkg.latestVersion == version);
538+
await apiExporter!.synchronizePackage(package);
520539
}
521540

522541
/// Verifies an update to the credential-less publishing settings and
@@ -781,7 +800,7 @@ class PackageBackend {
781800
if (currentPublisherId != null) {
782801
await purgePublisherCache(publisherId: currentPublisherId);
783802
}
784-
803+
await apiExporter!.synchronizePackage(packageName);
785804
return rs;
786805
}
787806

app/lib/scorecard/backend.dart

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
import 'dart:async';
66

7+
import 'package:_pub_shared/data/package_api.dart';
78
import 'package:clock/clock.dart';
89
import 'package:gcloud/service_scope.dart' as ss;
910
import 'package:logging/logging.dart';
1011
import 'package:meta/meta.dart';
1112
import 'package:pool/pool.dart';
13+
import 'package:pub_dev/service/download_counts/backend.dart';
1214
import 'package:pub_dev/service/download_counts/computations.dart';
1315
import 'package:pub_dev/shared/exceptions.dart';
1416
import 'package:pub_dev/task/backend.dart';
@@ -186,6 +188,43 @@ class ScoreCardBackend {
186188
final pv = list[1] as PackageVersion?;
187189
return PackageStatus.fromModels(p, pv);
188190
}
191+
192+
/// Return the version score object served in the API.
193+
Future<VersionScore> getVersionScore(String package,
194+
{String? version}) async {
195+
final pkg = await packageBackend.lookupPackage(package);
196+
if (pkg == null) {
197+
throw NotFoundException.resource('package "$package"');
198+
}
199+
final v =
200+
(version == null || version == 'latest') ? pkg.latestVersion! : version;
201+
final pv = await packageBackend.lookupPackageVersion(package, v);
202+
if (pv == null) {
203+
throw NotFoundException.resource('package "$package" version "$version"');
204+
}
205+
206+
var updated = pkg.updated;
207+
final card = await scoreCardBackend.getScoreCardData(package, v);
208+
if (updated == null || card.updated?.isAfter(updated) == true) {
209+
updated = card.updated;
210+
}
211+
212+
final tags = <String>{
213+
...pkg.getTags(),
214+
...pv.getTags(),
215+
...?card.derivedTags,
216+
};
217+
218+
return VersionScore(
219+
grantedPoints: card.grantedPubPoints,
220+
maxPoints: card.maxPubPoints,
221+
likeCount: pkg.likes,
222+
downloadCount30Days:
223+
downloadCountsBackend.lookup30DaysTotalCounts(package),
224+
tags: tags.toList(),
225+
lastUpdated: updated,
226+
);
227+
}
189228
}
190229

191230
Future<void> purgeScorecardData(

app/lib/task/backend.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import 'package:indexed_blob/indexed_blob.dart' show BlobIndex, FileRange;
1818
import 'package:logging/logging.dart' show Logger;
1919
import 'package:pana/models.dart' show Summary;
2020
import 'package:pool/pool.dart' show Pool;
21+
import 'package:pub_dev/package/api_export/api_exporter.dart';
2122
import 'package:pub_dev/package/backend.dart';
2223
import 'package:pub_dev/package/models.dart';
2324
import 'package:pub_dev/package/upload_signer_service.dart';
@@ -721,6 +722,7 @@ class TaskBackend {
721722

722723
// Clearing the state cache after the update.
723724
await _purgeCache(package, version);
725+
await apiExporter!.synchronizePackage(package);
724726

725727
// If nothing else is running on the instance, delete it!
726728
// We do this in a microtask after returning, so that it doesn't slow down

app/test/admin/exported_api_sync_test.dart

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ void main() {
7171
testWithProfile('baseline checks', fn: () async {
7272
await syncExportedApi();
7373
final data = await listExportedApi();
74-
expect(data.keys, hasLength(greaterThan(20)));
75-
expect(data.keys, hasLength(lessThan(40)));
74+
expect(data.keys, hasLength(greaterThan(50)));
75+
expect(data.keys, hasLength(lessThan(70)));
7676

7777
final oxygenFiles = data.keys.where((k) => k.contains('oxygen')).toSet();
7878
expect(oxygenFiles, hasLength(greaterThan(5)));
@@ -82,12 +82,20 @@ void main() {
8282
'$runtimeVersion/api/archives/oxygen-2.0.0-dev.tar.gz',
8383
'$runtimeVersion/api/packages/oxygen',
8484
'$runtimeVersion/api/packages/oxygen/advisories',
85+
'$runtimeVersion/api/packages/oxygen/likes',
86+
'$runtimeVersion/api/packages/oxygen/options',
87+
'$runtimeVersion/api/packages/oxygen/publisher',
88+
'$runtimeVersion/api/packages/oxygen/score',
8589
'$runtimeVersion/api/packages/oxygen/feed.atom',
8690
'latest/api/archives/oxygen-1.0.0.tar.gz',
8791
'latest/api/archives/oxygen-1.2.0.tar.gz',
8892
'latest/api/archives/oxygen-2.0.0-dev.tar.gz',
8993
'latest/api/packages/oxygen',
9094
'latest/api/packages/oxygen/advisories',
95+
'latest/api/packages/oxygen/likes',
96+
'latest/api/packages/oxygen/options',
97+
'latest/api/packages/oxygen/publisher',
98+
'latest/api/packages/oxygen/score',
9199
'latest/api/packages/oxygen/feed.atom',
92100
});
93101

0 commit comments

Comments
 (0)