@learnpack/learnpack 5.0.332 → 5.0.334
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 +1 -1
- package/lib/commands/publish.js +36 -12
- package/lib/commands/serve.js +47 -10
- package/lib/utils/api.d.ts +1 -0
- package/lib/utils/api.js +10 -3
- package/package.json +1 -1
- package/src/commands/publish.ts +54 -21
- package/src/commands/serve.ts +67 -21
- package/src/utils/api.ts +13 -4
|
@@ -2,7 +2,7 @@ import SessionCommand from "../utils/SessionCommand";
|
|
|
2
2
|
export declare const handleAssetCreation: (sessionPayload: {
|
|
3
3
|
token: string;
|
|
4
4
|
rigobotToken: string;
|
|
5
|
-
}, learnJson: any, selectedLang: string, learnpackDeployUrl: string, b64IndexReadme: string, all_translations?: string[]) => Promise<any>;
|
|
5
|
+
}, learnJson: any, selectedLang: string, learnpackDeployUrl: string, b64IndexReadme: string, academyId: number | undefined, all_translations?: string[]) => Promise<any>;
|
|
6
6
|
declare class BuildCommand extends SessionCommand {
|
|
7
7
|
static description: string;
|
|
8
8
|
static flags: {
|
package/lib/commands/publish.js
CHANGED
|
@@ -45,7 +45,7 @@ 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 handleAssetCreation = async (sessionPayload, learnJson, selectedLang, learnpackDeployUrl, b64IndexReadme, all_translations = []) => {
|
|
48
|
+
const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, learnpackDeployUrl, b64IndexReadme, academyId, all_translations = []) => {
|
|
49
49
|
const category = "uncategorized";
|
|
50
50
|
try {
|
|
51
51
|
const user = await api_1.default.validateToken(sessionPayload.token);
|
|
@@ -56,17 +56,31 @@ const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, lear
|
|
|
56
56
|
}
|
|
57
57
|
let slug = (0, creatorUtilities_1.slugify)(assetTitle).slice(0, 47);
|
|
58
58
|
slug = `${slug}-${selectedLang}`;
|
|
59
|
-
const { exists } = await api_1.default.doesAssetExists(sessionPayload.token, slug);
|
|
59
|
+
const { exists, academyId: existingAcademyId } = await api_1.default.doesAssetExists(sessionPayload.token, slug);
|
|
60
|
+
// Compare academy IDs if asset exists and academyId is provided
|
|
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
|
+
}
|
|
68
|
+
// const technologies: unknown[] = Array.isArray(learnJson?.technologies) ?
|
|
69
|
+
// learnJson.technologies :
|
|
70
|
+
// []
|
|
60
71
|
if (!exists) {
|
|
61
72
|
console_1.default.info("Asset does not exist in this academy, creating it");
|
|
62
|
-
const
|
|
73
|
+
const assetPayload = {
|
|
63
74
|
slug: slug,
|
|
64
75
|
title: assetTitle,
|
|
65
76
|
lang: selectedLang,
|
|
66
77
|
graded: true,
|
|
67
78
|
description: assetDescription,
|
|
68
79
|
learnpack_deploy_url: learnpackDeployUrl,
|
|
69
|
-
technologies:
|
|
80
|
+
// technologies: technologies.map((tech: unknown) =>
|
|
81
|
+
// String(tech).toLowerCase().replace(/\s+/g, "-")
|
|
82
|
+
// ),
|
|
83
|
+
technologies: [],
|
|
70
84
|
url: learnpackDeployUrl,
|
|
71
85
|
category: category,
|
|
72
86
|
owner: user.id,
|
|
@@ -74,7 +88,11 @@ const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, lear
|
|
|
74
88
|
preview: learnJson.preview,
|
|
75
89
|
readme_raw: b64IndexReadme,
|
|
76
90
|
all_translations,
|
|
77
|
-
}
|
|
91
|
+
};
|
|
92
|
+
if (academyId !== undefined) {
|
|
93
|
+
assetPayload.academy_id = academyId;
|
|
94
|
+
}
|
|
95
|
+
const asset = await api_1.default.createAsset(sessionPayload.token, assetPayload);
|
|
78
96
|
try {
|
|
79
97
|
await api_1.default.updateRigoPackage(sessionPayload.rigobotToken.trim(), learnJson.slug, {
|
|
80
98
|
asset_id: asset.id,
|
|
@@ -108,7 +126,7 @@ const handleAssetCreation = async (sessionPayload, learnJson, selectedLang, lear
|
|
|
108
126
|
}
|
|
109
127
|
catch (error) {
|
|
110
128
|
console_1.default.error("Error updating or creating asset:", error);
|
|
111
|
-
|
|
129
|
+
throw error;
|
|
112
130
|
}
|
|
113
131
|
};
|
|
114
132
|
exports.handleAssetCreation = handleAssetCreation;
|
|
@@ -132,13 +150,19 @@ const createMultiLangAssetFromDisk = async (sessionPayload, learnJson, deployUrl
|
|
|
132
150
|
indexReadmeString = "";
|
|
133
151
|
}
|
|
134
152
|
const b64IndexReadme = Buffer.from(indexReadmeString).toString("base64");
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
153
|
+
try {
|
|
154
|
+
// eslint-disable-next-line no-await-in-loop
|
|
155
|
+
const asset = await (0, exports.handleAssetCreation)(sessionPayload, learnJson, lang, deployUrl, b64IndexReadme, undefined, all_translations);
|
|
156
|
+
if (!asset) {
|
|
157
|
+
console_1.default.debug("Could not create/update asset for lang", lang);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
all_translations.push(asset.slug);
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
console_1.default.error("Error creating asset for language", lang, error);
|
|
164
|
+
// Continue with other languages
|
|
140
165
|
}
|
|
141
|
-
all_translations.push(asset.slug);
|
|
142
166
|
}
|
|
143
167
|
};
|
|
144
168
|
const runAudit = (strict) => {
|
package/lib/commands/serve.js
CHANGED
|
@@ -155,10 +155,12 @@ 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 createMultiLangAsset = async (bucket, rigoToken, bcToken, courseSlug, courseJson, deployUrl) => {
|
|
158
|
+
const createMultiLangAsset = async (bucket, rigoToken, bcToken, courseSlug, courseJson, deployUrl, academyId) => {
|
|
159
|
+
var _a;
|
|
159
160
|
const availableLangs = Object.keys(courseJson.title);
|
|
160
161
|
console.log("AVAILABLE LANGUAGES to upload asset", availableLangs);
|
|
161
162
|
const all_translations = [];
|
|
163
|
+
const errors = [];
|
|
162
164
|
for (const lang of availableLangs) {
|
|
163
165
|
// eslint-disable-next-line no-await-in-loop
|
|
164
166
|
const indexReadme = await bucket.file(`courses/${courseSlug}/README${(0, creatorUtilities_1.getReadmeExtension)(lang)}`);
|
|
@@ -174,14 +176,28 @@ const createMultiLangAsset = async (bucket, rigoToken, bcToken, courseSlug, cour
|
|
|
174
176
|
indexReadmeString = "";
|
|
175
177
|
}
|
|
176
178
|
const b64IndexReadme = buffer_1.Buffer.from(indexReadmeString).toString("base64");
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
try {
|
|
180
|
+
// eslint-disable-next-line no-await-in-loop
|
|
181
|
+
const asset = await (0, publish_1.handleAssetCreation)({ token: bcToken, rigobotToken: rigoToken.trim() }, courseJson, lang, deployUrl, b64IndexReadme, academyId, all_translations);
|
|
182
|
+
if (!asset) {
|
|
183
|
+
errors.push({
|
|
184
|
+
lang,
|
|
185
|
+
error: { detail: "Failed to create asset", status_code: 500 },
|
|
186
|
+
});
|
|
187
|
+
console.log("No se pudo crear el asset, saltando idioma", lang);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
all_translations.push(asset.slug);
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
const errorData = error && typeof error === "object" && "response" in error ?
|
|
194
|
+
((_a = error.response) === null || _a === void 0 ? void 0 : _a.data) || error :
|
|
195
|
+
error;
|
|
196
|
+
errors.push({ lang, error: errorData });
|
|
197
|
+
console.error(`Error creating asset for language ${lang}:`, error);
|
|
182
198
|
}
|
|
183
|
-
all_translations.push(asset.slug);
|
|
184
199
|
}
|
|
200
|
+
return { errors };
|
|
185
201
|
};
|
|
186
202
|
const lessonCleaner = (lesson) => {
|
|
187
203
|
return Object.assign(Object.assign({}, lesson), { duration: undefined, generated: undefined, status: undefined, translations: undefined, uid: undefined, initialContent: undefined, locked: undefined });
|
|
@@ -2907,12 +2923,30 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
2907
2923
|
return res.status(500).json({ error: error.message });
|
|
2908
2924
|
}
|
|
2909
2925
|
});
|
|
2926
|
+
app.get("/actions/academies", async (req, res) => {
|
|
2927
|
+
try {
|
|
2928
|
+
const bcToken = req.header("x-breathecode-token");
|
|
2929
|
+
if (!bcToken) {
|
|
2930
|
+
return res
|
|
2931
|
+
.status(400)
|
|
2932
|
+
.json({
|
|
2933
|
+
error: "Authentication failed, missing breathecode token",
|
|
2934
|
+
});
|
|
2935
|
+
}
|
|
2936
|
+
const academies = await (0, api_1.listUserAcademies)(bcToken);
|
|
2937
|
+
return res.json(academies);
|
|
2938
|
+
}
|
|
2939
|
+
catch (error) {
|
|
2940
|
+
console.error("Error fetching academies:", error);
|
|
2941
|
+
return res.status(500).json({ error: error.message });
|
|
2942
|
+
}
|
|
2943
|
+
});
|
|
2910
2944
|
app.post("/actions/publish/:slug", async (req, res) => {
|
|
2911
2945
|
try {
|
|
2912
2946
|
const { slug } = req.params;
|
|
2913
2947
|
const rigoToken = req.header("x-rigo-token");
|
|
2914
2948
|
const bcToken = req.header("x-breathecode-token");
|
|
2915
|
-
|
|
2949
|
+
const { academyId } = req.body;
|
|
2916
2950
|
if (!rigoToken || !bcToken) {
|
|
2917
2951
|
return res
|
|
2918
2952
|
.status(400)
|
|
@@ -2998,10 +3032,13 @@ class ServeCommand extends SessionCommand_1.default {
|
|
|
2998
3032
|
const rigoRes = await axios_1.default.post(`${api_1.RIGOBOT_HOST}/v1/learnpack/upload`, form, {
|
|
2999
3033
|
headers: Object.assign(Object.assign({}, form.getHeaders()), { Authorization: "Token " + rigoToken.trim() }),
|
|
3000
3034
|
});
|
|
3001
|
-
await createMultiLangAsset(bucket, rigoToken, bcToken, slug, fullConfig.config, rigoRes.data.url);
|
|
3035
|
+
const assetResults = await createMultiLangAsset(bucket, rigoToken, bcToken, slug, fullConfig.config, rigoRes.data.url, academyId);
|
|
3002
3036
|
rimraf.sync(tmpRoot);
|
|
3003
3037
|
console.log("RigoRes", rigoRes.data);
|
|
3004
|
-
return res.json({
|
|
3038
|
+
return res.json({
|
|
3039
|
+
url: rigoRes.data.url,
|
|
3040
|
+
errors: assetResults.errors,
|
|
3041
|
+
});
|
|
3005
3042
|
});
|
|
3006
3043
|
archive.on("error", err => {
|
|
3007
3044
|
console.error("ZIP Error:", err);
|
package/lib/utils/api.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ type TAssetMissing = {
|
|
|
26
26
|
preview: string;
|
|
27
27
|
readme_raw: string;
|
|
28
28
|
all_translations: string[];
|
|
29
|
+
academy_id?: number;
|
|
29
30
|
};
|
|
30
31
|
export declare const createAsset: (token: string, asset: TAssetMissing) => Promise<any>;
|
|
31
32
|
export declare const doesAssetExists: (token: string, assetSlug: string) => Promise<{
|
package/lib/utils/api.js
CHANGED
|
@@ -358,10 +358,15 @@ const createAsset = async (token, asset) => {
|
|
|
358
358
|
readme_raw: asset.readme_raw,
|
|
359
359
|
all_translations: asset.all_translations,
|
|
360
360
|
};
|
|
361
|
-
|
|
361
|
+
let url = `https://breathecode.herokuapp.com/v1/registry/asset/me`;
|
|
362
362
|
const headers = {
|
|
363
363
|
Authorization: `Token ${token}`,
|
|
364
364
|
};
|
|
365
|
+
// Use academy-specific endpoint if academy_id is provided
|
|
366
|
+
if (asset.academy_id !== undefined) {
|
|
367
|
+
url = `https://breathecode.herokuapp.com/v1/registry/academy/asset`;
|
|
368
|
+
headers.Academy = String(asset.academy_id);
|
|
369
|
+
}
|
|
365
370
|
try {
|
|
366
371
|
const response = await axios_1.default.post(url, body, { headers });
|
|
367
372
|
return response.data;
|
|
@@ -373,6 +378,7 @@ const createAsset = async (token, asset) => {
|
|
|
373
378
|
};
|
|
374
379
|
exports.createAsset = createAsset;
|
|
375
380
|
const doesAssetExists = async (token, assetSlug) => {
|
|
381
|
+
var _a, _b, _c;
|
|
376
382
|
const url = `https://breathecode.herokuapp.com/v1/registry/asset/${assetSlug}`;
|
|
377
383
|
const headers = {
|
|
378
384
|
Authorization: `Token ${token}`,
|
|
@@ -380,11 +386,12 @@ const doesAssetExists = async (token, assetSlug) => {
|
|
|
380
386
|
try {
|
|
381
387
|
const response = await axios_1.default.get(url, { headers });
|
|
382
388
|
if (response.status === 200) {
|
|
383
|
-
|
|
389
|
+
const academyId = ((_b = (_a = response.data) === null || _a === void 0 ? void 0 : _a.academy) === null || _b === void 0 ? void 0 : _b.id) || ((_c = response.data) === null || _c === void 0 ? void 0 : _c.academy_id);
|
|
390
|
+
return { exists: true, academyId };
|
|
384
391
|
}
|
|
385
392
|
return { exists: false };
|
|
386
393
|
}
|
|
387
|
-
catch (
|
|
394
|
+
catch (_d) {
|
|
388
395
|
// console.error("Failed to get asset:", error)
|
|
389
396
|
return { exists: false };
|
|
390
397
|
}
|
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.334",
|
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
|
6
6
|
"contributors": [
|
|
7
7
|
{
|
package/src/commands/publish.ts
CHANGED
|
@@ -60,6 +60,7 @@ export const handleAssetCreation = async (
|
|
|
60
60
|
selectedLang: string,
|
|
61
61
|
learnpackDeployUrl: string,
|
|
62
62
|
b64IndexReadme: string,
|
|
63
|
+
academyId: number | undefined,
|
|
63
64
|
all_translations: string[] = []
|
|
64
65
|
) => {
|
|
65
66
|
const category = "uncategorized"
|
|
@@ -82,20 +83,41 @@ export const handleAssetCreation = async (
|
|
|
82
83
|
let slug = slugify(assetTitle).slice(0, 47)
|
|
83
84
|
slug = `${slug}-${selectedLang}`
|
|
84
85
|
|
|
85
|
-
const { exists } = await api.doesAssetExists(
|
|
86
|
+
const { exists, academyId: existingAcademyId } = await api.doesAssetExists(
|
|
87
|
+
sessionPayload.token,
|
|
88
|
+
slug
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
// Compare academy IDs if asset exists and academyId is provided
|
|
92
|
+
if (
|
|
93
|
+
exists &&
|
|
94
|
+
existingAcademyId !== undefined &&
|
|
95
|
+
academyId !== undefined &&
|
|
96
|
+
existingAcademyId !== academyId
|
|
97
|
+
) {
|
|
98
|
+
Console.warning(
|
|
99
|
+
`Asset exists in academy ${existingAcademyId}, but attempting to publish to academy ${academyId}. ` +
|
|
100
|
+
`The asset will be updated in its current academy (${existingAcademyId}).`
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// const technologies: unknown[] = Array.isArray(learnJson?.technologies) ?
|
|
105
|
+
// learnJson.technologies :
|
|
106
|
+
// []
|
|
86
107
|
|
|
87
108
|
if (!exists) {
|
|
88
109
|
Console.info("Asset does not exist in this academy, creating it")
|
|
89
|
-
const
|
|
110
|
+
const assetPayload: any = {
|
|
90
111
|
slug: slug,
|
|
91
112
|
title: assetTitle,
|
|
92
113
|
lang: selectedLang,
|
|
93
114
|
graded: true,
|
|
94
115
|
description: assetDescription,
|
|
95
116
|
learnpack_deploy_url: learnpackDeployUrl,
|
|
96
|
-
technologies:
|
|
97
|
-
|
|
98
|
-
),
|
|
117
|
+
// technologies: technologies.map((tech: unknown) =>
|
|
118
|
+
// String(tech).toLowerCase().replace(/\s+/g, "-")
|
|
119
|
+
// ),
|
|
120
|
+
technologies: [],
|
|
99
121
|
url: learnpackDeployUrl,
|
|
100
122
|
category: category,
|
|
101
123
|
owner: user.id,
|
|
@@ -103,7 +125,12 @@ export const handleAssetCreation = async (
|
|
|
103
125
|
preview: learnJson.preview,
|
|
104
126
|
readme_raw: b64IndexReadme,
|
|
105
127
|
all_translations,
|
|
106
|
-
}
|
|
128
|
+
}
|
|
129
|
+
if (academyId !== undefined) {
|
|
130
|
+
assetPayload.academy_id = academyId
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const asset = await api.createAsset(sessionPayload.token, assetPayload)
|
|
107
134
|
try {
|
|
108
135
|
await api.updateRigoPackage(
|
|
109
136
|
sessionPayload.rigobotToken.trim(),
|
|
@@ -145,7 +172,7 @@ export const handleAssetCreation = async (
|
|
|
145
172
|
return asset
|
|
146
173
|
} catch (error) {
|
|
147
174
|
Console.error("Error updating or creating asset:", error)
|
|
148
|
-
|
|
175
|
+
throw error
|
|
149
176
|
}
|
|
150
177
|
}
|
|
151
178
|
|
|
@@ -182,22 +209,28 @@ const createMultiLangAssetFromDisk = async (
|
|
|
182
209
|
|
|
183
210
|
const b64IndexReadme = Buffer.from(indexReadmeString).toString("base64")
|
|
184
211
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
212
|
+
try {
|
|
213
|
+
// eslint-disable-next-line no-await-in-loop
|
|
214
|
+
const asset = await handleAssetCreation(
|
|
215
|
+
sessionPayload,
|
|
216
|
+
learnJson,
|
|
217
|
+
lang,
|
|
218
|
+
deployUrl,
|
|
219
|
+
b64IndexReadme,
|
|
220
|
+
undefined,
|
|
221
|
+
all_translations
|
|
222
|
+
)
|
|
194
223
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
224
|
+
if (!asset) {
|
|
225
|
+
Console.debug("Could not create/update asset for lang", lang)
|
|
226
|
+
continue
|
|
227
|
+
}
|
|
199
228
|
|
|
200
|
-
|
|
229
|
+
all_translations.push(asset.slug)
|
|
230
|
+
} catch (error) {
|
|
231
|
+
Console.error("Error creating asset for language", lang, error)
|
|
232
|
+
// Continue with other languages
|
|
233
|
+
}
|
|
201
234
|
}
|
|
202
235
|
}
|
|
203
236
|
|
package/src/commands/serve.ts
CHANGED
|
@@ -49,7 +49,11 @@ import {
|
|
|
49
49
|
// import { handleAssetCreation } from "./publish"
|
|
50
50
|
import axios from "axios"
|
|
51
51
|
import * as FormData from "form-data"
|
|
52
|
-
import api, {
|
|
52
|
+
import api, {
|
|
53
|
+
RIGOBOT_HOST,
|
|
54
|
+
RIGOBOT_REALTIME_HOST,
|
|
55
|
+
listUserAcademies,
|
|
56
|
+
} from "../utils/api"
|
|
53
57
|
import {
|
|
54
58
|
createUploadMiddleware,
|
|
55
59
|
minutesToISO8601Duration,
|
|
@@ -279,12 +283,14 @@ const createMultiLangAsset = async (
|
|
|
279
283
|
bcToken: string,
|
|
280
284
|
courseSlug: string,
|
|
281
285
|
courseJson: any,
|
|
282
|
-
deployUrl: string
|
|
283
|
-
|
|
286
|
+
deployUrl: string,
|
|
287
|
+
academyId?: number
|
|
288
|
+
): Promise<{ errors: Array<{ lang: string; error: any }> }> => {
|
|
284
289
|
const availableLangs = Object.keys(courseJson.title)
|
|
285
290
|
console.log("AVAILABLE LANGUAGES to upload asset", availableLangs)
|
|
286
291
|
|
|
287
292
|
const all_translations: string[] = []
|
|
293
|
+
const errors: Array<{ lang: string; error: any }> = []
|
|
288
294
|
|
|
289
295
|
for (const lang of availableLangs) {
|
|
290
296
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -304,23 +310,39 @@ const createMultiLangAsset = async (
|
|
|
304
310
|
|
|
305
311
|
const b64IndexReadme = Buffer.from(indexReadmeString).toString("base64")
|
|
306
312
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
313
|
+
try {
|
|
314
|
+
// eslint-disable-next-line no-await-in-loop
|
|
315
|
+
const asset = await handleAssetCreation(
|
|
316
|
+
{ token: bcToken, rigobotToken: rigoToken.trim() },
|
|
317
|
+
courseJson,
|
|
318
|
+
lang,
|
|
319
|
+
deployUrl,
|
|
320
|
+
b64IndexReadme,
|
|
321
|
+
academyId,
|
|
322
|
+
all_translations
|
|
323
|
+
)
|
|
316
324
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
325
|
+
if (!asset) {
|
|
326
|
+
errors.push({
|
|
327
|
+
lang,
|
|
328
|
+
error: { detail: "Failed to create asset", status_code: 500 },
|
|
329
|
+
})
|
|
330
|
+
console.log("No se pudo crear el asset, saltando idioma", lang)
|
|
331
|
+
continue
|
|
332
|
+
}
|
|
321
333
|
|
|
322
|
-
|
|
334
|
+
all_translations.push(asset.slug)
|
|
335
|
+
} catch (error) {
|
|
336
|
+
const errorData =
|
|
337
|
+
error && typeof error === "object" && "response" in error ?
|
|
338
|
+
(error as any).response?.data || error :
|
|
339
|
+
error
|
|
340
|
+
errors.push({ lang, error: errorData })
|
|
341
|
+
console.error(`Error creating asset for language ${lang}:`, error)
|
|
342
|
+
}
|
|
323
343
|
}
|
|
344
|
+
|
|
345
|
+
return { errors }
|
|
324
346
|
}
|
|
325
347
|
|
|
326
348
|
const lessonCleaner = (lesson: Lesson) => {
|
|
@@ -4233,12 +4255,32 @@ class ServeCommand extends SessionCommand {
|
|
|
4233
4255
|
}
|
|
4234
4256
|
)
|
|
4235
4257
|
|
|
4258
|
+
app.get("/actions/academies", async (req, res) => {
|
|
4259
|
+
try {
|
|
4260
|
+
const bcToken = req.header("x-breathecode-token")
|
|
4261
|
+
|
|
4262
|
+
if (!bcToken) {
|
|
4263
|
+
return res
|
|
4264
|
+
.status(400)
|
|
4265
|
+
.json({
|
|
4266
|
+
error: "Authentication failed, missing breathecode token",
|
|
4267
|
+
})
|
|
4268
|
+
}
|
|
4269
|
+
|
|
4270
|
+
const academies = await listUserAcademies(bcToken)
|
|
4271
|
+
return res.json(academies)
|
|
4272
|
+
} catch (error) {
|
|
4273
|
+
console.error("Error fetching academies:", error)
|
|
4274
|
+
return res.status(500).json({ error: (error as Error).message })
|
|
4275
|
+
}
|
|
4276
|
+
})
|
|
4277
|
+
|
|
4236
4278
|
app.post("/actions/publish/:slug", async (req, res) => {
|
|
4237
4279
|
try {
|
|
4238
4280
|
const { slug } = req.params
|
|
4239
4281
|
const rigoToken = req.header("x-rigo-token")
|
|
4240
4282
|
const bcToken = req.header("x-breathecode-token")
|
|
4241
|
-
|
|
4283
|
+
const { academyId } = req.body
|
|
4242
4284
|
|
|
4243
4285
|
if (!rigoToken || !bcToken) {
|
|
4244
4286
|
return res
|
|
@@ -4360,18 +4402,22 @@ class ServeCommand extends SessionCommand {
|
|
|
4360
4402
|
}
|
|
4361
4403
|
)
|
|
4362
4404
|
|
|
4363
|
-
await createMultiLangAsset(
|
|
4405
|
+
const assetResults = await createMultiLangAsset(
|
|
4364
4406
|
bucket,
|
|
4365
4407
|
rigoToken,
|
|
4366
4408
|
bcToken,
|
|
4367
4409
|
slug,
|
|
4368
4410
|
fullConfig.config,
|
|
4369
|
-
rigoRes.data.url
|
|
4411
|
+
rigoRes.data.url,
|
|
4412
|
+
academyId
|
|
4370
4413
|
)
|
|
4371
4414
|
|
|
4372
4415
|
rimraf.sync(tmpRoot)
|
|
4373
4416
|
console.log("RigoRes", rigoRes.data)
|
|
4374
|
-
return res.json({
|
|
4417
|
+
return res.json({
|
|
4418
|
+
url: rigoRes.data.url,
|
|
4419
|
+
errors: assetResults.errors,
|
|
4420
|
+
})
|
|
4375
4421
|
})
|
|
4376
4422
|
|
|
4377
4423
|
archive.on("error", err => {
|
package/src/utils/api.ts
CHANGED
|
@@ -431,10 +431,11 @@ type TAssetMissing = {
|
|
|
431
431
|
preview: string;
|
|
432
432
|
readme_raw: string;
|
|
433
433
|
all_translations: string[];
|
|
434
|
+
academy_id?: number;
|
|
434
435
|
};
|
|
435
436
|
|
|
436
437
|
export const createAsset = async (token: string, asset: TAssetMissing) => {
|
|
437
|
-
const body = {
|
|
438
|
+
const body: any = {
|
|
438
439
|
slug: asset.slug,
|
|
439
440
|
title: asset.title,
|
|
440
441
|
lang: asset.lang,
|
|
@@ -462,11 +463,18 @@ export const createAsset = async (token: string, asset: TAssetMissing) => {
|
|
|
462
463
|
readme_raw: asset.readme_raw,
|
|
463
464
|
all_translations: asset.all_translations,
|
|
464
465
|
}
|
|
465
|
-
|
|
466
|
-
|
|
466
|
+
|
|
467
|
+
let url = `https://breathecode.herokuapp.com/v1/registry/asset/me`
|
|
468
|
+
const headers: any = {
|
|
467
469
|
Authorization: `Token ${token}`,
|
|
468
470
|
}
|
|
469
471
|
|
|
472
|
+
// Use academy-specific endpoint if academy_id is provided
|
|
473
|
+
if (asset.academy_id !== undefined) {
|
|
474
|
+
url = `https://breathecode.herokuapp.com/v1/registry/academy/asset`
|
|
475
|
+
headers.Academy = String(asset.academy_id)
|
|
476
|
+
}
|
|
477
|
+
|
|
470
478
|
try {
|
|
471
479
|
const response = await axios.post(url, body, { headers })
|
|
472
480
|
return response.data
|
|
@@ -489,7 +497,8 @@ export const doesAssetExists = async (
|
|
|
489
497
|
try {
|
|
490
498
|
const response = await axios.get(url, { headers })
|
|
491
499
|
if (response.status === 200) {
|
|
492
|
-
|
|
500
|
+
const academyId = response.data?.academy?.id || response.data?.academy_id
|
|
501
|
+
return { exists: true, academyId }
|
|
493
502
|
}
|
|
494
503
|
|
|
495
504
|
return { exists: false }
|