fix(explore): copies keep their ties to PDF pages, and ids swap whole
A copy's cards, notes and screenshots tied to a page of one of its PDFs kept the author's PDF id, so the tie led nowhere in every copy from Explore and every archive imported. The copier now writes the PDFs first and points what is tied to them at the PDFs it made; an update does the same, writing a release's new PDFs before the cards tied to them, so a card the release changes keeps its tie. The files a copy names were swapped by replacing each author's id in the payload's text, one after another: an id that was another's new one swapped twice, and an id written in the text changed too. Now only whole values are swapped (withOwnIds): a block's asset URL, a PDF's file, a study button's or an exam plan's studysets, a page's PDF. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
39926ddc5b
commit
197726f5a3
2 changed files with 284 additions and 103 deletions
|
|
@ -542,4 +542,70 @@ void main() {
|
|||
['Animals', 'JLPT-N5', 'Noun'],
|
||||
);
|
||||
});
|
||||
|
||||
test("what is tied to a page of a PDF stays tied to the copy's PDF when "
|
||||
'the release changes it, and what a release ties to a PDF it brings '
|
||||
'is tied to the one made of it', () async {
|
||||
PublishedRelease release(int version) {
|
||||
final base = japanese(version);
|
||||
Map<String, Object?> page(String id, String back, String pdf) =>
|
||||
sortedKeys({
|
||||
'id': id,
|
||||
'position': 'a5',
|
||||
'tags': const <String>[],
|
||||
'payload': json(
|
||||
encodeCardPayload(
|
||||
CardContent(
|
||||
front: RichContent.plain(id),
|
||||
back: RichContent.plain(back),
|
||||
source: (pdfId: pdf, page: 3),
|
||||
),
|
||||
),
|
||||
),
|
||||
});
|
||||
return PublishedRelease(
|
||||
publicId: base.publicId,
|
||||
version: version,
|
||||
items: {
|
||||
...base.items,
|
||||
'cards/page.json': page(
|
||||
'page',
|
||||
version == 1 ? 'is' : 'is, politely',
|
||||
'book',
|
||||
),
|
||||
if (version > 1) ...{
|
||||
'pdfs/workbook.json': sortedKeys({
|
||||
'id': 'workbook',
|
||||
'position': 'a1',
|
||||
'payload': json(
|
||||
encodePdfSourcePayload(
|
||||
const PdfSourceContent(
|
||||
title: 'Workbook',
|
||||
fileName: 'workbook.pdf',
|
||||
assetId: bookAsset,
|
||||
),
|
||||
),
|
||||
),
|
||||
}),
|
||||
'cards/drill.json': page('drill', 'a drill', 'workbook'),
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
final v1 = release(1);
|
||||
final root = await copyOf(v1);
|
||||
await updater.take(root, v1, release(2), fileOf: fileOf);
|
||||
|
||||
final copied = await pdfs.sourcesOf(root);
|
||||
String pdfTitled(String title) =>
|
||||
copied.singleWhere((pdf) => pdf.content.title == title).id;
|
||||
final page = await cardFrom(root, 'page');
|
||||
expect(page.content.back.plainText, 'is, politely');
|
||||
expect(page.content.source, (pdfId: pdfTitled('A book'), page: 3));
|
||||
expect(
|
||||
(await cardFrom(root, 'drill')).content.source,
|
||||
(pdfId: pdfTitled('Workbook'), page: 3),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,7 +134,22 @@ void main() {
|
|||
),
|
||||
'kanji/cards/pictured.json': item(
|
||||
'pictured',
|
||||
encodeCardPayload(card('asset:$imageAsset', '絵')),
|
||||
encodeCardPayload(
|
||||
CardContent(
|
||||
front: RichContent({
|
||||
'document': {
|
||||
'type': 'page',
|
||||
'children': [
|
||||
{
|
||||
'type': 'image',
|
||||
'data': {'url': assetUrl(imageAsset)},
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
back: RichContent.plain('絵'),
|
||||
),
|
||||
),
|
||||
),
|
||||
'notes/particles.json': item(
|
||||
'particles',
|
||||
|
|
@ -318,10 +333,8 @@ void main() {
|
|||
(studyset) => studyset.parentId == id,
|
||||
);
|
||||
final pictured = (await cards.cardsOf(kanji.id)).single;
|
||||
final front = pictured.content.front.plainText;
|
||||
expect(front, startsWith('asset:'));
|
||||
expect(front, isNot(contains(imageAsset)));
|
||||
final assetId = front.substring('asset:'.length);
|
||||
final assetId = pictured.content.front.assetIds.single;
|
||||
expect(assetId, isNot(imageAsset));
|
||||
expect((await assets.fileOf(assetId))!.bytes, image);
|
||||
final pdf = (await pdfs.sourcesOf(kanji.id)).single;
|
||||
expect(pdf.content.title, 'A book');
|
||||
|
|
@ -330,6 +343,56 @@ void main() {
|
|||
expect((await assets.fileOf(pdf.content.assetId))!.bytes, book);
|
||||
});
|
||||
|
||||
test("a card or note tied to a page of the release's PDF is tied to the "
|
||||
'PDF made of it', () async {
|
||||
final release = japanese();
|
||||
final id = await copier.copy(
|
||||
PublishedRelease(
|
||||
publicId: release.publicId,
|
||||
version: release.version,
|
||||
items: {
|
||||
...release.items,
|
||||
'kanji/cards/page.json': item(
|
||||
'page',
|
||||
encodeCardPayload(
|
||||
CardContent(
|
||||
front: RichContent.plain('本'),
|
||||
back: RichContent.plain('book'),
|
||||
source: (pdfId: 'book', page: 2),
|
||||
),
|
||||
),
|
||||
position: 'a5',
|
||||
),
|
||||
'kanji/notes/reading.json': item(
|
||||
'reading',
|
||||
encodeNotePayload(
|
||||
NoteContent(
|
||||
body: RichContent.plain('Chapter 1'),
|
||||
source: (pdfId: 'book', page: 2),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
files: release.files,
|
||||
),
|
||||
location: 'halkyon.eu/@alice/japanese',
|
||||
fileOf: fileOf,
|
||||
);
|
||||
|
||||
final kanji = (await studysets.all()).singleWhere(
|
||||
(studyset) => studyset.parentId == id,
|
||||
);
|
||||
final pdf = (await pdfs.sourcesOf(kanji.id)).single;
|
||||
final page = (await cards.cardsOf(
|
||||
kanji.id,
|
||||
)).singleWhere((card) => card.content.front.plainText == '本');
|
||||
expect(page.content.source, (pdfId: pdf.id, page: 2));
|
||||
expect(
|
||||
(await notes.notesOf(kanji.id)).single.content.source,
|
||||
(pdfId: pdf.id, page: 2),
|
||||
);
|
||||
});
|
||||
|
||||
test('notes and learning paths, steps in their order', () async {
|
||||
final id = await copier.copy(
|
||||
japanese(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue