@learnpack/learnpack 5.0.334 → 5.0.335
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/serve.js +56 -3
- package/package.json +1 -1
- package/src/commands/serve.ts +73 -5
package/lib/commands/serve.js
CHANGED
|
@@ -155,6 +155,21 @@ const cleanFormState = (formState) => {
|
|
|
155
155
|
const cleanFormStateForSyllabus = (formState) => {
|
|
156
156
|
return Object.assign(Object.assign({}, formState), { description: formState.description, technologies: formState.technologies, contentIndex: formState.contentIndex, purposse: undefined, duration: undefined, hasContentIndex: undefined, variables: undefined, currentStep: undefined, language: undefined, isCompleted: undefined });
|
|
157
157
|
};
|
|
158
|
+
const getLocalizedValue = (translations, lang, fallbackLangs = ["en", "us"]) => {
|
|
159
|
+
if (!translations || typeof translations !== "object")
|
|
160
|
+
return "";
|
|
161
|
+
const direct = translations[lang];
|
|
162
|
+
if (typeof direct === "string" && direct.trim().length > 0)
|
|
163
|
+
return direct;
|
|
164
|
+
for (const fb of fallbackLangs) {
|
|
165
|
+
const v = translations[fb];
|
|
166
|
+
if (typeof v === "string" && v.trim().length > 0)
|
|
167
|
+
return v;
|
|
168
|
+
}
|
|
169
|
+
const firstKey = Object.keys(translations)[0];
|
|
170
|
+
const first = firstKey ? translations[firstKey] : "";
|
|
171
|
+
return typeof first === "string" ? first : "";
|
|
172
|
+
};
|
|
158
173
|
const createMultiLangAsset = async (bucket, rigoToken, bcToken, courseSlug, courseJson, deployUrl, academyId) => {
|
|
159
174
|
var _a;
|
|
160
175
|
const availableLangs = Object.keys(courseJson.title);
|
|
@@ -2927,9 +2942,7 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
2927
2942
|
try {
|
|
2928
2943
|
const bcToken = req.header("x-breathecode-token");
|
|
2929
2944
|
if (!bcToken) {
|
|
2930
|
-
return res
|
|
2931
|
-
.status(400)
|
|
2932
|
-
.json({
|
|
2945
|
+
return res.status(400).json({
|
|
2933
2946
|
error: "Authentication failed, missing breathecode token",
|
|
2934
2947
|
});
|
|
2935
2948
|
}
|
|
@@ -2941,6 +2954,46 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
2941
2954
|
return res.status(500).json({ error: error.message });
|
|
2942
2955
|
}
|
|
2943
2956
|
});
|
|
2957
|
+
app.get("/actions/package-academy/:slug", async (req, res) => {
|
|
2958
|
+
try {
|
|
2959
|
+
const { slug } = req.params;
|
|
2960
|
+
const bcToken = req.header("x-breathecode-token");
|
|
2961
|
+
if (!bcToken) {
|
|
2962
|
+
return res.status(400).json({
|
|
2963
|
+
error: "Authentication failed, missing breathecode token",
|
|
2964
|
+
});
|
|
2965
|
+
}
|
|
2966
|
+
const configFile = await bucket.file(`courses/${slug}/.learn/config.json`);
|
|
2967
|
+
const [configContent] = await configFile.download();
|
|
2968
|
+
const configJson = JSON.parse(configContent.toString());
|
|
2969
|
+
const { config } = configJson;
|
|
2970
|
+
const availableLangs = Object.keys(config.title || {});
|
|
2971
|
+
let academyId = null;
|
|
2972
|
+
let isPublished = false;
|
|
2973
|
+
for (const lang of availableLangs) {
|
|
2974
|
+
const assetTitle = getLocalizedValue(config.title, lang);
|
|
2975
|
+
if (!assetTitle)
|
|
2976
|
+
continue;
|
|
2977
|
+
let assetSlug = (0, creatorUtilities_2.slugify)(assetTitle).slice(0, 47);
|
|
2978
|
+
assetSlug = `${assetSlug}-${lang}`;
|
|
2979
|
+
const { exists, academyId: existingAcademyId } =
|
|
2980
|
+
// eslint-disable-next-line no-await-in-loop
|
|
2981
|
+
await (0, api_1.doesAssetExists)(bcToken, assetSlug);
|
|
2982
|
+
if (exists) {
|
|
2983
|
+
isPublished = true;
|
|
2984
|
+
if (existingAcademyId !== undefined) {
|
|
2985
|
+
academyId = existingAcademyId;
|
|
2986
|
+
break;
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
return res.json({ academyId, isPublished });
|
|
2991
|
+
}
|
|
2992
|
+
catch (error) {
|
|
2993
|
+
console.error("Error fetching package academy:", error);
|
|
2994
|
+
return res.status(500).json({ error: error.message });
|
|
2995
|
+
}
|
|
2996
|
+
});
|
|
2944
2997
|
app.post("/actions/publish/:slug", async (req, res) => {
|
|
2945
2998
|
try {
|
|
2946
2999
|
const { slug } = req.params;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@learnpack/learnpack",
|
|
3
3
|
"description": "Seamlessly build, sell and/or take interactive & auto-graded tutorials, start learning now or build a new tutorial to your audience.",
|
|
4
|
-
"version": "5.0.
|
|
4
|
+
"version": "5.0.335",
|
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
|
6
6
|
"contributors": [
|
|
7
7
|
{
|
package/src/commands/serve.ts
CHANGED
|
@@ -53,6 +53,7 @@ import api, {
|
|
|
53
53
|
RIGOBOT_HOST,
|
|
54
54
|
RIGOBOT_REALTIME_HOST,
|
|
55
55
|
listUserAcademies,
|
|
56
|
+
doesAssetExists,
|
|
56
57
|
} from "../utils/api"
|
|
57
58
|
import {
|
|
58
59
|
createUploadMiddleware,
|
|
@@ -277,6 +278,26 @@ const cleanFormStateForSyllabus = (formState: FormState) => {
|
|
|
277
278
|
}
|
|
278
279
|
}
|
|
279
280
|
|
|
281
|
+
const getLocalizedValue = (
|
|
282
|
+
translations: Record<string, any> | undefined,
|
|
283
|
+
lang: string,
|
|
284
|
+
fallbackLangs: string[] = ["en", "us"]
|
|
285
|
+
): string => {
|
|
286
|
+
if (!translations || typeof translations !== "object") return ""
|
|
287
|
+
|
|
288
|
+
const direct = translations[lang]
|
|
289
|
+
if (typeof direct === "string" && direct.trim().length > 0) return direct
|
|
290
|
+
|
|
291
|
+
for (const fb of fallbackLangs) {
|
|
292
|
+
const v = translations[fb]
|
|
293
|
+
if (typeof v === "string" && v.trim().length > 0) return v
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const firstKey = Object.keys(translations)[0]
|
|
297
|
+
const first = firstKey ? translations[firstKey] : ""
|
|
298
|
+
return typeof first === "string" ? first : ""
|
|
299
|
+
}
|
|
300
|
+
|
|
280
301
|
const createMultiLangAsset = async (
|
|
281
302
|
bucket: Bucket,
|
|
282
303
|
rigoToken: string,
|
|
@@ -4260,11 +4281,9 @@ class ServeCommand extends SessionCommand {
|
|
|
4260
4281
|
const bcToken = req.header("x-breathecode-token")
|
|
4261
4282
|
|
|
4262
4283
|
if (!bcToken) {
|
|
4263
|
-
return res
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
error: "Authentication failed, missing breathecode token",
|
|
4267
|
-
})
|
|
4284
|
+
return res.status(400).json({
|
|
4285
|
+
error: "Authentication failed, missing breathecode token",
|
|
4286
|
+
})
|
|
4268
4287
|
}
|
|
4269
4288
|
|
|
4270
4289
|
const academies = await listUserAcademies(bcToken)
|
|
@@ -4275,6 +4294,55 @@ class ServeCommand extends SessionCommand {
|
|
|
4275
4294
|
}
|
|
4276
4295
|
})
|
|
4277
4296
|
|
|
4297
|
+
app.get("/actions/package-academy/:slug", async (req, res) => {
|
|
4298
|
+
try {
|
|
4299
|
+
const { slug } = req.params
|
|
4300
|
+
const bcToken = req.header("x-breathecode-token")
|
|
4301
|
+
|
|
4302
|
+
if (!bcToken) {
|
|
4303
|
+
return res.status(400).json({
|
|
4304
|
+
error: "Authentication failed, missing breathecode token",
|
|
4305
|
+
})
|
|
4306
|
+
}
|
|
4307
|
+
|
|
4308
|
+
const configFile = await bucket.file(
|
|
4309
|
+
`courses/${slug}/.learn/config.json`
|
|
4310
|
+
)
|
|
4311
|
+
const [configContent] = await configFile.download()
|
|
4312
|
+
const configJson = JSON.parse(configContent.toString())
|
|
4313
|
+
const { config } = configJson
|
|
4314
|
+
|
|
4315
|
+
const availableLangs = Object.keys(config.title || {})
|
|
4316
|
+
let academyId: number | null = null
|
|
4317
|
+
let isPublished = false
|
|
4318
|
+
|
|
4319
|
+
for (const lang of availableLangs) {
|
|
4320
|
+
const assetTitle = getLocalizedValue(config.title, lang)
|
|
4321
|
+
if (!assetTitle) continue
|
|
4322
|
+
|
|
4323
|
+
let assetSlug = slugify(assetTitle).slice(0, 47)
|
|
4324
|
+
assetSlug = `${assetSlug}-${lang}`
|
|
4325
|
+
|
|
4326
|
+
const { exists, academyId: existingAcademyId } =
|
|
4327
|
+
// eslint-disable-next-line no-await-in-loop
|
|
4328
|
+
await doesAssetExists(bcToken, assetSlug)
|
|
4329
|
+
|
|
4330
|
+
if (exists) {
|
|
4331
|
+
isPublished = true
|
|
4332
|
+
if (existingAcademyId !== undefined) {
|
|
4333
|
+
academyId = existingAcademyId
|
|
4334
|
+
break
|
|
4335
|
+
}
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
|
|
4339
|
+
return res.json({ academyId, isPublished })
|
|
4340
|
+
} catch (error) {
|
|
4341
|
+
console.error("Error fetching package academy:", error)
|
|
4342
|
+
return res.status(500).json({ error: (error as Error).message })
|
|
4343
|
+
}
|
|
4344
|
+
})
|
|
4345
|
+
|
|
4278
4346
|
app.post("/actions/publish/:slug", async (req, res) => {
|
|
4279
4347
|
try {
|
|
4280
4348
|
const { slug } = req.params
|