Skip to content

Commit 0acd880

Browse files
committed
rearranging folders and working on imports
1 parent 2156882 commit 0acd880

45 files changed

Lines changed: 384 additions & 176 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/mws/src/new-commands/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as load_wiki_folder from "./load-wiki-folder";
33
// import * as load_archive from "./load-archive";
44
import * as init_store from "./init-store";
55
// import * as manager from "./manager";
6+
import * as test_args from "./test-args";
67
import * as tests_complete from "./tests-complete";
78
import * as listen from "./listen";
89
import { BaseCommand, CommandInfo } from "@tiddlywiki/commander";
@@ -13,6 +14,7 @@ export const commands = {
1314
listen,
1415
load_wiki_folder,
1516
init_store,
17+
test_args,
1618
tests_complete,
1719
} as const satisfies Record<string, {
1820
info: CommandInfo,

packages/mws/src/new-commands/load-wiki-folder.ts

Lines changed: 106 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import { TiddlerFields, TW } from "tiddlywiki";
44
import * as fs from "fs";
55
import * as path from "path";
66
import { truthy } from "@tiddlywiki/server";
7-
import { importBags, importRecipes, indexImportedBagsByName } from "../new-managers/wiki-import";
7+
import { importBags, importRecipes, indexImportedBagsByName, toMappingRows, WikiImportWriter } from "../new-managers/wiki-import";
8+
import { RecipeDefinition } from "../new-managers/wiki-actions";
89

910
export const info: CommandInfo = {
1011
name: "load-wiki-folder",
@@ -13,12 +14,14 @@ export const info: CommandInfo = {
1314
["path", "Path to the folder containing a tiddlywiki.info file"],
1415
],
1516
options: [
16-
["bag-name <string>", "Name of the bag to load tiddlers into"],
17-
["bag-description <string>", "Description of the bag"],
1817
["recipe-name <string>", "Name of the recipe to create"],
1918
["recipe-description <string>", "Description of the recipe"],
19+
["bag-name <string>", "Name of the bag to load tiddlers into"],
20+
["bag-description <string>", "Description of the bag"],
2021
["template-name <string>", "Template for this recipe"],
21-
["overwrite", "Confirm that you want to overwrite existing content"]
22+
["owner-roles <string>", "Roles to set on the recipes and bags."],
23+
["overwrite", "Confirm that you want to overwrite existing content"],
24+
["skip-existing", "Confirm that you want to skip existing content"],
2225
],
2326
};
2427
// tiddlywiki --load ./mywiki.html --savewikifolder ./mywikifolder
@@ -27,8 +30,10 @@ export class Command extends BaseCommand<[string], {
2730
"bag-description"?: string[];
2831
"recipe-name"?: string[];
2932
"recipe-description"?: string[];
33+
"owner-roles"?: string[];
3034
"template-name"?: string[];
3135
"overwrite"?: boolean;
36+
"skip-existing"?: boolean;
3237
}> {
3338

3439

@@ -51,79 +56,113 @@ export class Command extends BaseCommand<[string], {
5156
const templateName = this.options["template-name"]?.[0] ?? "Blank Template";
5257

5358
const overwrite = !!this.options["overwrite"];
59+
const skipExisting = !!this.options["skip-existing"];
5460

5561
const bagName = this.options["bag-name"][0];
5662
const bagDescription = this.options["bag-description"][0];
5763
const recipeName = this.options["recipe-name"][0];
5864
const recipeDescription = this.options["recipe-description"][0];
59-
const templateId = await getTemplateIdByName(this.config.engine, templateName);
60-
if (!templateId) {
65+
66+
const ownerRoles = this.options["owner-roles"] ?? [];
67+
68+
if (!templateName) {
6169
throw new Error(`Template ${templateName} does not exist.`);
6270
}
6371

64-
const existingRecipe = await this.config.engine.recipe.findUnique({
65-
where: { slug: recipeName },
66-
select: { id: true },
67-
});
68-
const existingBag = await this.config.engine.bag.findUnique({
69-
where: { name: bagName },
70-
select: { id: true },
71-
});
72+
this.config.engine.$transaction(async prisma => {
73+
const importer = new WikiImportWriter(prisma, false);
7274

73-
if (!overwrite && (existingRecipe || existingBag)) {
74-
console.log(`Recipe or bag already exists for ${recipeName}. Use --overwrite to overwrite it. Skipping.`);
75-
return;
76-
}
75+
const existingRecipe = await prisma.recipe.findUnique({
76+
where: { slug: recipeName },
77+
select: { id: true },
78+
});
79+
const existingBag = await prisma.bag.findUnique({
80+
where: { name: bagName },
81+
select: { id: true },
82+
});
83+
if ((existingRecipe || existingBag)) {
84+
if (!overwrite && !skipExisting) {
85+
throw `Recipe or bag already exists for ${recipeName}. Use --overwrite to overwrite it or --skip-existing to continue.`;
86+
}
87+
if (skipExisting) {
88+
console.log(`Recipe or bag already exists for ${recipeName}. Use --overwrite to overwrite it or --skip-existing to continue.`);
89+
return;
90+
}
91+
}
7792

78-
const { pluginTitles, tiddlers } = loadWikiFolder({
79-
wikiPath: this.params[0],
80-
bagName,
81-
bagDescription,
82-
recipeName,
83-
recipeDescription,
84-
$tw: this.$tw,
85-
cache: this.config.pluginCache,
86-
});
93+
const template = await prisma.template.findUnique({
94+
where: { name: templateName },
95+
select: { id: true, definition: true, type: true }
96+
});
8797

88-
if (overwrite) {
89-
await deleteExistingWikiFolderSeedData(this.config.engine, { recipeName, bagName });
90-
}
98+
if (!template) {
99+
throw `The specified template name '${templateName}' could not be found.`;
100+
}
101+
102+
const { pluginTitles, tiddlers } = loadWikiFolder({
103+
recipeName,
104+
recipeDescription,
105+
bagName,
106+
bagDescription,
107+
wikiPath: this.params[0],
108+
cache: this.config.pluginCache,
109+
$tw: this.$tw,
110+
});
91111

92-
const bagSeed = await importBags(this.config.engine, [{
112+
const [bag] = await importer.importBags([{
93113
name: bagName,
94114
description: bagDescription,
95-
permissions: [],
115+
permissions: ownerRoles.map(roleId => ({ level: "C_admin", roleId })),
96116
}]);
97-
const bag = indexImportedBagsByName(bagSeed).get(bagName)
98-
?? await this.config.engine.bag.findUnique({ where: { name: bagName }, select: { id: true, name: true } });
99117

100-
if (!bag) {
101-
throw new Error(`Failed to create bag ${bagName}`);
102-
}
118+
if (!bag) {
119+
throw new Error(`Failed to create bag ${bagName}`);
120+
}
103121

104-
await importRecipes(this.config.engine, [{
105-
slug: recipeName,
106-
templateId,
107-
definition: {
108-
displayName: recipeName,
109-
description: recipeDescription,
110-
readonlyBags: [],
111-
writablePrefixBags: { "": bagName },
112-
plugins: pluginTitles,
113-
},
114-
plugins: pluginTitles,
115-
permissions: [],
116-
compiledBags: [{
117-
bagId: bag.id,
118-
priority: 0,
119-
isWritable: true,
120-
prefix: "",
121-
}],
122-
}]);
122+
switch (template.type) {
123+
case "simpleV1": {
124+
const recipeDefinition: RecipeDefinition = {
125+
displayName: recipeName,
126+
description: recipeDescription,
127+
plugins: pluginTitles,
128+
readonlyBags: [],
129+
writablePrefixBags: toMappingRows({ "": bagName }),
130+
};
131+
const {
132+
bags: compiledBags, plugins: compiledPlugins
133+
} = await importer.compileRecipeSimpleV1(recipeDefinition, template.definition);
134+
const [recipe] = await importer.importRecipes([{
135+
compiledBags,
136+
plugins: compiledPlugins,
137+
definition: recipeDefinition,
138+
permissions: ownerRoles.map(roleId => ({ level: "B_write", roleId })),
139+
slug: recipeName,
140+
templateId: template.id,
141+
}]);
142+
await saveLoadedTiddlers(this.config.engine, bag.id, tiddlers);
143+
}
144+
}
145+
146+
147+
// const compiledRecipe = await importer.compileRecipe({
148+
// slug: recipeName,
149+
// definition: {
150+
// displayName: recipeName,
151+
// description: recipeDescription,
152+
// readonlyBags: [],
153+
// writablePrefixBags: { "": bagName },
154+
// plugins: pluginTitles,
155+
// },
156+
// permissions: ownerRoles.map(roleId => ({ level: "B_write", roleId })),
157+
// }, template);
123158

124-
await saveLoadedTiddlers(this.config.engine, bag.id, tiddlers);
125159

126-
console.log(info.name, "complete:", this.params[0])
160+
161+
162+
163+
console.log(info.name, "complete:", this.params[0])
164+
});
165+
127166
return null;
128167
}
129168

@@ -162,46 +201,9 @@ function loadWikiFolder({ $tw, cache, ...options }: {
162201

163202
}
164203

165-
async function getTemplateIdByName(prisma: PrismaEngineClient, templateName: string) {
166-
const templates = await prisma.template.findMany({
167-
select: { id: true, definition: true },
168-
});
169-
return templates.find((template) => template.definition.name === templateName)?.id ?? null;
170-
}
171-
172-
async function deleteExistingWikiFolderSeedData(prisma: PrismaEngineClient, { recipeName, bagName }: {
173-
recipeName: string;
174-
bagName: string;
175-
}) {
176-
await prisma.$transaction(async (tx) => {
177-
const existingRecipe = await tx.recipe.findUnique({
178-
where: { slug: recipeName },
179-
select: { id: true, template_id: true },
180-
});
181-
182-
if (existingRecipe) {
183-
await tx.recipe.delete({ where: { id: existingRecipe.id } });
184-
const templateUsageCount = await tx.recipe.count({ where: { template_id: existingRecipe.template_id } });
185-
if (!templateUsageCount) {
186-
await tx.template.delete({ where: { id: existingRecipe.template_id } });
187-
}
188-
}
189-
190-
const existingBag = await tx.bag.findUnique({
191-
where: { name: bagName },
192-
select: { id: true },
193-
});
194-
195-
if (existingBag) {
196-
await tx.bag.delete({ where: { id: existingBag.id } });
197-
}
198-
});
199-
200-
}
201-
202-
async function saveLoadedTiddlers(prisma: PrismaEngineClient, bagId: string, tiddlers: TiddlerFields[]) {
204+
async function saveLoadedTiddlers(prisma: PrismaEngineClient, bag_id: string, tiddlers: TiddlerFields[]) {
203205
await prisma.$transaction(async (tx) => {
204-
await tx.tiddler.deleteMany({ where: { bag_id: bagId } });
206+
await tx.tiddler.deleteMany({ where: { bag_id } });
205207

206208
for (const tiddler of tiddlers) {
207209
const title = tiddler.title;
@@ -214,12 +216,16 @@ async function saveLoadedTiddlers(prisma: PrismaEngineClient, bagId: string, tid
214216
.filter(([, value]) => value !== undefined)
215217
.map(([fieldName, fieldValue]) => [fieldName, typeof fieldValue === "string" ? fieldValue : `${fieldValue}`])
216218
);
219+
const event = await tx.tiddlerEvent.create({
220+
data: { bag_id, title, type: "save" }
221+
});
217222

218223
await tx.tiddler.upsert({
219-
where: { bag_id_title: { bag_id: bagId, title } },
220-
update: { fields, revision: BigInt(0) },
221-
create: { bag_id: bagId, title, fields, revision: BigInt(0) },
224+
where: { bag_id_title: { bag_id, title } },
225+
update: { fields, revision: event.seq },
226+
create: { bag_id, title, fields, revision: event.seq },
222227
});
228+
223229
}
224230
});
225231

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { BaseCommand, CommandInfo } from "@tiddlywiki/commander";
2+
3+
export const info: CommandInfo = {
4+
name: "test-args",
5+
description: "Prints the command args to console. Useful for testing your inputs.",
6+
arguments: [],
7+
};
8+
9+
10+
export class Command extends BaseCommand {
11+
12+
async execute() {
13+
console.log(this.params);
14+
}
15+
}

packages/mws/src/new-managers/wiki-actions.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ type IUserRow = DataStore["users"][number];
99
type IRoleRow = DataStore["roles"][number];
1010

1111

12-
type TemplateDefinition = Omit<
12+
export type TemplateDefinition = Omit<
1313
ITemplateRow,
1414
| "id"
1515
| "lastUpdatedAt"
1616
| "templatePermissions"
1717
| "dependentWikis"
1818
>;
1919

20-
type RecipeDefinition = Omit<
20+
export type RecipeDefinition = Omit<
2121
IWikiRow,
2222
| "id"
2323
| "slug"
@@ -274,13 +274,18 @@ async function saveWikiRow(prisma: PrismaTxnClient, data: IWikiRow): Promise<str
274274
}
275275

276276
async function saveTemplateRow(prisma: PrismaTxnClient, data: ITemplateRow): Promise<string> {
277-
const writableRows = normalizePrefixRows(data.writablePrefixBags);
278-
const existing = data.id ? await prisma.template.findUnique({ where: { id: data.id }, select: { id: true, type: true, definition: true } }) : null;
277+
278+
const existing = data.id
279+
? await prisma.template.findUnique({
280+
where: { id: data.id },
281+
select: { id: true, type: true, definition: true }
282+
})
283+
: null;
279284
const definition: PrismaJson.Template_definition = {
280285
name: data.name,
281286
description: data.description,
282287
readonlyBags: normalizeLineList(data.readonlyBags),
283-
writablePrefixBags: writableRows,
288+
writablePrefixBags: normalizePrefixRows(data.writablePrefixBags),
284289
plugins: normalizeLineList(data.plugins),
285290
requiredPluginsEnabled: data.requiredPluginsEnabled,
286291
customHtmlEnabled: data.customHtmlEnabled,
@@ -297,7 +302,8 @@ async function saveTemplateRow(prisma: PrismaTxnClient, data: ITemplateRow): Pro
297302
})
298303
: await prisma.template.create({
299304
data: {
300-
type: "prefixV1",
305+
name: definition.name,
306+
type: "simpleV1",
301307
definition,
302308
},
303309
select: { id: true },

0 commit comments

Comments
 (0)