feat(explore): take a later release into a copy, at a tap
A copy's top studyset says when a newer release of what it came from is out, and what it would bring: changed, new and withdrawn items, counted against the release the copy last took. Update takes it, never by itself (ADR 0005, rule 4): cards, notes and steps take the release as a revision on the one where they last took a release and merge per side, as a dictionary's corrections do, so what the learner changed stays and a side both changed is a conflict to settle; studysets, paths and PDFs take each field the learner left as it was. New items come in where they belong, unless the learner deleted that part; what the author withdrew stays, marked, and the card browser filters for it; what the learner deleted stays deleted; progress is never touched. The instance gives out any release by its version, for the app to compare the two. UpdateTaken moves into the shared revision merge, now that notes and steps take updates too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
f4af6cfd3a
commit
5613530f82
4 changed files with 2230 additions and 93 deletions
|
|
@ -101,11 +101,20 @@ class ExploreEndpoint extends Endpoint {
|
|||
);
|
||||
}
|
||||
|
||||
/// The latest release of the published studyset [publicId], to make a
|
||||
/// copy of or take into one. Throws [NotFoundException] for a studyset
|
||||
/// withdrawn or never published.
|
||||
Future<ReleaseContent> release(Session session, UuidValue publicId) async {
|
||||
final (:published, :version) = await _listed(session, publicId);
|
||||
/// Release [version] of the published studyset [publicId], else its
|
||||
/// latest: to make a copy of, or to take into one from the release it
|
||||
/// last took. Throws [NotFoundException] for a release that doesn't
|
||||
/// exist, or a studyset withdrawn or never published.
|
||||
Future<ReleaseContent> release(
|
||||
Session session,
|
||||
UuidValue publicId, {
|
||||
int? version,
|
||||
}) async {
|
||||
final (:published, version: latest) = await _listed(session, publicId);
|
||||
if (version != null && (version < 1 || version > latest)) {
|
||||
throw NotFoundException(what: 'release');
|
||||
}
|
||||
version ??= latest;
|
||||
final items = await repositoryOf(published.publicId).readJson(version);
|
||||
final files = switch (items['files.json']) {
|
||||
final String index => [
|
||||
|
|
|
|||
|
|
@ -559,6 +559,11 @@ class Endpoints extends _is.EndpointDispatch {
|
|||
type: _is.getType<_is.UuidValue>(),
|
||||
nullable: false,
|
||||
),
|
||||
'version': _is.ParameterDescription(
|
||||
name: 'version',
|
||||
type: _is.getType<int?>(),
|
||||
nullable: true,
|
||||
),
|
||||
},
|
||||
call:
|
||||
(
|
||||
|
|
@ -568,6 +573,7 @@ class Endpoints extends _is.EndpointDispatch {
|
|||
(endpoints['explore'] as _i897jtwc.ExploreEndpoint).release(
|
||||
session,
|
||||
params['publicId'],
|
||||
version: params['version'],
|
||||
),
|
||||
),
|
||||
'file': _is.MethodConnector(
|
||||
|
|
|
|||
|
|
@ -309,6 +309,34 @@ void main() {
|
|||
}
|
||||
});
|
||||
|
||||
test('gives out an older release, to take a newer one from', () async {
|
||||
final japanese = await studyset(alice, 'Japanese');
|
||||
await publish(alice, japanese, 'japanese');
|
||||
await addCard(alice, japanese);
|
||||
final published = await publish(alice, japanese, 'japanese');
|
||||
|
||||
Future<int> cardsIn(int? version) async =>
|
||||
(await endpoints.explore.release(
|
||||
anonymous,
|
||||
published.publicId,
|
||||
version: version,
|
||||
)).items.where((item) => item.path.startsWith('cards/')).length;
|
||||
expect(await cardsIn(1), 1);
|
||||
expect(await cardsIn(2), 2);
|
||||
expect(await cardsIn(null), 2);
|
||||
for (final version in [0, 3]) {
|
||||
await expectLater(
|
||||
endpoints.explore.release(
|
||||
anonymous,
|
||||
published.publicId,
|
||||
version: version,
|
||||
),
|
||||
throwsA(isA<NotFoundException>()),
|
||||
reason: '$version',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('says which of the studysets asked for are out, and their '
|
||||
'latest version', () async {
|
||||
final published = await publish(
|
||||
|
|
|
|||
|
|
@ -922,8 +922,9 @@ class _ExploreEndpoint {
|
|||
|
||||
_ida.Future<_id78hw3d.ReleaseContent> release(
|
||||
_ist.TestSessionBuilder sessionBuilder,
|
||||
_is.UuidValue publicId,
|
||||
) async {
|
||||
_is.UuidValue publicId, {
|
||||
int? version,
|
||||
}) async {
|
||||
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
|
||||
var _localUniqueSession =
|
||||
(sessionBuilder as _ist.InternalTestSessionBuilder).internalBuild(
|
||||
|
|
@ -935,7 +936,10 @@ class _ExploreEndpoint {
|
|||
createSessionCallback: (_) => _localUniqueSession,
|
||||
endpointPath: 'explore',
|
||||
methodName: 'release',
|
||||
parameters: _ist.testObjectToJson({'publicId': publicId}),
|
||||
parameters: _ist.testObjectToJson({
|
||||
'publicId': publicId,
|
||||
'version': version,
|
||||
}),
|
||||
serializationManager: _serializationManager,
|
||||
);
|
||||
var _localReturnValue =
|
||||
|
|
|
|||
Loading…
Reference in a new issue