@learnpack/learnpack 5.0.246 → 5.0.252

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.
@@ -309,7 +309,7 @@ class AuditCommand extends SessionCommand_1.default {
309
309
  for (const readmeFile of readmeFiles) {
310
310
  // Checking the language of each README file.
311
311
  if (readmeFile === "README.md")
312
- translations.push("us");
312
+ translations.push("en");
313
313
  else {
314
314
  const regexGroups = translationRegex.exec(readmeFile);
315
315
  if (regexGroups)
@@ -22,6 +22,7 @@ const creatorUtilities_1 = require("../utils/creatorUtilities");
22
22
  const uploadZipEndpont = api_1.RIGOBOT_HOST + "/v1/learnpack/upload";
23
23
  const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, learnpackDeployUrl, b64IndexReadme, all_translations = []) => {
24
24
  const categories = {
25
+ en: 9,
25
26
  us: 9,
26
27
  es: 10,
27
28
  };
@@ -232,8 +233,8 @@ class BuildCommand extends SessionCommand_1.default {
232
233
  const buildManifestPWA = path.join(buildDir, "manifest.webmanifest");
233
234
  if (fs.existsSync(indexHtmlPath)) {
234
235
  let indexHtmlContent = fs.readFileSync(indexHtmlPath, "utf-8");
235
- const description = learnJson.description.us || "LearnPack is awesome!";
236
- const title = learnJson.title.us || "LearnPack: Interactive Learning as a Service";
236
+ const description = learnJson.description.en || "LearnPack is awesome!";
237
+ const title = learnJson.title.en || "LearnPack: Interactive Learning as a Service";
237
238
  const previewUrl = learnJson.preview ||
238
239
  "https://raw.githubusercontent.com/learnpack/ide/refs/heads/master/public/learnpack.svg";
239
240
  // Replace placeholders and the <title>Old title </title> tag for a new tag with the title
@@ -301,7 +302,7 @@ class BuildCommand extends SessionCommand_1.default {
301
302
  console.log(res.data);
302
303
  fs.unlinkSync(zipFilePath);
303
304
  this.removeDirectory(buildDir);
304
- await (0, exports.handleAssetCreation)(sessionPayload, learnJson, "us", res.data.url, "", []);
305
+ await (0, exports.handleAssetCreation)(sessionPayload, learnJson, "en", res.data.url, "", []);
305
306
  }
306
307
  catch (error) {
307
308
  if (axios_1.default.isAxiosError(error)) {
@@ -3,10 +3,7 @@ import { FormState } from "../models/creator";
3
3
  export declare const createLearnJson: (courseInfo: FormState) => {
4
4
  slug: string;
5
5
  title: {
6
- us: string;
7
- } | {
8
6
  [x: string]: string;
9
- us?: undefined;
10
7
  };
11
8
  technologies: string[];
12
9
  difficulty: string;
@@ -42,21 +42,16 @@ function findLast(array, predicate) {
42
42
  const createLearnJson = (courseInfo) => {
43
43
  // console.log("courseInfo to create learn json", courseInfo)
44
44
  const expectedPreviewUrl = `https://${courseInfo.slug}.learn-pack.com/preview.png`;
45
- console.log("Preview url in generated learn.json", expectedPreviewUrl);
46
45
  const language = courseInfo.language || "en";
47
46
  const learnJson = {
48
47
  slug: courseInfo.slug,
49
- title: language === "en" || language === "us" ?
50
- {
51
- us: courseInfo.title,
52
- } :
53
- {
54
- [language]: courseInfo.title,
55
- },
48
+ title: {
49
+ [language]: courseInfo.title,
50
+ },
56
51
  technologies: courseInfo.technologies || [],
57
52
  difficulty: "beginner",
58
53
  description: {
59
- [language === "en" || language === "us" ? "us" : language]: courseInfo.description,
54
+ [language]: courseInfo.description,
60
55
  },
61
56
  grading: "isolated",
62
57
  telemetry: {
@@ -96,11 +91,10 @@ const processImage = async (url, description, rigoToken, courseSlug) => {
96
91
  };
97
92
  exports.processImage = processImage;
98
93
  const createInitialSidebar = async (slugs, initialLanguage = "en") => {
99
- const language = initialLanguage === "en" ? "us" : initialLanguage;
100
94
  const sidebar = {};
101
95
  for (const slug of slugs) {
102
96
  sidebar[slug] = {
103
- [language]: slug,
97
+ [initialLanguage]: slug,
104
98
  };
105
99
  }
106
100
  return sidebar;
@@ -126,13 +120,17 @@ const createMultiLangAsset = async (bucket, rigoToken, bcToken, courseSlug, cour
126
120
  const all_translations = [];
127
121
  for (const lang of availableLangs) {
128
122
  // eslint-disable-next-line no-await-in-loop
129
- const indexReadme = await bucket.file(`courses/${courseSlug}/README.${lang === "us" || lang === "en" ? "md" : `${lang}.md`}`);
123
+ const indexReadme = await bucket.file(`courses/${courseSlug}/README${(0, creatorUtilities_1.getReadmeExtension)(lang)}`);
130
124
  // eslint-disable-next-line no-await-in-loop
131
125
  const [indexReadmeContent] = await indexReadme.download();
132
126
  const indexReadmeString = indexReadmeContent.toString();
133
127
  const b64IndexReadme = Buffer.from(indexReadmeString).toString("base64");
134
128
  // eslint-disable-next-line no-await-in-loop
135
129
  const asset = await (0, publish_1.handleAssetCreation)({ token: bcToken, rigobotToken: rigoToken.trim() }, courseJson, lang, deployUrl, b64IndexReadme, all_translations);
130
+ if (!asset) {
131
+ console.log("No se pudo crear el asset, saltando idioma", lang);
132
+ continue;
133
+ }
136
134
  all_translations.push(asset.slug);
137
135
  }
138
136
  };
@@ -191,6 +189,7 @@ class ServeCommand extends SessionCommand_1.default {
191
189
  console.log("GCP_CREDENTIALS_JSON is not set");
192
190
  process.exit(1);
193
191
  }
192
+ await api_1.default.updateTechnologiesPeriodically();
194
193
  const credentials = JSON.parse(crendsEnv);
195
194
  const bucketStorage = new storage_1.Storage({
196
195
  credentials,
@@ -333,13 +332,8 @@ class ServeCommand extends SessionCommand_1.default {
333
332
  const { courseSlug } = req.params;
334
333
  const body = req.body;
335
334
  // Save the file as courses/courseSlug/README.md
336
- const filePath = `courses/${courseSlug}/README.${body.parsed.language_code === "us" ||
337
- body.parsed.language_code === "en" ?
338
- "md" :
339
- `${body.parsed.language_code}.md`}`;
340
- console.log("Saving initial readme to", filePath);
335
+ const filePath = `courses/${courseSlug}/README${(0, creatorUtilities_1.getReadmeExtension)(body.parsed.language_code)}`;
341
336
  await uploadFileToBucket(bucket, body.parsed.content, filePath);
342
- console.log("Initial readme saved to", filePath);
343
337
  res.json({ status: "SUCCESS" });
344
338
  });
345
339
  app.post("/webhooks/:courseSlug/images/:imageId", async (req, res) => {
@@ -496,7 +490,8 @@ class ServeCommand extends SessionCommand_1.default {
496
490
  console.log("GET /exercise/:slug/readme");
497
491
  const { slug } = req.params;
498
492
  const courseSlug = req.query.slug;
499
- const lang = req.query.lang || "us";
493
+ const lang = req.query.lang || "en";
494
+ console.log("LANG", lang);
500
495
  if (!courseSlug) {
501
496
  return res.status(400).json({ error: "Missing courseSlug" });
502
497
  }
@@ -508,15 +503,14 @@ class ServeCommand extends SessionCommand_1.default {
508
503
  if (readmeFiles.length === 0) {
509
504
  return res.status(404).json({ error: "No README files found" });
510
505
  }
511
- const requestedFilename = lang === "us" || lang === "en" ?
512
- `${basePath}README.md` :
513
- `${basePath}README.${lang}.md`;
506
+ const requestedFilename = `${basePath}README${(0, creatorUtilities_1.getReadmeExtension)(lang)}`;
514
507
  let selectedFile = readmeFiles.find(f => f === requestedFilename);
515
508
  if (!selectedFile) {
509
+ console.log("No se encontro en ese idioma, devolviendo el primero");
516
510
  selectedFile = readmeFiles[0];
517
511
  console.warn(`Requested README not found for lang '${lang}', using '${selectedFile}'`);
518
512
  }
519
- let foundLang = "us";
513
+ let foundLang = "en";
520
514
  const match = selectedFile.match(/readme(?:\.([a-z]{2}))?\.md$/i);
521
515
  if (match && match[1]) {
522
516
  foundLang = match[1].toLowerCase();
@@ -574,7 +568,7 @@ class ServeCommand extends SessionCommand_1.default {
574
568
  .json({ error: "Missing title or readme content" });
575
569
  }
576
570
  const courseSlug = query.slug;
577
- const fileName = `courses/${courseSlug}/exercises/${title}/README${language === "us" || language === "en" ? "" : `.${language}`}.md`;
571
+ const fileName = `courses/${courseSlug}/exercises/${title}/README${(0, creatorUtilities_1.getReadmeExtension)(language)}`;
578
572
  const file = bucket.file(fileName);
579
573
  await file.save(readme);
580
574
  const created = await file.exists();
@@ -613,9 +607,7 @@ class ServeCommand extends SessionCommand_1.default {
613
607
  const languageCodes = new Set();
614
608
  try {
615
609
  await Promise.all(exerciseSlugs.map(async (slug) => {
616
- const readmePath = `courses/${courseSlug}/exercises/${slug}/README${currentLanguage === "us" || currentLanguage === "en" ?
617
- "" :
618
- `.${currentLanguage}`}.md`;
610
+ const readmePath = `courses/${courseSlug}/exercises/${slug}/README${(0, creatorUtilities_1.getReadmeExtension)(currentLanguage)}`;
619
611
  const readme = await bucket.file(readmePath).download();
620
612
  await Promise.all(languagesToTranslate.map(async (language) => {
621
613
  const response = await (0, rigoActions_1.translateExercise)(rigoToken, {
@@ -623,18 +615,11 @@ class ServeCommand extends SessionCommand_1.default {
623
615
  output_language: language,
624
616
  exercise_slug: slug,
625
617
  });
626
- const translatedReadme = await bucket.file(`courses/${courseSlug}/exercises/${slug}/README${response.parsed.output_language_code === "us" ||
627
- response.parsed.output_language_code === "en" ?
628
- "" :
629
- `.${response.parsed.output_language_code}`}.md`);
618
+ const translatedReadme = await bucket.file(`courses/${courseSlug}/exercises/${slug}/README${(0, creatorUtilities_1.getReadmeExtension)(response.parsed.output_language_code)}`);
630
619
  await translatedReadme.save(response.parsed.translation);
631
620
  languageCodes.add(response.parsed.output_language_code);
632
621
  }));
633
622
  }));
634
- if (languageCodes.has("en")) {
635
- languageCodes.delete("en");
636
- languageCodes.add("us");
637
- }
638
623
  const currentLanguages = Object.keys(courseJson.title);
639
624
  for (const languageCode of currentLanguages) {
640
625
  if (languageCodes.has(languageCode)) {
@@ -642,7 +627,6 @@ class ServeCommand extends SessionCommand_1.default {
642
627
  }
643
628
  }
644
629
  if ([...languageCodes].length > 0) {
645
- console.log("TRANSLATING COURSE METADATA", languageCodes);
646
630
  const translatedCourseMetadata = await Promise.all([...languageCodes].map(async (languageCode) => {
647
631
  const result = await (0, rigoActions_1.translateCourseMetadata)(rigoToken, {
648
632
  title: courseJson.title[currentLanguage],
@@ -661,9 +645,7 @@ class ServeCommand extends SessionCommand_1.default {
661
645
  metadata.description;
662
646
  }
663
647
  await uploadFileToBucket(bucket, JSON.stringify(courseJson), `courses/${courseSlug}/learn.json`);
664
- const previewReadme = await bucket.file(`courses/${courseSlug}/README${currentLanguage === "us" || currentLanguage === "en" ?
665
- "" :
666
- `.${currentLanguage}`}.md`);
648
+ const previewReadme = await bucket.file(`courses/${courseSlug}/README${(0, creatorUtilities_1.getReadmeExtension)(currentLanguage)}`);
667
649
  const [previewReadmeContent] = await previewReadme.download();
668
650
  const previewReadmeContentString = previewReadmeContent.toString();
669
651
  await Promise.all([...languageCodes].map(async (languageCode) => {
@@ -673,9 +655,7 @@ class ServeCommand extends SessionCommand_1.default {
673
655
  exercise_slug: "preview-readme",
674
656
  });
675
657
  await bucket
676
- .file(`courses/${courseSlug}/README${languageCode === "us" || languageCode === "en" ?
677
- "" :
678
- `.${languageCode}`}.md`)
658
+ .file(`courses/${courseSlug}/README${(0, creatorUtilities_1.getReadmeExtension)(languageCode)}`)
679
659
  .save(translatedPreviewReadme.parsed.translation);
680
660
  }));
681
661
  }
@@ -918,10 +898,10 @@ class ServeCommand extends SessionCommand_1.default {
918
898
  };
919
899
  copyDir(uiSrc, buildRoot);
920
900
  const availableLangs = Object.keys(config.title);
921
- let selectedLang = "us";
901
+ let selectedLang = "en";
922
902
  let title = "";
923
- if (availableLangs.includes("us")) {
924
- title = config.title.us;
903
+ if (availableLangs.includes("en")) {
904
+ title = config.title.en;
925
905
  }
926
906
  else {
927
907
  // Select the first available lang
@@ -18251,28 +18251,31 @@ const d2 = async (e) => {
18251
18251
  try {
18252
18252
  const l = Ku(15),
18253
18253
  u = `https://9cw5zmww-3000.use2.devtunnels.ms/notifications/${l}`
18254
- return {
18255
- res: (
18256
- await Pe.post(
18257
- `${Ds}/v1/prompting${r ? "/public" : ""}/completion/${
18258
- L1 ? "39" : "390"
18259
- }/`,
18260
- {
18261
- inputs: e,
18262
- include_purpose_objective: !0,
18263
- purpose_slug: n,
18264
- webhook_url: u,
18265
- },
18266
- {
18267
- headers: {
18268
- "Content-Type": "application/json",
18269
- Authorization: `Token ${t}`,
18254
+ return (
18255
+ console.log("WEBHOOK URL to send to Rigo", u),
18256
+ {
18257
+ res: (
18258
+ await Pe.post(
18259
+ `${Ds}/v1/prompting${r ? "/public" : ""}/completion/${
18260
+ L1 ? "39" : "390"
18261
+ }/`,
18262
+ {
18263
+ inputs: e,
18264
+ include_purpose_objective: !0,
18265
+ purpose_slug: n,
18266
+ webhook_url: u,
18270
18267
  },
18271
- }
18272
- )
18273
- ).data,
18274
- notificationId: l,
18275
- }
18268
+ {
18269
+ headers: {
18270
+ "Content-Type": "application/json",
18271
+ Authorization: `Token ${t}`,
18272
+ },
18273
+ }
18274
+ )
18275
+ ).data,
18276
+ notificationId: l,
18277
+ }
18278
+ )
18276
18279
  } catch (l) {
18277
18280
  const u = l
18278
18281
  return (
@@ -21192,7 +21195,7 @@ function K7() {
21192
21195
  y.rigoToken &&
21193
21196
  l({ ...y, rigoToken: "", bcToken: "", userId: "", user: null })
21194
21197
  let $ = T.filter((ee) => ee.lang === r.language)
21195
- $.length === 0 && ($ = T.filter((ee) => ee.lang === "us"))
21198
+ $.length === 0 && ($ = T.filter((ee) => ee.lang === "en"))
21196
21199
  const Q = await p2(
21197
21200
  {
21198
21201
  courseInfo: `${JSON.stringify(
@@ -10,7 +10,7 @@
10
10
  />
11
11
 
12
12
  <title>Learnpack Creator: Craft tutorials in seconds!</title>
13
- <script type="module" crossorigin src="/creator/assets/index-CZYzWk3G.js"></script>
13
+ <script type="module" crossorigin src="/creator/assets/index-CFM_Ypyi.js"></script>
14
14
  <link rel="stylesheet" crossorigin href="/creator/assets/index-DmpsXknz.css">
15
15
  </head>
16
16
  <body>
@@ -89,7 +89,7 @@ const exercise = (path, position, configObject) => {
89
89
  exercises[position].done :
90
90
  false,
91
91
  getReadme: function (lang = null) {
92
- if (lang === "us")
92
+ if (lang === "en" || lang === "us")
93
93
  lang = null; // <-- english is default, no need to append it to the file name
94
94
  if (!fs.existsSync(`${this.path}/README${lang ? "." + lang : ""}.md`)) {
95
95
  console_1.default.error(`Language ${lang} not found for exercise ${slug}, switching to default language`);
@@ -35,6 +35,7 @@ type TTechnology = {
35
35
  lang: string;
36
36
  };
37
37
  export declare const fetchTechnologies: () => Promise<any[]>;
38
+ declare function updateTechnologiesPeriodically(): Promise<void>;
38
39
  export declare const getCurrentTechnologies: () => TTechnology[];
39
40
  declare const _default: {
40
41
  login: (identification: string, password: string) => Promise<any>;
@@ -60,5 +61,6 @@ declare const _default: {
60
61
  updateRigoAssetID: (token: string, slug: string, asset_id: number) => Promise<any>;
61
62
  createRigoPackage: (token: string, slug: string, config: any) => Promise<any>;
62
63
  getCurrentTechnologies: () => TTechnology[];
64
+ updateTechnologiesPeriodically: typeof updateTechnologiesPeriodically;
63
65
  };
64
66
  export default _default;
package/lib/utils/api.js CHANGED
@@ -420,7 +420,7 @@ const getCategories = async (token) => {
420
420
  const updateRigoAssetID = async (token, slug, asset_id) => {
421
421
  const url = `${exports.RIGOBOT_HOST}/v1/learnpack/package/${slug}/`;
422
422
  const headers = {
423
- Authorization: `Token ${token.trim()}`,
423
+ Authorization: "Token " + token.trim(),
424
424
  };
425
425
  try {
426
426
  const response = await axios_1.default.put(url, { asset_id }, { headers });
@@ -434,7 +434,7 @@ const updateRigoAssetID = async (token, slug, asset_id) => {
434
434
  const createRigoPackage = async (token, slug, config) => {
435
435
  const url = `${exports.RIGOBOT_HOST}/v1/learnpack/package`;
436
436
  const headers = {
437
- Authorization: `Token ${token}`,
437
+ Authorization: "Token " + token.trim(),
438
438
  };
439
439
  try {
440
440
  const response = await axios_1.default.post(url, { slug, config }, { headers });
@@ -448,7 +448,7 @@ const createRigoPackage = async (token, slug, config) => {
448
448
  let technologiesCache = [];
449
449
  const fetchTechnologies = async () => {
450
450
  const BREATHECODE_PERMANENT_TOKEN = process.env.BREATHECODE_PERMANENT_TOKEN;
451
- const LANGS = ["en", "es", "us"];
451
+ const LANGS = ["en", "es"];
452
452
  if (!BREATHECODE_PERMANENT_TOKEN) {
453
453
  throw new Error("BREATHECODE_PERMANENT_TOKEN is not defined in environment variables");
454
454
  }
@@ -492,7 +492,6 @@ async function updateTechnologiesPeriodically() {
492
492
  setTimeout(updateTechnologiesPeriodically, 24 * 60 * 60 * 1000);
493
493
  }
494
494
  }
495
- updateTechnologiesPeriodically();
496
495
  const getCurrentTechnologies = () => technologiesCache;
497
496
  exports.getCurrentTechnologies = getCurrentTechnologies;
498
497
  exports.default = {
@@ -513,4 +512,5 @@ exports.default = {
513
512
  updateRigoAssetID,
514
513
  createRigoPackage,
515
514
  getCurrentTechnologies: exports.getCurrentTechnologies,
515
+ updateTechnologiesPeriodically,
516
516
  };
@@ -34,7 +34,7 @@ async function buildConfig(bucket, courseSlug) {
34
34
  const fname = parts.pop();
35
35
  const m = fname.match(/^readme(?:\.([a-z]{2}))?\.md$/i);
36
36
  if (m) {
37
- const lang = m[1] || "us";
37
+ const lang = m[1] || "en";
38
38
  map[slug].translations[lang] = fname;
39
39
  }
40
40
  else {
@@ -96,4 +96,5 @@ export declare function countSentences(text: string): number;
96
96
  export declare function howManyDifficultParagraphs(paragraphs: TFKGLResult[], maxFKGL: number): number;
97
97
  export declare const appendContentIndex: () => Promise<string | null>;
98
98
  export declare const appendAIRules: () => Promise<string | null>;
99
+ export declare const getReadmeExtension: (language: string) => string;
99
100
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.appendAIRules = exports.appendContentIndex = exports.saveTranslatedReadme = exports.makePackageInfo = exports.getExInfo = exports.slugify = exports.estimateReadingTime = void 0;
3
+ exports.getReadmeExtension = exports.appendAIRules = exports.appendContentIndex = exports.saveTranslatedReadme = exports.makePackageInfo = exports.getExInfo = exports.slugify = exports.estimateReadingTime = void 0;
4
4
  exports.checkReadability = checkReadability;
5
5
  exports.extractImagesFromMarkdown = extractImagesFromMarkdown;
6
6
  exports.getFilenameFromUrl = getFilenameFromUrl;
@@ -405,3 +405,7 @@ const appendAIRules = async () => {
405
405
  return null;
406
406
  };
407
407
  exports.appendAIRules = appendAIRules;
408
+ const getReadmeExtension = (language) => {
409
+ return language === "en" || language === "us" ? ".md" : `.${language}.md`;
410
+ };
411
+ exports.getReadmeExtension = getReadmeExtension;
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.246",
4
+ "version": "5.0.252",
5
5
  "author": "Alejandro Sanchez @alesanchezr",
6
6
  "contributors": [
7
7
  {
@@ -178,8 +178,7 @@ class AuditCommand extends SessionCommand {
178
178
  exercise: undefined,
179
179
  msg: "The repository property is not in the configuration object",
180
180
  })
181
- } else
182
- Audit.isUrl(config!.config?.repository, errors, counter)
181
+ } else Audit.isUrl(config!.config?.repository, errors, counter)
183
182
 
184
183
  // These two lines check if the 'description' property is inside the configuration object.
185
184
  Console.debug(
@@ -196,8 +195,7 @@ Audit.isUrl(config!.config?.repository, errors, counter)
196
195
  msg: "The projectType property is mandatory in the configuration object",
197
196
  })
198
197
 
199
- if (errors.length === 0)
200
- Console.log("The config file is ok")
198
+ if (errors.length === 0) Console.log("The config file is ok")
201
199
 
202
200
  // Validates if images and links are working at every README file.
203
201
  const exercises = config!.exercises
@@ -314,13 +312,11 @@ Console.log("The config file is ok")
314
312
  const files: string[] = []
315
313
  let count = 0
316
314
  for (const item of readmeFiles) {
317
- if (count < item.count)
318
- count = item.count
315
+ if (count < item.count) count = item.count
319
316
  }
320
317
 
321
318
  for (const item of readmeFiles) {
322
- if (item.count !== count)
323
- files.push(` ${item.exercise}`)
319
+ if (item.count !== count) files.push(` ${item.exercise}`)
324
320
  }
325
321
 
326
322
  if (files.length > 0) {
@@ -390,12 +386,10 @@ files.push(` ${item.exercise}`)
390
386
 
391
387
  for (const readmeFile of readmeFiles) {
392
388
  // Checking the language of each README file.
393
- if (readmeFile === "README.md")
394
- translations.push("us")
389
+ if (readmeFile === "README.md") translations.push("en")
395
390
  else {
396
391
  const regexGroups = translationRegex.exec(readmeFile)
397
- if (regexGroups)
398
- translations.push(regexGroups[1])
392
+ if (regexGroups) translations.push(regexGroups[1])
399
393
  }
400
394
 
401
395
  const readme = fs.readFileSync(path.resolve(readmeFile)).toString()
@@ -450,12 +444,9 @@ translations.push(regexGroups[1])
450
444
  const date = new Date()
451
445
  learnjson.validationAt = date.getTime()
452
446
 
453
- if (errors.length > 0)
454
- learnjson.validationStatus = "error"
455
- else if (warnings.length > 0)
456
- learnjson.validationStatus = "warning"
457
- else
458
- learnjson.validationStatus = "success"
447
+ if (errors.length > 0) learnjson.validationStatus = "error"
448
+ else if (warnings.length > 0) learnjson.validationStatus = "warning"
449
+ else learnjson.validationStatus = "success"
459
450
 
460
451
  // Writes the "learn.json" file with all the new properties
461
452
  await fs.promises.writeFile("./learn.json", JSON.stringify(learnjson))
@@ -32,6 +32,7 @@ export const handleAssetCreation = async (
32
32
  all_translations: string[] = []
33
33
  ) => {
34
34
  const categories: Record<string, number> = {
35
+ en: 9,
35
36
  us: 9,
36
37
  es: 10,
37
38
  }
@@ -346,9 +347,9 @@ class BuildCommand extends SessionCommand {
346
347
  if (fs.existsSync(indexHtmlPath)) {
347
348
  let indexHtmlContent = fs.readFileSync(indexHtmlPath, "utf-8")
348
349
 
349
- const description = learnJson.description.us || "LearnPack is awesome!"
350
+ const description = learnJson.description.en || "LearnPack is awesome!"
350
351
  const title =
351
- learnJson.title.us || "LearnPack: Interactive Learning as a Service"
352
+ learnJson.title.en || "LearnPack: Interactive Learning as a Service"
352
353
 
353
354
  const previewUrl =
354
355
  learnJson.preview ||
@@ -441,7 +442,7 @@ class BuildCommand extends SessionCommand {
441
442
  await handleAssetCreation(
442
443
  sessionPayload,
443
444
  learnJson,
444
- "us",
445
+ "en",
445
446
  res.data.url,
446
447
  "",
447
448
  []
@@ -36,6 +36,7 @@ import * as dotenv from "dotenv"
36
36
  import {
37
37
  extractImagesFromMarkdown,
38
38
  getFilenameFromUrl,
39
+ getReadmeExtension,
39
40
  } from "../utils/creatorUtilities"
40
41
  // import { handleAssetCreation } from "./publish"
41
42
  import axios from "axios"
@@ -66,25 +67,18 @@ export const createLearnJson = (courseInfo: FormState) => {
66
67
  // console.log("courseInfo to create learn json", courseInfo)
67
68
 
68
69
  const expectedPreviewUrl = `https://${courseInfo.slug}.learn-pack.com/preview.png`
69
- console.log("Preview url in generated learn.json", expectedPreviewUrl)
70
70
 
71
71
  const language = courseInfo.language || "en"
72
72
 
73
73
  const learnJson = {
74
74
  slug: courseInfo.slug,
75
- title:
76
- language === "en" || language === "us" ?
77
- {
78
- us: courseInfo.title,
79
- } :
80
- {
81
- [language]: courseInfo.title,
82
- },
75
+ title: {
76
+ [language]: courseInfo.title,
77
+ },
83
78
  technologies: courseInfo.technologies || [],
84
79
  difficulty: "beginner",
85
80
  description: {
86
- [language === "en" || language === "us" ? "us" : language]:
87
- courseInfo.description,
81
+ [language]: courseInfo.description,
88
82
  },
89
83
  grading: "isolated",
90
84
  telemetry: {
@@ -140,12 +134,10 @@ const createInitialSidebar = async (
140
134
  slugs: string[],
141
135
  initialLanguage = "en"
142
136
  ) => {
143
- const language = initialLanguage === "en" ? "us" : initialLanguage
144
-
145
137
  const sidebar: Record<string, Record<string, string>> = {}
146
138
  for (const slug of slugs) {
147
139
  sidebar[slug] = {
148
- [language]: slug,
140
+ [initialLanguage]: slug,
149
141
  }
150
142
  }
151
143
 
@@ -208,9 +200,7 @@ const createMultiLangAsset = async (
208
200
  for (const lang of availableLangs) {
209
201
  // eslint-disable-next-line no-await-in-loop
210
202
  const indexReadme = await bucket.file(
211
- `courses/${courseSlug}/README.${
212
- lang === "us" || lang === "en" ? "md" : `${lang}.md`
213
- }`
203
+ `courses/${courseSlug}/README${getReadmeExtension(lang)}`
214
204
  )
215
205
  // eslint-disable-next-line no-await-in-loop
216
206
  const [indexReadmeContent] = await indexReadme.download()
@@ -227,6 +217,11 @@ const createMultiLangAsset = async (
227
217
  all_translations
228
218
  )
229
219
 
220
+ if (!asset) {
221
+ console.log("No se pudo crear el asset, saltando idioma", lang)
222
+ continue
223
+ }
224
+
230
225
  all_translations.push(asset.slug)
231
226
  }
232
227
  }
@@ -334,6 +329,8 @@ export default class ServeCommand extends SessionCommand {
334
329
  process.exit(1)
335
330
  }
336
331
 
332
+ await api.updateTechnologiesPeriodically()
333
+
337
334
  const credentials = JSON.parse(crendsEnv)
338
335
  const bucketStorage = new Storage({
339
336
  credentials,
@@ -524,15 +521,10 @@ export default class ServeCommand extends SessionCommand {
524
521
  const body = req.body
525
522
 
526
523
  // Save the file as courses/courseSlug/README.md
527
- const filePath = `courses/${courseSlug}/README.${
528
- body.parsed.language_code === "us" ||
529
- body.parsed.language_code === "en" ?
530
- "md" :
531
- `${body.parsed.language_code}.md`
532
- }`
533
- console.log("Saving initial readme to", filePath)
524
+ const filePath = `courses/${courseSlug}/README${getReadmeExtension(
525
+ body.parsed.language_code
526
+ )}`
534
527
  await uploadFileToBucket(bucket, body.parsed.content, filePath)
535
- console.log("Initial readme saved to", filePath)
536
528
 
537
529
  res.json({ status: "SUCCESS" })
538
530
  }
@@ -776,7 +768,9 @@ export default class ServeCommand extends SessionCommand {
776
768
 
777
769
  const { slug } = req.params
778
770
  const courseSlug = req.query.slug
779
- const lang = req.query.lang || "us"
771
+ const lang = req.query.lang || "en"
772
+
773
+ console.log("LANG", lang)
780
774
 
781
775
  if (!courseSlug) {
782
776
  return res.status(400).json({ error: "Missing courseSlug" })
@@ -794,21 +788,21 @@ export default class ServeCommand extends SessionCommand {
794
788
  return res.status(404).json({ error: "No README files found" })
795
789
  }
796
790
 
797
- const requestedFilename =
798
- lang === "us" || lang === "en" ?
799
- `${basePath}README.md` :
800
- `${basePath}README.${lang}.md`
791
+ const requestedFilename = `${basePath}README${getReadmeExtension(
792
+ lang as string
793
+ )}`
801
794
 
802
795
  let selectedFile = readmeFiles.find(f => f === requestedFilename)
803
796
 
804
797
  if (!selectedFile) {
798
+ console.log("No se encontro en ese idioma, devolviendo el primero")
805
799
  selectedFile = readmeFiles[0]
806
800
  console.warn(
807
801
  `Requested README not found for lang '${lang}', using '${selectedFile}'`
808
802
  )
809
803
  }
810
804
 
811
- let foundLang = "us"
805
+ let foundLang = "en"
812
806
  const match = selectedFile.match(/readme(?:\.([a-z]{2}))?\.md$/i)
813
807
  if (match && match[1]) {
814
808
  foundLang = match[1].toLowerCase()
@@ -883,9 +877,9 @@ export default class ServeCommand extends SessionCommand {
883
877
 
884
878
  const courseSlug = query.slug
885
879
 
886
- const fileName = `courses/${courseSlug}/exercises/${title}/README${
887
- language === "us" || language === "en" ? "" : `.${language}`
888
- }.md`
880
+ const fileName = `courses/${courseSlug}/exercises/${title}/README${getReadmeExtension(
881
+ language
882
+ )}`
889
883
  const file = bucket.file(fileName)
890
884
  await file.save(readme)
891
885
  const created = await file.exists()
@@ -933,11 +927,9 @@ export default class ServeCommand extends SessionCommand {
933
927
  try {
934
928
  await Promise.all(
935
929
  exerciseSlugs.map(async (slug: string) => {
936
- const readmePath = `courses/${courseSlug}/exercises/${slug}/README${
937
- currentLanguage === "us" || currentLanguage === "en" ?
938
- "" :
939
- `.${currentLanguage}`
940
- }.md`
930
+ const readmePath = `courses/${courseSlug}/exercises/${slug}/README${getReadmeExtension(
931
+ currentLanguage
932
+ )}`
941
933
 
942
934
  const readme = await bucket.file(readmePath).download()
943
935
 
@@ -950,12 +942,9 @@ export default class ServeCommand extends SessionCommand {
950
942
  })
951
943
 
952
944
  const translatedReadme = await bucket.file(
953
- `courses/${courseSlug}/exercises/${slug}/README${
954
- response.parsed.output_language_code === "us" ||
955
- response.parsed.output_language_code === "en" ?
956
- "" :
957
- `.${response.parsed.output_language_code}`
958
- }.md`
945
+ `courses/${courseSlug}/exercises/${slug}/README${getReadmeExtension(
946
+ response.parsed.output_language_code
947
+ )}`
959
948
  )
960
949
  await translatedReadme.save(response.parsed.translation)
961
950
 
@@ -965,11 +954,6 @@ export default class ServeCommand extends SessionCommand {
965
954
  })
966
955
  )
967
956
 
968
- if (languageCodes.has("en")) {
969
- languageCodes.delete("en")
970
- languageCodes.add("us")
971
- }
972
-
973
957
  const currentLanguages = Object.keys(courseJson.title)
974
958
  for (const languageCode of currentLanguages) {
975
959
  if (languageCodes.has(languageCode)) {
@@ -978,8 +962,6 @@ export default class ServeCommand extends SessionCommand {
978
962
  }
979
963
 
980
964
  if ([...languageCodes].length > 0) {
981
- console.log("TRANSLATING COURSE METADATA", languageCodes)
982
-
983
965
  const translatedCourseMetadata = await Promise.all(
984
966
  [...languageCodes].map(async languageCode => {
985
967
  const result = await translateCourseMetadata(rigoToken, {
@@ -1009,11 +991,7 @@ export default class ServeCommand extends SessionCommand {
1009
991
  )
1010
992
 
1011
993
  const previewReadme = await bucket.file(
1012
- `courses/${courseSlug}/README${
1013
- currentLanguage === "us" || currentLanguage === "en" ?
1014
- "" :
1015
- `.${currentLanguage}`
1016
- }.md`
994
+ `courses/${courseSlug}/README${getReadmeExtension(currentLanguage)}`
1017
995
  )
1018
996
  const [previewReadmeContent] = await previewReadme.download()
1019
997
  const previewReadmeContentString = previewReadmeContent.toString()
@@ -1031,11 +1009,9 @@ export default class ServeCommand extends SessionCommand {
1031
1009
 
1032
1010
  await bucket
1033
1011
  .file(
1034
- `courses/${courseSlug}/README${
1035
- languageCode === "us" || languageCode === "en" ?
1036
- "" :
1037
- `.${languageCode}`
1038
- }.md`
1012
+ `courses/${courseSlug}/README${getReadmeExtension(
1013
+ languageCode as string
1014
+ )}`
1039
1015
  )
1040
1016
  .save(translatedPreviewReadme.parsed.translation)
1041
1017
  })
@@ -1434,10 +1410,10 @@ export default class ServeCommand extends SessionCommand {
1434
1410
 
1435
1411
  const availableLangs = Object.keys(config.title)
1436
1412
 
1437
- let selectedLang = "us"
1413
+ let selectedLang = "en"
1438
1414
  let title = ""
1439
- if (availableLangs.includes("us")) {
1440
- title = config.title.us
1415
+ if (availableLangs.includes("en")) {
1416
+ title = config.title.en
1441
1417
  } else {
1442
1418
  // Select the first available lang
1443
1419
  title = config.title[availableLangs[0]]
@@ -174,7 +174,7 @@ function App() {
174
174
  let techs = technologies.filter((t) => t.lang === formState.language)
175
175
 
176
176
  if (techs.length === 0) {
177
- techs = technologies.filter((t) => t.lang === "us")
177
+ techs = technologies.filter((t) => t.lang === "en")
178
178
  }
179
179
 
180
180
  const res = await publicInteractiveCreation(
@@ -25,7 +25,7 @@ import { Sidebar } from "./Sidebar"
25
25
  import Login from "../Login"
26
26
  import { useNavigate } from "react-router"
27
27
  import { ParamsChecker } from "../ParamsChecker"
28
- import { randomUUID, slugify } from "../../utils/creatorUtils"
28
+ import { randomUUID } from "../../utils/creatorUtils"
29
29
  import { RIGO_FLOAT_GIF } from "../../utils/constants"
30
30
  import { useTranslation } from "react-i18next"
31
31
  import NotificationListener from "../NotificationListener"
@@ -24,6 +24,8 @@ export const publicInteractiveCreation = async (
24
24
  "https://9cw5zmww-3000.use2.devtunnels.ms"
25
25
  }/notifications/${randomUID}`
26
26
 
27
+ console.log("WEBHOOK URL to send to Rigo", webhookUrl)
28
+
27
29
  const response = await axios.post(
28
30
  `${RIGOBOT_HOST}/v1/prompting${
29
31
  publicRequest ? "/public" : ""
@@ -18251,28 +18251,31 @@ const d2 = async (e) => {
18251
18251
  try {
18252
18252
  const l = Ku(15),
18253
18253
  u = `https://9cw5zmww-3000.use2.devtunnels.ms/notifications/${l}`
18254
- return {
18255
- res: (
18256
- await Pe.post(
18257
- `${Ds}/v1/prompting${r ? "/public" : ""}/completion/${
18258
- L1 ? "39" : "390"
18259
- }/`,
18260
- {
18261
- inputs: e,
18262
- include_purpose_objective: !0,
18263
- purpose_slug: n,
18264
- webhook_url: u,
18265
- },
18266
- {
18267
- headers: {
18268
- "Content-Type": "application/json",
18269
- Authorization: `Token ${t}`,
18254
+ return (
18255
+ console.log("WEBHOOK URL to send to Rigo", u),
18256
+ {
18257
+ res: (
18258
+ await Pe.post(
18259
+ `${Ds}/v1/prompting${r ? "/public" : ""}/completion/${
18260
+ L1 ? "39" : "390"
18261
+ }/`,
18262
+ {
18263
+ inputs: e,
18264
+ include_purpose_objective: !0,
18265
+ purpose_slug: n,
18266
+ webhook_url: u,
18270
18267
  },
18271
- }
18272
- )
18273
- ).data,
18274
- notificationId: l,
18275
- }
18268
+ {
18269
+ headers: {
18270
+ "Content-Type": "application/json",
18271
+ Authorization: `Token ${t}`,
18272
+ },
18273
+ }
18274
+ )
18275
+ ).data,
18276
+ notificationId: l,
18277
+ }
18278
+ )
18276
18279
  } catch (l) {
18277
18280
  const u = l
18278
18281
  return (
@@ -21192,7 +21195,7 @@ function K7() {
21192
21195
  y.rigoToken &&
21193
21196
  l({ ...y, rigoToken: "", bcToken: "", userId: "", user: null })
21194
21197
  let $ = T.filter((ee) => ee.lang === r.language)
21195
- $.length === 0 && ($ = T.filter((ee) => ee.lang === "us"))
21198
+ $.length === 0 && ($ = T.filter((ee) => ee.lang === "en"))
21196
21199
  const Q = await p2(
21197
21200
  {
21198
21201
  courseInfo: `${JSON.stringify(
@@ -10,7 +10,7 @@
10
10
  />
11
11
 
12
12
  <title>Learnpack Creator: Craft tutorials in seconds!</title>
13
- <script type="module" crossorigin src="/creator/assets/index-CZYzWk3G.js"></script>
13
+ <script type="module" crossorigin src="/creator/assets/index-CFM_Ypyi.js"></script>
14
14
  <link rel="stylesheet" crossorigin href="/creator/assets/index-DmpsXknz.css">
15
15
  </head>
16
16
  <body>
@@ -85,15 +85,12 @@ export const exercise = (
85
85
  // fs.writeFileSync(path + "/" + file, updatedMarkdown, "utf8")
86
86
  // }
87
87
 
88
- if (parts.length === 3)
89
- translations[parts[1]] = file
90
- else
91
- translations.us = file
88
+ if (parts.length === 3) translations[parts[1]] = file
89
+ else translations.us = file
92
90
  }
93
91
 
94
92
  // if the slug is a dot, it means there is not "exercises" folder, and its just a single README.md
95
- if (slug === ".")
96
- slug = "default-index"
93
+ if (slug === ".") slug = "default-index"
97
94
 
98
95
  const detected = detect(configObject, files)
99
96
 
@@ -120,16 +117,14 @@ slug = "default-index"
120
117
  exercises[position].done :
121
118
  false,
122
119
  getReadme: function (lang = null) {
123
- if (lang === "us")
124
- lang = null // <-- english is default, no need to append it to the file name
120
+ if (lang === "en" || lang === "us") lang = null // <-- english is default, no need to append it to the file name
125
121
 
126
122
  if (!fs.existsSync(`${this.path}/README${lang ? "." + lang : ""}.md`)) {
127
123
  Console.error(
128
124
  `Language ${lang} not found for exercise ${slug}, switching to default language`
129
125
  )
130
126
 
131
- if (lang)
132
- lang = null
127
+ if (lang) lang = null
133
128
 
134
129
  if (!fs.existsSync(`${this.path}/README${lang ? "." + lang : ""}.md`))
135
130
  throw new Error(
@@ -169,8 +164,7 @@ lang = null
169
164
 
170
165
  for (const _file of this.files) {
171
166
  const stats = fs.statSync(_file.path)
172
- if (stats.isDirectory() || _file.hidden)
173
- continue
167
+ if (stats.isDirectory() || _file.hidden) continue
174
168
  const fileContent = fs.readFileSync(_file.path)
175
169
  if (
176
170
  !fs.existsSync(`${config?.dirPath}/resets/${this.slug}/${_file.name}`)
@@ -217,8 +211,7 @@ continue
217
211
  getTestReport: function () {
218
212
  const _path = `${configObject?.confPath?.base}/reports/${this.slug}.json`
219
213
 
220
- if (!fs.existsSync(_path))
221
- return {}
214
+ if (!fs.existsSync(_path)) return {}
222
215
 
223
216
  const content = fs.readFileSync(_path)
224
217
  const data = JSON.parse(`${content}`)
@@ -230,8 +223,7 @@ return {}
230
223
  }
231
224
 
232
225
  export const validateExerciseDirectoryName = (str: string) => {
233
- if (str === "./")
234
- return true
226
+ if (str === "./") return true
235
227
  // TODO: Add nameValidationREgex from the config
236
228
  const regex = /^(\d{2,3}(\.\d{1,2})?-([\dA-Za-z]+(-|_)?)+)$/
237
229
  return regex.test(str)
package/src/utils/api.ts CHANGED
@@ -536,7 +536,7 @@ const updateRigoAssetID = async (
536
536
  ) => {
537
537
  const url = `${RIGOBOT_HOST}/v1/learnpack/package/${slug}/`
538
538
  const headers = {
539
- Authorization: `Token ${token.trim()}`,
539
+ Authorization: "Token " + token.trim(),
540
540
  }
541
541
  try {
542
542
  const response = await axios.put(url, { asset_id }, { headers })
@@ -550,7 +550,7 @@ const updateRigoAssetID = async (
550
550
  const createRigoPackage = async (token: string, slug: string, config: any) => {
551
551
  const url = `${RIGOBOT_HOST}/v1/learnpack/package`
552
552
  const headers = {
553
- Authorization: `Token ${token}`,
553
+ Authorization: "Token " + token.trim(),
554
554
  }
555
555
  try {
556
556
  const response = await axios.post(url, { slug, config }, { headers })
@@ -570,7 +570,7 @@ let technologiesCache: TTechnology[] = []
570
570
 
571
571
  export const fetchTechnologies = async () => {
572
572
  const BREATHECODE_PERMANENT_TOKEN = process.env.BREATHECODE_PERMANENT_TOKEN
573
- const LANGS = ["en", "es", "us"]
573
+ const LANGS = ["en", "es"]
574
574
 
575
575
  if (!BREATHECODE_PERMANENT_TOKEN) {
576
576
  throw new Error(
@@ -627,8 +627,6 @@ async function updateTechnologiesPeriodically() {
627
627
  }
628
628
  }
629
629
 
630
- updateTechnologiesPeriodically()
631
-
632
630
  export const getCurrentTechnologies = () => technologiesCache
633
631
 
634
632
  export default {
@@ -649,4 +647,5 @@ export default {
649
647
  updateRigoAssetID,
650
648
  createRigoPackage,
651
649
  getCurrentTechnologies,
650
+ updateTechnologiesPeriodically,
652
651
  }
@@ -59,7 +59,7 @@ export async function buildConfig(
59
59
  const fname = parts.pop()!
60
60
  const m = fname.match(/^readme(?:\.([a-z]{2}))?\.md$/i)
61
61
  if (m) {
62
- const lang = m[1] || "us"
62
+ const lang = m[1] || "en"
63
63
  map[slug].translations[lang] = fname
64
64
  } else {
65
65
  map[slug].files.push({
@@ -498,3 +498,7 @@ export const appendAIRules = async () => {
498
498
 
499
499
  return null
500
500
  }
501
+
502
+ export const getReadmeExtension = (language: string) => {
503
+ return language === "en" || language === "us" ? ".md" : `.${language}.md`
504
+ }
@@ -12,14 +12,14 @@
12
12
  "title": {
13
13
  "type": "object",
14
14
  "properties": {
15
- "us": {
15
+ "en": {
16
16
  "type": "string"
17
17
  },
18
18
  "es": {
19
19
  "type": "string"
20
20
  }
21
21
  },
22
- "required": ["us"]
22
+ "required": ["en"]
23
23
  },
24
24
  "repository": {
25
25
  "type": "string",
@@ -32,14 +32,14 @@
32
32
  "description": {
33
33
  "type": "object",
34
34
  "properties": {
35
- "us": {
35
+ "en": {
36
36
  "type": "string"
37
37
  },
38
38
  "es": {
39
39
  "type": "string"
40
40
  }
41
41
  },
42
- "required": ["us"]
42
+ "required": ["en"]
43
43
  },
44
44
  "duration": {
45
45
  "type": "integer"
@@ -96,7 +96,7 @@
96
96
  "intro": {
97
97
  "type": "object",
98
98
  "properties": {
99
- "us": {
99
+ "en": {
100
100
  "type": "string",
101
101
  "format": "uri"
102
102
  },
@@ -12,14 +12,14 @@
12
12
  "title": {
13
13
  "type": "object",
14
14
  "properties": {
15
- "us": {
15
+ "en": {
16
16
  "type": "string"
17
17
  },
18
18
  "es": {
19
19
  "type": "string"
20
20
  }
21
21
  },
22
- "required": ["us"]
22
+ "required": ["en"]
23
23
  },
24
24
  "repository": {
25
25
  "type": "string",
@@ -32,14 +32,14 @@
32
32
  "description": {
33
33
  "type": "object",
34
34
  "properties": {
35
- "us": {
35
+ "en": {
36
36
  "type": "string"
37
37
  },
38
38
  "es": {
39
39
  "type": "string"
40
40
  }
41
41
  },
42
- "required": ["us"]
42
+ "required": ["en"]
43
43
  },
44
44
  "duration": {
45
45
  "type": "integer"
@@ -96,7 +96,7 @@
96
96
  "intro": {
97
97
  "type": "object",
98
98
  "properties": {
99
- "us": {
99
+ "en": {
100
100
  "type": "string",
101
101
  "format": "uri"
102
102
  },