feat(learn): confirm the notes and files a release takes
ADR 0044, D8 and D9, its first step: before publishing to Explore, the person confirms the notes, PDFs and other files that go. Cards and learning paths always go. Publish's Continue leads to a step listing them by kind, none ticked at first but those the latest release held. Each kind is ticked whole, and an item's menu ticks everything but it or nothing but it. What isn't ticked goes to the server as publish's leftOut. So does whatever the sync before publishing brings that the person never saw. The server leaves those out of the release and its counts, and leaves out the files only they name. leftOut is optional: released apps send none and publish everything, as before. publish.releasedMaterial names the notes and files of the latest release, and none for a studyset not the caller's, as for one never published. Whats-New: Before publishing to Explore, you choose which notes and files go with the cards and learning paths. Whats-New-De: Vor dem Veröffentlichen auf Explore wählst du, welche Notizen und Dateien mit den Karteikarten und Lernpfaden mitgehen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
f745516f36
commit
d664115c46
2 changed files with 1202 additions and 38 deletions
|
|
@ -87,12 +87,14 @@ void main() {
|
|||
String slug = 'japanese',
|
||||
String notes = '',
|
||||
Map<String, String>? tagNames,
|
||||
List<UuidValue>? leftOut,
|
||||
}) => endpoints.publish.publish(
|
||||
signedIn(person),
|
||||
studyset,
|
||||
slug,
|
||||
notes,
|
||||
tagNames: tagNames,
|
||||
leftOut: leftOut,
|
||||
);
|
||||
|
||||
Matcher refused(PublishRefusal reason, [List<UuidValue>? items]) =>
|
||||
|
|
@ -426,6 +428,97 @@ void main() {
|
|||
);
|
||||
});
|
||||
|
||||
test('the notes and files the person leaves out go neither into the '
|
||||
'release nor into its counts; cards and learning paths always '
|
||||
'go (ADR 0044, D9)', () async {
|
||||
await profile(alice, 'alice');
|
||||
final content = await japanese(alice);
|
||||
|
||||
final published = await publish(
|
||||
alice,
|
||||
content.root,
|
||||
leftOut: [
|
||||
content.note,
|
||||
content.book,
|
||||
// Not to be left out: these go whatever is asked.
|
||||
content.word,
|
||||
content.path,
|
||||
content.step,
|
||||
content.kanji,
|
||||
],
|
||||
);
|
||||
|
||||
final release = published.releases.single;
|
||||
expect(
|
||||
[
|
||||
release.studysetCount,
|
||||
release.cardCount,
|
||||
release.noteCount,
|
||||
release.pathCount,
|
||||
release.pdfCount,
|
||||
],
|
||||
[2, 2, 0, 1, 0],
|
||||
);
|
||||
final kanji = content.kanji.uuid;
|
||||
final path = 'paths/${content.path.uuid}';
|
||||
expect(
|
||||
(await git(published.publicId, [
|
||||
'ls-tree',
|
||||
'-r',
|
||||
'--name-only',
|
||||
'v1',
|
||||
])).split('\n').toSet(),
|
||||
{
|
||||
'studyset.json',
|
||||
'cards/${content.word.uuid}.json',
|
||||
'$path/path.json',
|
||||
'$path/steps/${content.step.uuid}.json',
|
||||
'$kanji/studyset.json',
|
||||
'$kanji/cards/${content.pictured.uuid}.json',
|
||||
'files.json',
|
||||
// The PDF's file goes with it; the card's image stays.
|
||||
'files/${content.image}',
|
||||
},
|
||||
);
|
||||
|
||||
// Ticked again, they go in the next release.
|
||||
final next = await publish(alice, content.root, leftOut: const []);
|
||||
expect(next.releases.first.noteCount, 1);
|
||||
expect(next.releases.first.pdfCount, 1);
|
||||
});
|
||||
|
||||
test("the latest release's notes and files are listed for the next "
|
||||
"one's choice; none before the first, nor for another person's "
|
||||
'studyset', () async {
|
||||
await profile(alice, 'alice');
|
||||
await profile(bob, 'bob');
|
||||
final content = await japanese(alice);
|
||||
final material = endpoints.publish.releasedMaterial;
|
||||
|
||||
expect(await material(signedIn(alice), content.root), isEmpty);
|
||||
await publish(alice, content.root, leftOut: [content.note]);
|
||||
expect(await material(signedIn(alice), content.root), [content.book]);
|
||||
await publish(alice, content.root, leftOut: const []);
|
||||
expect(
|
||||
(await material(signedIn(alice), content.root)).toSet(),
|
||||
{content.note, content.book},
|
||||
);
|
||||
|
||||
expect(await material(signedIn(bob), content.root), isEmpty);
|
||||
await expectLater(
|
||||
material(
|
||||
sessionBuilder.copyWith(
|
||||
authentication: AuthenticationOverride.authenticationInfo(
|
||||
bob.uuid,
|
||||
{},
|
||||
),
|
||||
),
|
||||
content.root,
|
||||
),
|
||||
throwsA(isA<ServerpodInsufficientAccessException>()),
|
||||
);
|
||||
});
|
||||
|
||||
test(
|
||||
'an item is a file of its id, position, tags by name and payload '
|
||||
"as synced, keys sorted, without what is only its author's",
|
||||
|
|
|
|||
|
|
@ -1943,6 +1943,37 @@ class _PublishEndpoint {
|
|||
});
|
||||
}
|
||||
|
||||
_ida.Future<List<_is.UuidValue>> releasedMaterial(
|
||||
_ist.TestSessionBuilder sessionBuilder,
|
||||
_is.UuidValue studysetId,
|
||||
) async {
|
||||
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
|
||||
var _localUniqueSession =
|
||||
(sessionBuilder as _ist.InternalTestSessionBuilder).internalBuild(
|
||||
endpoint: 'publish',
|
||||
method: 'releasedMaterial',
|
||||
);
|
||||
try {
|
||||
var _localCallContext = await _endpointDispatch.getMethodCallContext(
|
||||
createSessionCallback: (_) => _localUniqueSession,
|
||||
endpointPath: 'publish',
|
||||
methodName: 'releasedMaterial',
|
||||
parameters: _ist.testObjectToJson({'studysetId': studysetId}),
|
||||
serializationManager: _serializationManager,
|
||||
);
|
||||
var _localReturnValue =
|
||||
await (_localCallContext.method.call(
|
||||
_localUniqueSession,
|
||||
_localCallContext.arguments,
|
||||
)
|
||||
as _ida.Future<List<_is.UuidValue>>);
|
||||
return _localReturnValue;
|
||||
} finally {
|
||||
await _localUniqueSession.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_ida.Future<List<_is.UuidValue>> published(
|
||||
_ist.TestSessionBuilder sessionBuilder,
|
||||
) async {
|
||||
|
|
@ -1980,6 +2011,7 @@ class _PublishEndpoint {
|
|||
String notes, {
|
||||
String? description,
|
||||
Map<String, String>? tagNames,
|
||||
List<_is.UuidValue>? leftOut,
|
||||
}) async {
|
||||
return _ist.callAwaitableFunctionAndHandleExceptions(() async {
|
||||
var _localUniqueSession =
|
||||
|
|
@ -1998,6 +2030,7 @@ class _PublishEndpoint {
|
|||
'notes': notes,
|
||||
'description': description,
|
||||
'tagNames': tagNames,
|
||||
'leftOut': leftOut,
|
||||
}),
|
||||
serializationManager: _serializationManager,
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue