@learnpack/learnpack 5.0.343 → 5.0.346
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commands/publish.d.ts +7 -1
- package/lib/commands/publish.js +64 -21
- package/lib/commands/serve.js +810 -15
- package/lib/creatorDist/assets/{index-BhqDgBS9.js → index-DnthLsvb.js} +4731 -4730
- package/lib/creatorDist/index.html +1 -1
- package/lib/utils/api.d.ts +1 -1
- package/lib/utils/api.js +38 -18
- package/package.json +1 -1
- package/src/commands/publish.ts +107 -30
- package/src/commands/serve.ts +1194 -16
- package/src/creator/src/components/FileUploader.tsx +1 -2
- package/src/creator/src/utils/rigo.ts +1 -2
- package/src/creatorDist/assets/{index-BhqDgBS9.js → index-DnthLsvb.js} +4731 -4730
- package/src/creatorDist/index.html +1 -1
- package/src/ui/_app/app.css +1 -1
- package/src/ui/_app/app.js +2114 -2113
- package/src/ui/app.tar.gz +0 -0
- package/src/utils/api.ts +52 -20
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import SessionCommand from "../utils/SessionCommand";
|
|
2
|
+
type ExistingAssetInfo = {
|
|
3
|
+
lang: string;
|
|
4
|
+
slug: string;
|
|
5
|
+
exists: boolean;
|
|
6
|
+
academyId?: number;
|
|
7
|
+
};
|
|
2
8
|
export declare const handleAssetCreation: (sessionPayload: {
|
|
3
9
|
token: string;
|
|
4
10
|
rigobotToken: string;
|
|
5
|
-
}, learnJson: any, selectedLang: string, learnpackDeployUrl: string, b64IndexReadme: string, academyId: number | undefined, all_translations?: string[]) => Promise<any>;
|
|
11
|
+
}, learnJson: any, selectedLang: string, learnpackDeployUrl: string, b64IndexReadme: string, academyId: number | undefined, preflightInfo?: ExistingAssetInfo, all_translations?: string[]) => Promise<any>;
|
|
6
12
|
declare class BuildCommand extends SessionCommand {
|
|
7
13
|
static description: string;
|
|
8
14
|
static flags: {
|
package/lib/commands/publish.js
CHANGED
|
@@ -45,7 +45,33 @@ const getLocalizedValue = (translations, lang, fallbackLangs = ["en", "us"]) =>
|
|
|
45
45
|
const first = firstKey ? translations[firstKey] : "";
|
|
46
46
|
return typeof first === "string" ? first : "";
|
|
47
47
|
};
|
|
48
|
-
const
|
|
48
|
+
const getExistingAssetsInfo = async (token, learnJson) => {
|
|
49
|
+
const availableLangs = getAvailableLangs(learnJson);
|
|
50
|
+
const results = [];
|
|
51
|
+
for (const lang of availableLangs) {
|
|
52
|
+
const assetTitle = getLocalizedValue(learnJson === null || learnJson === void 0 ? void 0 : learnJson.title, lang);
|
|
53
|
+
if (!assetTitle)
|
|
54
|
+
continue;
|
|
55
|
+
let slug = (0, creatorUtilities_1.slugify)(assetTitle).slice(0, 47);
|
|
56
|
+
slug = `${slug}-${lang}`;
|
|
57
|
+
// eslint-disable-next-line no-await-in-loop
|
|
58
|
+
const { exists, academyId } = await api_1.default.doesAssetExists(token, slug);
|
|
59
|
+
results.push({ lang, slug, exists, academyId });
|
|
60
|
+
}
|
|
61
|
+
return results;
|
|
62
|
+
};
|
|
63
|
+
const determinePublishAcademyMode = (existingAssets) => {
|
|
64
|
+
const academyIds = existingAssets
|
|
65
|
+
.filter((a) => a.exists && a.academyId !== undefined)
|
|
66
|
+
.map((a) => a.academyId);
|
|
67
|
+
const unique = [...new Set(academyIds)];
|
|
68
|
+
if (unique.length === 0)
|
|
69
|
+
return { type: "select" };
|
|
70
|
+
if (unique.length === 1)
|
|
71
|
+
return { type: "locked", academyId: unique[0] };
|
|
72
|
+
return { type: "conflict", academies: unique };
|
|
73
|
+
};
|
|
74
|
+
const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, learnpackDeployUrl, b64IndexReadme, academyId, preflightInfo, all_translations = []) => {
|
|
49
75
|
const category = "uncategorized";
|
|
50
76
|
try {
|
|
51
77
|
const user = await api_1.default.validateToken(sessionPayload.token);
|
|
@@ -56,15 +82,8 @@ const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, lear
|
|
|
56
82
|
}
|
|
57
83
|
let slug = (0, creatorUtilities_1.slugify)(assetTitle).slice(0, 47);
|
|
58
84
|
slug = `${slug}-${selectedLang}`;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (exists &&
|
|
62
|
-
existingAcademyId !== undefined &&
|
|
63
|
-
academyId !== undefined &&
|
|
64
|
-
existingAcademyId !== academyId) {
|
|
65
|
-
console_1.default.warning(`Asset exists in academy ${existingAcademyId}, but attempting to publish to academy ${academyId}. ` +
|
|
66
|
-
`The asset will be updated in its current academy (${existingAcademyId}).`);
|
|
67
|
-
}
|
|
85
|
+
// Use pre-flight info when available to avoid an extra GET request
|
|
86
|
+
const { exists, academyId: existingAcademyId } = preflightInfo !== null && preflightInfo !== void 0 ? preflightInfo : (await api_1.default.doesAssetExists(sessionPayload.token, slug));
|
|
68
87
|
// const technologies: unknown[] = Array.isArray(learnJson?.technologies) ?
|
|
69
88
|
// learnJson.technologies :
|
|
70
89
|
// []
|
|
@@ -105,14 +124,19 @@ const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, lear
|
|
|
105
124
|
return asset;
|
|
106
125
|
}
|
|
107
126
|
console_1.default.info("Asset exists, updating it");
|
|
108
|
-
const
|
|
127
|
+
const updatePayload = {
|
|
109
128
|
graded: true,
|
|
110
129
|
learnpack_deploy_url: learnpackDeployUrl,
|
|
111
130
|
title: assetTitle,
|
|
112
131
|
category: category,
|
|
113
132
|
description: assetDescription,
|
|
114
133
|
all_translations,
|
|
115
|
-
}
|
|
134
|
+
};
|
|
135
|
+
// Only set academy when the asset has none yet and the user selected one
|
|
136
|
+
if (existingAcademyId === undefined && academyId !== undefined) {
|
|
137
|
+
updatePayload.academy_id = academyId;
|
|
138
|
+
}
|
|
139
|
+
const asset = await api_1.default.updateAsset(sessionPayload.token, slug, updatePayload);
|
|
116
140
|
try {
|
|
117
141
|
await api_1.default.updateRigoPackage(sessionPayload.rigobotToken.trim(), learnJson.slug, {
|
|
118
142
|
asset_id: asset.id,
|
|
@@ -130,7 +154,7 @@ const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, lear
|
|
|
130
154
|
}
|
|
131
155
|
};
|
|
132
156
|
exports.handleAssetCreation = handleAssetCreation;
|
|
133
|
-
const createMultiLangAssetFromDisk = async (sessionPayload, learnJson, deployUrl) => {
|
|
157
|
+
const createMultiLangAssetFromDisk = async (sessionPayload, learnJson, deployUrl, selectedAcademyId, existingAssetsInfo = []) => {
|
|
134
158
|
const availableLangs = getAvailableLangs(learnJson);
|
|
135
159
|
if (availableLangs.length === 0) {
|
|
136
160
|
console_1.default.error("No languages found in learn.json.title. Add at least one language (e.g. title.en).");
|
|
@@ -150,9 +174,10 @@ const createMultiLangAssetFromDisk = async (sessionPayload, learnJson, deployUrl
|
|
|
150
174
|
indexReadmeString = "";
|
|
151
175
|
}
|
|
152
176
|
const b64IndexReadme = Buffer.from(indexReadmeString).toString("base64");
|
|
177
|
+
const preflightInfo = existingAssetsInfo.find((a) => a.lang === lang);
|
|
153
178
|
try {
|
|
154
179
|
// eslint-disable-next-line no-await-in-loop
|
|
155
|
-
const asset = await (0, exports.handleAssetCreation)(sessionPayload, learnJson, lang, deployUrl, b64IndexReadme,
|
|
180
|
+
const asset = await (0, exports.handleAssetCreation)(sessionPayload, learnJson, lang, deployUrl, b64IndexReadme, selectedAcademyId, preflightInfo, all_translations);
|
|
156
181
|
if (!asset) {
|
|
157
182
|
console_1.default.debug("Could not create/update asset for lang", lang);
|
|
158
183
|
continue;
|
|
@@ -230,7 +255,7 @@ class BuildCommand extends SessionCommand_1.default {
|
|
|
230
255
|
await this.initSession(flags);
|
|
231
256
|
}
|
|
232
257
|
async run() {
|
|
233
|
-
var _a, _b, _c;
|
|
258
|
+
var _a, _b, _c, _d;
|
|
234
259
|
const buildDir = path.join(process.cwd(), "build");
|
|
235
260
|
const { flags } = this.parse(BuildCommand);
|
|
236
261
|
const strict = flags.strict;
|
|
@@ -269,17 +294,35 @@ class BuildCommand extends SessionCommand_1.default {
|
|
|
269
294
|
console_1.default.debug("Building exercises");
|
|
270
295
|
(_c = this.configManager) === null || _c === void 0 ? void 0 : _c.buildIndex();
|
|
271
296
|
}
|
|
297
|
+
const learnJsonPath = path.join(process.cwd(), "learn.json");
|
|
298
|
+
if (!fs.existsSync(learnJsonPath)) {
|
|
299
|
+
this.error("learn.json not found");
|
|
300
|
+
}
|
|
301
|
+
const learnJson = JSON.parse(fs.readFileSync(learnJsonPath, "utf-8"));
|
|
272
302
|
const academies = await api_1.default.listUserAcademies(sessionPayload.token);
|
|
273
303
|
if (academies.length === 0) {
|
|
274
304
|
console_1.default.error("It seems you cannot publish tutorials. Make sure you creator subscription is up to date here: https://4geeks.com/profile/subscriptions. If you believe there is an issue you can always contact support@4geeks.com");
|
|
275
305
|
process.exit(1);
|
|
276
306
|
}
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
307
|
+
console_1.default.info("Checking existing assets...");
|
|
308
|
+
const existingAssetsInfo = await getExistingAssetsInfo(sessionPayload.token, learnJson);
|
|
309
|
+
const academyMode = determinePublishAcademyMode(existingAssetsInfo);
|
|
310
|
+
let selectedAcademyId;
|
|
311
|
+
if (academyMode.type === "conflict") {
|
|
312
|
+
console_1.default.warning(`Some of your assets are associated with different academies ` +
|
|
313
|
+
`(${academyMode.academies.join(", ")}). ` +
|
|
314
|
+
`Academy assignment will be skipped to avoid conflicts.`);
|
|
315
|
+
}
|
|
316
|
+
else if (academyMode.type === "locked") {
|
|
317
|
+
const lockedAcademy = academies.find((a) => a.id === academyMode.academyId);
|
|
318
|
+
console_1.default.info(`This package is associated with academy: ${(_d = lockedAcademy === null || lockedAcademy === void 0 ? void 0 : lockedAcademy.name) !== null && _d !== void 0 ? _d : academyMode.academyId}. Academy cannot be changed.`);
|
|
319
|
+
selectedAcademyId = academyMode.academyId;
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
// mode === "select": all existing assets have no academy, user picks one
|
|
323
|
+
const { academy } = await selectAcademy(academies, sessionPayload.token);
|
|
324
|
+
selectedAcademyId = academy === null || academy === void 0 ? void 0 : academy.id;
|
|
281
325
|
}
|
|
282
|
-
const learnJson = JSON.parse(fs.readFileSync(learnJsonPath, "utf-8"));
|
|
283
326
|
const zipFilePath = path.join(process.cwd(), `${learnJson.slug}.zip`);
|
|
284
327
|
// Ensure build directory exists
|
|
285
328
|
if (!fs.existsSync(buildDir)) {
|
|
@@ -405,7 +448,7 @@ class BuildCommand extends SessionCommand_1.default {
|
|
|
405
448
|
console.log(res.data);
|
|
406
449
|
fs.unlinkSync(zipFilePath);
|
|
407
450
|
this.removeDirectory(buildDir);
|
|
408
|
-
await createMultiLangAssetFromDisk({ token: sessionPayload.token, rigobotToken: rigoToken }, learnJson, res.data.url);
|
|
451
|
+
await createMultiLangAssetFromDisk({ token: sessionPayload.token, rigobotToken: rigoToken }, learnJson, res.data.url, selectedAcademyId, existingAssetsInfo);
|
|
409
452
|
}
|
|
410
453
|
catch (error) {
|
|
411
454
|
if (axios_1.default.isAxiosError(error)) {
|