@learnpack/learnpack 5.0.50 → 5.0.51
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/README.md +12 -12
- package/lib/commands/publish.js +35 -6
- package/lib/utils/api.d.ts +20 -0
- package/lib/utils/api.js +95 -4
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/commands/publish.ts +54 -6
- package/src/utils/api.ts +120 -3
package/README.md
CHANGED
@@ -21,7 +21,7 @@ $ npm install -g @learnpack/learnpack
|
|
21
21
|
$ learnpack COMMAND
|
22
22
|
running command...
|
23
23
|
$ learnpack (-v|--version|version)
|
24
|
-
@learnpack/learnpack/5.0.
|
24
|
+
@learnpack/learnpack/5.0.51 win32-x64 node-v22.14.0
|
25
25
|
$ learnpack --help [COMMAND]
|
26
26
|
USAGE
|
27
27
|
$ learnpack COMMAND
|
@@ -79,7 +79,7 @@ DESCRIPTION
|
|
79
79
|
12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
|
80
80
|
```
|
81
81
|
|
82
|
-
_See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
82
|
+
_See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.51/src\commands\audit.ts)_
|
83
83
|
|
84
84
|
## `learnpack breakToken`
|
85
85
|
|
@@ -94,7 +94,7 @@ OPTIONS
|
|
94
94
|
-y, --yes Skip all prompts and initialize an empty project
|
95
95
|
```
|
96
96
|
|
97
|
-
_See code: [src\commands\breakToken.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
97
|
+
_See code: [src\commands\breakToken.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.51/src\commands\breakToken.ts)_
|
98
98
|
|
99
99
|
## `learnpack clean`
|
100
100
|
|
@@ -109,7 +109,7 @@ DESCRIPTION
|
|
109
109
|
Extra documentation goes here
|
110
110
|
```
|
111
111
|
|
112
|
-
_See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
112
|
+
_See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.51/src\commands\clean.ts)_
|
113
113
|
|
114
114
|
## `learnpack download [PACKAGE]`
|
115
115
|
|
@@ -127,7 +127,7 @@ DESCRIPTION
|
|
127
127
|
Extra documentation goes here
|
128
128
|
```
|
129
129
|
|
130
|
-
_See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
130
|
+
_See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.51/src\commands\download.ts)_
|
131
131
|
|
132
132
|
## `learnpack help [COMMAND]`
|
133
133
|
|
@@ -159,7 +159,7 @@ OPTIONS
|
|
159
159
|
-y, --yes Skip all prompts and initialize an empty project
|
160
160
|
```
|
161
161
|
|
162
|
-
_See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
162
|
+
_See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.51/src\commands\init.ts)_
|
163
163
|
|
164
164
|
## `learnpack login [PACKAGE]`
|
165
165
|
|
@@ -177,7 +177,7 @@ DESCRIPTION
|
|
177
177
|
Extra documentation goes here
|
178
178
|
```
|
179
179
|
|
180
|
-
_See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
180
|
+
_See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.51/src\commands\login.ts)_
|
181
181
|
|
182
182
|
## `learnpack logout [PACKAGE]`
|
183
183
|
|
@@ -195,7 +195,7 @@ DESCRIPTION
|
|
195
195
|
Extra documentation goes here
|
196
196
|
```
|
197
197
|
|
198
|
-
_See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
198
|
+
_See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.51/src\commands\logout.ts)_
|
199
199
|
|
200
200
|
## `learnpack plugins`
|
201
201
|
|
@@ -327,7 +327,7 @@ OPTIONS
|
|
327
327
|
-s, --strict strict mode
|
328
328
|
```
|
329
329
|
|
330
|
-
_See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
330
|
+
_See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.51/src\commands\publish.ts)_
|
331
331
|
|
332
332
|
## `learnpack start`
|
333
333
|
|
@@ -349,7 +349,7 @@ OPTIONS
|
|
349
349
|
-y, --yes Skip all prompts and initialize an empty project
|
350
350
|
```
|
351
351
|
|
352
|
-
_See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
352
|
+
_See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.51/src\commands\start.ts)_
|
353
353
|
|
354
354
|
## `learnpack test [EXERCISESLUG]`
|
355
355
|
|
@@ -366,7 +366,7 @@ OPTIONS
|
|
366
366
|
-y, --yes Skip all prompts and initialize an empty project
|
367
367
|
```
|
368
368
|
|
369
|
-
_See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
369
|
+
_See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.51/src\commands\test.ts)_
|
370
370
|
|
371
371
|
## `learnpack translate`
|
372
372
|
|
@@ -380,7 +380,7 @@ OPTIONS
|
|
380
380
|
-y, --yes Skip all prompts and initialize an empty project
|
381
381
|
```
|
382
382
|
|
383
|
-
_See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
383
|
+
_See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.51/src\commands\translate.ts)_
|
384
384
|
<!-- commandsstop -->
|
385
385
|
|
386
386
|
> > > > > > > 0cb3e56d84c197f9d008836bb573eade212b7e57
|
package/lib/commands/publish.js
CHANGED
@@ -17,6 +17,36 @@ const api_1 = require("../utils/api");
|
|
17
17
|
const prompts = require("prompts");
|
18
18
|
const rigoActions_1 = require("../utils/rigoActions");
|
19
19
|
const uploadZipEndpont = api_1.RIGOBOT_HOST + "/v1/learnpack/upload";
|
20
|
+
const handleAssetCreation = async (sessionPayload, academy, learnJson, learnpackDeployUrl) => {
|
21
|
+
try {
|
22
|
+
const { exists, academyId } = await api_1.default.doesAssetExists(sessionPayload.token, learnJson.slug);
|
23
|
+
if (!exists) {
|
24
|
+
console_1.default.info("Asset does not exist in this academy, creating it");
|
25
|
+
const asset = await api_1.default.createAsset(sessionPayload.token, academy.id, {
|
26
|
+
slug: learnJson.slug,
|
27
|
+
title: learnJson.title.us,
|
28
|
+
lang: "us",
|
29
|
+
description: learnJson.description.us,
|
30
|
+
learnpack_deploy_url: learnpackDeployUrl,
|
31
|
+
technologies: ["node", "bash"],
|
32
|
+
url: "https://4geeksacademy.com",
|
33
|
+
});
|
34
|
+
console_1.default.info("Asset created with id", asset.id);
|
35
|
+
}
|
36
|
+
else {
|
37
|
+
console_1.default.info("Asset exists, updating it");
|
38
|
+
const asset = await api_1.default.updateAsset(sessionPayload.token, academyId, learnJson.slug, {
|
39
|
+
learnpack_deploy_url: learnpackDeployUrl,
|
40
|
+
title: learnJson.title.us,
|
41
|
+
description: learnJson.description.us,
|
42
|
+
});
|
43
|
+
console_1.default.info("Asset updated with id", asset.id);
|
44
|
+
}
|
45
|
+
}
|
46
|
+
catch (error) {
|
47
|
+
console_1.default.error("Error updating or creating asset:", error);
|
48
|
+
}
|
49
|
+
};
|
20
50
|
const runAudit = (strict) => {
|
21
51
|
try {
|
22
52
|
console_1.default.info("Running learnpack audit before publishing...");
|
@@ -104,10 +134,9 @@ class BuildCommand extends SessionCommand_1.default {
|
|
104
134
|
console_1.default.debug("Building exercises");
|
105
135
|
(_c = this.configManager) === null || _c === void 0 ? void 0 : _c.buildIndex();
|
106
136
|
}
|
107
|
-
|
137
|
+
const academies = await api_1.default.listUserAcademies(sessionPayload.token);
|
108
138
|
// // console.log(academies, "academies")
|
109
|
-
|
110
|
-
// console.log(academy, "academy")
|
139
|
+
const academy = await selectAcademy(academies);
|
111
140
|
// Read learn.json to get the slug
|
112
141
|
const learnJsonPath = path.join(process.cwd(), "learn.json");
|
113
142
|
if (!fs.existsSync(learnJsonPath)) {
|
@@ -225,9 +254,9 @@ class BuildCommand extends SessionCommand_1.default {
|
|
225
254
|
headers: Object.assign(Object.assign({}, formData.getHeaders()), { Authorization: `Token ${rigoToken}` }),
|
226
255
|
});
|
227
256
|
console.log(res.data);
|
228
|
-
// Remove the zip file after uploading
|
229
257
|
fs.unlinkSync(zipFilePath);
|
230
258
|
this.removeDirectory(buildDir);
|
259
|
+
await handleAssetCreation(sessionPayload, academy, learnJson, res.data.url);
|
231
260
|
}
|
232
261
|
catch (error) {
|
233
262
|
if (axios_1.default.isAxiosError(error)) {
|
@@ -244,8 +273,8 @@ class BuildCommand extends SessionCommand_1.default {
|
|
244
273
|
else {
|
245
274
|
console.error("Error uploading file:", error);
|
246
275
|
}
|
247
|
-
fs.unlinkSync(zipFilePath)
|
248
|
-
this.removeDirectory(buildDir)
|
276
|
+
// fs.unlinkSync(zipFilePath)
|
277
|
+
// this.removeDirectory(buildDir)
|
249
278
|
}
|
250
279
|
});
|
251
280
|
archive.on("error", (err) => {
|
package/lib/utils/api.d.ts
CHANGED
@@ -10,6 +10,20 @@ export interface TAcademy {
|
|
10
10
|
}
|
11
11
|
export declare const listUserAcademies: (breathecodeToken: string) => Promise<TAcademy[]>;
|
12
12
|
export declare const validateToken: (token: string) => Promise<any>;
|
13
|
+
type TAssetMissing = {
|
14
|
+
slug: string;
|
15
|
+
title: string;
|
16
|
+
lang: string;
|
17
|
+
url: string;
|
18
|
+
description: string;
|
19
|
+
learnpack_deploy_url: string;
|
20
|
+
technologies: string[];
|
21
|
+
};
|
22
|
+
export declare const createAsset: (token: string, academyId: number, asset: TAssetMissing) => Promise<any>;
|
23
|
+
export declare const doesAssetExists: (token: string, assetSlug: string) => Promise<{
|
24
|
+
exists: boolean;
|
25
|
+
academyId?: number;
|
26
|
+
}>;
|
13
27
|
declare const _default: {
|
14
28
|
login: (identification: string, password: string) => Promise<any>;
|
15
29
|
publish: (config: any) => Promise<any>;
|
@@ -24,5 +38,11 @@ declare const _default: {
|
|
24
38
|
sendStreamTelemetry: (url: string, body: object) => Promise<void>;
|
25
39
|
listUserAcademies: (breathecodeToken: string) => Promise<TAcademy[]>;
|
26
40
|
validateToken: (token: string) => Promise<any>;
|
41
|
+
createAsset: (token: string, academyId: number, asset: TAssetMissing) => Promise<any>;
|
42
|
+
doesAssetExists: (token: string, assetSlug: string) => Promise<{
|
43
|
+
exists: boolean;
|
44
|
+
academyId?: number;
|
45
|
+
}>;
|
46
|
+
updateAsset: (token: string, academyId: number, assetSlug: string, asset: Partial<TAssetMissing>) => Promise<any>;
|
27
47
|
};
|
28
48
|
export default _default;
|
package/lib/utils/api.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.validateToken = exports.listUserAcademies = exports.getConsumable = exports.countConsumables = exports.RIGOBOT_HOST = void 0;
|
3
|
+
exports.doesAssetExists = exports.createAsset = exports.validateToken = exports.listUserAcademies = exports.getConsumable = exports.countConsumables = exports.RIGOBOT_HOST = void 0;
|
4
4
|
const console_1 = require("../utils/console");
|
5
5
|
const storage = require("node-persist");
|
6
6
|
const cli_ux_1 = require("cli-ux");
|
@@ -272,6 +272,14 @@ const getConsumable = async (token, consumableSlug = "ai-generation") => {
|
|
272
272
|
}
|
273
273
|
};
|
274
274
|
exports.getConsumable = getConsumable;
|
275
|
+
const with_crud_asset_roles = new Set([
|
276
|
+
"content_writer",
|
277
|
+
"growth_manager",
|
278
|
+
"syllabus_coordinator",
|
279
|
+
"country_manager",
|
280
|
+
"community_manager",
|
281
|
+
"carrer_support_head",
|
282
|
+
]);
|
275
283
|
const listUserAcademies = async (breathecodeToken) => {
|
276
284
|
const url = "https://breathecode.herokuapp.com/v1/auth/user/me";
|
277
285
|
try {
|
@@ -283,9 +291,12 @@ const listUserAcademies = async (breathecodeToken) => {
|
|
283
291
|
const data = response.data;
|
284
292
|
const academiesMap = new Map();
|
285
293
|
for (const role of data.roles) {
|
286
|
-
|
287
|
-
if (
|
288
|
-
|
294
|
+
// Only add academies where the user's role is in the whitelist
|
295
|
+
if (with_crud_asset_roles.has(role.role)) {
|
296
|
+
const academy = role.academy;
|
297
|
+
if (!academiesMap.has(academy.id)) {
|
298
|
+
academiesMap.set(academy.id, academy);
|
299
|
+
}
|
289
300
|
}
|
290
301
|
}
|
291
302
|
return [...academiesMap.values()];
|
@@ -310,6 +321,83 @@ const validateToken = async (token) => {
|
|
310
321
|
}
|
311
322
|
};
|
312
323
|
exports.validateToken = validateToken;
|
324
|
+
const createAsset = async (token, academyId, asset) => {
|
325
|
+
const body = {
|
326
|
+
slug: asset.slug,
|
327
|
+
title: asset.title,
|
328
|
+
lang: asset.lang,
|
329
|
+
asset_type: "EXERCISE",
|
330
|
+
visibility: "PUBLIC",
|
331
|
+
status: "PUBLISHED",
|
332
|
+
url: "https://4geeksacademy.com",
|
333
|
+
readme_url: null,
|
334
|
+
difficulty: null,
|
335
|
+
duration: null,
|
336
|
+
graded: false,
|
337
|
+
gitpod: true,
|
338
|
+
category: 7,
|
339
|
+
preview: null,
|
340
|
+
description: asset.description,
|
341
|
+
external: true,
|
342
|
+
interactive: true,
|
343
|
+
solution_video_url: null,
|
344
|
+
intro_video_url: null,
|
345
|
+
translations: ["us"],
|
346
|
+
learnpack_deploy_url: asset.learnpack_deploy_url,
|
347
|
+
technologies: asset.technologies,
|
348
|
+
};
|
349
|
+
const url = `https://breathecode.herokuapp.com/v1/registry/academy/asset`;
|
350
|
+
const headers = {
|
351
|
+
Authorization: `Token ${token}`,
|
352
|
+
Academy: academyId,
|
353
|
+
};
|
354
|
+
try {
|
355
|
+
const response = await axios_1.default.post(url, body, { headers });
|
356
|
+
return response.data;
|
357
|
+
}
|
358
|
+
catch (error) {
|
359
|
+
// console.error("Failed to create asset:", error)
|
360
|
+
throw error.response.data;
|
361
|
+
}
|
362
|
+
};
|
363
|
+
exports.createAsset = createAsset;
|
364
|
+
const doesAssetExists = async (token, assetSlug) => {
|
365
|
+
const url = `https://breathecode.herokuapp.com/v1/registry/asset/${assetSlug}`;
|
366
|
+
const headers = {
|
367
|
+
Authorization: `Token ${token}`,
|
368
|
+
};
|
369
|
+
try {
|
370
|
+
const response = await axios_1.default.get(url, { headers });
|
371
|
+
if (response.status === 200) {
|
372
|
+
const data = response.data;
|
373
|
+
const academy = data.academy.id;
|
374
|
+
return { exists: true, academyId: academy };
|
375
|
+
}
|
376
|
+
return { exists: false };
|
377
|
+
}
|
378
|
+
catch (error) {
|
379
|
+
console.error("Failed to get asset:", error);
|
380
|
+
return { exists: false };
|
381
|
+
}
|
382
|
+
};
|
383
|
+
exports.doesAssetExists = doesAssetExists;
|
384
|
+
const updateAsset = async (token, academyId, assetSlug, asset) => {
|
385
|
+
const url = `https://breathecode.herokuapp.com/v1/registry/academy/asset/${assetSlug}`;
|
386
|
+
const headers = {
|
387
|
+
Authorization: `Token ${token}`,
|
388
|
+
Academy: academyId,
|
389
|
+
};
|
390
|
+
try {
|
391
|
+
const response = await axios_1.default.put(url, asset, { headers });
|
392
|
+
return response.data;
|
393
|
+
}
|
394
|
+
catch (error) {
|
395
|
+
// console.error("Failed to update asset:", error)
|
396
|
+
// Try to print the data
|
397
|
+
// console.log(error.response.data)
|
398
|
+
throw error.response.data;
|
399
|
+
}
|
400
|
+
};
|
313
401
|
exports.default = {
|
314
402
|
login,
|
315
403
|
publish,
|
@@ -321,4 +409,7 @@ exports.default = {
|
|
321
409
|
sendStreamTelemetry,
|
322
410
|
listUserAcademies: exports.listUserAcademies,
|
323
411
|
validateToken: exports.validateToken,
|
412
|
+
createAsset: exports.createAsset,
|
413
|
+
doesAssetExists: exports.doesAssetExists,
|
414
|
+
updateAsset,
|
324
415
|
};
|
package/oclif.manifest.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":"5.0.
|
1
|
+
{"version":"5.0.51","commands":{"audit":{"id":"audit","description":"learnpack audit is the command in charge of creating an auditory of the repository\n...\nlearnpack audit checks for the following information in a repository:\n 1. The configuration object has slug, repository and description. (Error)\n 2. The command learnpack clean has been run. (Error)\n 3. If a markdown or test file doesn't have any content. (Error)\n 4. The links are accessing to valid servers. (Error)\n 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)\n 6. The external images are working (If they are pointing to a valid server). (Error)\n 7. The exercises directory names are valid. (Error)\n 8. If an exercise doesn't have a README file. (Error)\n 9. The exercises array (Of the config file) has content. (Error)\n 10. The exercses have the same translations. (Warning)\n 11. The .gitignore file exists. (Warning)\n 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false}},"args":[]},"breakToken":{"id":"breakToken","description":"Break the token","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"clean":{"id":"clean","description":"Clean the configuration object\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"download":{"id":"download","description":"Describe the command here\n...\nExtra documentation goes here\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"init":{"id":"init","description":"Create a new learning package: Book, Tutorial or Exercise","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"logout":{"id":"logout","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"publish":{"id":"publish","description":"Builds the project by copying necessary files and directories into a zip file","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"start":{"id":"start","description":"Runs a small server with all the exercise instructions","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"disableGrading":{"name":"disableGrading","type":"boolean","char":"D","description":"disble grading functionality","allowNo":false},"watch":{"name":"watch","type":"boolean","char":"w","description":"Watch for file changes","allowNo":false},"editor":{"name":"editor","type":"option","char":"e","description":"[preview, extension]","options":["extension","preview"]},"version":{"name":"version","type":"option","char":"v","description":"E.g: 1.0.1"},"grading":{"name":"grading","type":"option","char":"g","description":"[isolated, incremental]","options":["isolated","incremental"]},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"test":{"id":"test","description":"Test exercises","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]},"translate":{"id":"translate","description":"List all the lessons, the user is able of select many of them to translate to the given languages","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[]}}}
|
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.51",
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
6
6
|
"contributors": [
|
7
7
|
{
|
package/src/commands/publish.ts
CHANGED
@@ -21,6 +21,48 @@ import { generateCourseShortName, isValidRigoToken } from "../utils/rigoActions"
|
|
21
21
|
|
22
22
|
const uploadZipEndpont = RIGOBOT_HOST + "/v1/learnpack/upload"
|
23
23
|
|
24
|
+
const handleAssetCreation = async (
|
25
|
+
sessionPayload: any,
|
26
|
+
academy: TAcademy,
|
27
|
+
learnJson: any,
|
28
|
+
learnpackDeployUrl: string
|
29
|
+
) => {
|
30
|
+
try {
|
31
|
+
const { exists, academyId } = await api.doesAssetExists(
|
32
|
+
sessionPayload.token,
|
33
|
+
learnJson.slug
|
34
|
+
)
|
35
|
+
if (!exists) {
|
36
|
+
Console.info("Asset does not exist in this academy, creating it")
|
37
|
+
const asset = await api.createAsset(sessionPayload.token, academy.id, {
|
38
|
+
slug: learnJson.slug,
|
39
|
+
title: learnJson.title.us,
|
40
|
+
lang: "us",
|
41
|
+
description: learnJson.description.us,
|
42
|
+
learnpack_deploy_url: learnpackDeployUrl,
|
43
|
+
technologies: ["node", "bash"],
|
44
|
+
url: "https://4geeksacademy.com",
|
45
|
+
})
|
46
|
+
Console.info("Asset created with id", asset.id)
|
47
|
+
} else {
|
48
|
+
Console.info("Asset exists, updating it")
|
49
|
+
const asset = await api.updateAsset(
|
50
|
+
sessionPayload.token,
|
51
|
+
academyId as number,
|
52
|
+
learnJson.slug,
|
53
|
+
{
|
54
|
+
learnpack_deploy_url: learnpackDeployUrl,
|
55
|
+
title: learnJson.title.us,
|
56
|
+
description: learnJson.description.us,
|
57
|
+
}
|
58
|
+
)
|
59
|
+
Console.info("Asset updated with id", asset.id)
|
60
|
+
}
|
61
|
+
} catch (error) {
|
62
|
+
Console.error("Error updating or creating asset:", error)
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
24
66
|
const runAudit = (strict: boolean) => {
|
25
67
|
try {
|
26
68
|
Console.info("Running learnpack audit before publishing...")
|
@@ -148,10 +190,9 @@ class BuildCommand extends SessionCommand {
|
|
148
190
|
this.configManager?.buildIndex()
|
149
191
|
}
|
150
192
|
|
151
|
-
|
193
|
+
const academies = await api.listUserAcademies(sessionPayload.token)
|
152
194
|
// // console.log(academies, "academies")
|
153
|
-
|
154
|
-
// console.log(academy, "academy")
|
195
|
+
const academy = await selectAcademy(academies)
|
155
196
|
|
156
197
|
// Read learn.json to get the slug
|
157
198
|
const learnJsonPath = path.join(process.cwd(), "learn.json")
|
@@ -306,9 +347,16 @@ class BuildCommand extends SessionCommand {
|
|
306
347
|
},
|
307
348
|
})
|
308
349
|
console.log(res.data)
|
309
|
-
|
350
|
+
|
310
351
|
fs.unlinkSync(zipFilePath)
|
311
352
|
this.removeDirectory(buildDir)
|
353
|
+
|
354
|
+
await handleAssetCreation(
|
355
|
+
sessionPayload,
|
356
|
+
academy,
|
357
|
+
learnJson,
|
358
|
+
res.data.url
|
359
|
+
)
|
312
360
|
} catch (error) {
|
313
361
|
if (axios.isAxiosError(error)) {
|
314
362
|
if (error.response && error.response.status === 403) {
|
@@ -322,8 +370,8 @@ class BuildCommand extends SessionCommand {
|
|
322
370
|
console.error("Error uploading file:", error)
|
323
371
|
}
|
324
372
|
|
325
|
-
fs.unlinkSync(zipFilePath)
|
326
|
-
this.removeDirectory(buildDir)
|
373
|
+
// fs.unlinkSync(zipFilePath)
|
374
|
+
// this.removeDirectory(buildDir)
|
327
375
|
}
|
328
376
|
})
|
329
377
|
|
package/src/utils/api.ts
CHANGED
@@ -349,6 +349,15 @@ export interface TAcademy {
|
|
349
349
|
timezone: string
|
350
350
|
}
|
351
351
|
|
352
|
+
const with_crud_asset_roles = new Set([
|
353
|
+
"content_writer",
|
354
|
+
"growth_manager",
|
355
|
+
"syllabus_coordinator",
|
356
|
+
"country_manager",
|
357
|
+
"community_manager",
|
358
|
+
"carrer_support_head",
|
359
|
+
])
|
360
|
+
|
352
361
|
export const listUserAcademies = async (
|
353
362
|
breathecodeToken: string
|
354
363
|
): Promise<TAcademy[]> => {
|
@@ -364,10 +373,14 @@ export const listUserAcademies = async (
|
|
364
373
|
const data = response.data
|
365
374
|
|
366
375
|
const academiesMap = new Map<number, TAcademy>()
|
376
|
+
|
367
377
|
for (const role of data.roles) {
|
368
|
-
|
369
|
-
if (
|
370
|
-
|
378
|
+
// Only add academies where the user's role is in the whitelist
|
379
|
+
if (with_crud_asset_roles.has(role.role)) {
|
380
|
+
const academy = role.academy
|
381
|
+
if (!academiesMap.has(academy.id)) {
|
382
|
+
academiesMap.set(academy.id, academy)
|
383
|
+
}
|
371
384
|
}
|
372
385
|
}
|
373
386
|
|
@@ -392,6 +405,107 @@ export const validateToken = async (token: string) => {
|
|
392
405
|
}
|
393
406
|
}
|
394
407
|
|
408
|
+
type TAssetMissing = {
|
409
|
+
slug: string
|
410
|
+
title: string
|
411
|
+
lang: string
|
412
|
+
url: string
|
413
|
+
description: string
|
414
|
+
learnpack_deploy_url: string
|
415
|
+
technologies: string[]
|
416
|
+
}
|
417
|
+
|
418
|
+
export const createAsset = async (
|
419
|
+
token: string,
|
420
|
+
academyId: number,
|
421
|
+
asset: TAssetMissing
|
422
|
+
) => {
|
423
|
+
const body = {
|
424
|
+
slug: asset.slug,
|
425
|
+
title: asset.title,
|
426
|
+
lang: asset.lang,
|
427
|
+
asset_type: "EXERCISE",
|
428
|
+
visibility: "PUBLIC",
|
429
|
+
status: "PUBLISHED",
|
430
|
+
url: "https://4geeksacademy.com",
|
431
|
+
readme_url: null,
|
432
|
+
difficulty: null,
|
433
|
+
duration: null,
|
434
|
+
graded: false,
|
435
|
+
gitpod: true,
|
436
|
+
category: 7,
|
437
|
+
preview: null,
|
438
|
+
description: asset.description,
|
439
|
+
external: true,
|
440
|
+
interactive: true,
|
441
|
+
solution_video_url: null,
|
442
|
+
intro_video_url: null,
|
443
|
+
translations: ["us"],
|
444
|
+
learnpack_deploy_url: asset.learnpack_deploy_url,
|
445
|
+
technologies: asset.technologies,
|
446
|
+
}
|
447
|
+
const url = `https://breathecode.herokuapp.com/v1/registry/academy/asset`
|
448
|
+
const headers = {
|
449
|
+
Authorization: `Token ${token}`,
|
450
|
+
Academy: academyId,
|
451
|
+
}
|
452
|
+
|
453
|
+
try {
|
454
|
+
const response = await axios.post(url, body, { headers })
|
455
|
+
return response.data
|
456
|
+
} catch (error: any) {
|
457
|
+
// console.error("Failed to create asset:", error)
|
458
|
+
throw error.response.data
|
459
|
+
}
|
460
|
+
}
|
461
|
+
|
462
|
+
export const doesAssetExists = async (
|
463
|
+
token: string,
|
464
|
+
assetSlug: string
|
465
|
+
): Promise<{ exists: boolean; academyId?: number }> => {
|
466
|
+
const url = `https://breathecode.herokuapp.com/v1/registry/asset/${assetSlug}`
|
467
|
+
const headers = {
|
468
|
+
Authorization: `Token ${token}`,
|
469
|
+
}
|
470
|
+
|
471
|
+
try {
|
472
|
+
const response = await axios.get(url, { headers })
|
473
|
+
if (response.status === 200) {
|
474
|
+
const data = response.data
|
475
|
+
const academy = data.academy.id
|
476
|
+
return { exists: true, academyId: academy }
|
477
|
+
}
|
478
|
+
|
479
|
+
return { exists: false }
|
480
|
+
|
481
|
+
} catch (error) {
|
482
|
+
console.error("Failed to get asset:", error)
|
483
|
+
return { exists: false }
|
484
|
+
}
|
485
|
+
}
|
486
|
+
|
487
|
+
const updateAsset = async (
|
488
|
+
token: string,
|
489
|
+
academyId: number,
|
490
|
+
assetSlug: string,
|
491
|
+
asset: Partial<TAssetMissing>
|
492
|
+
) => {
|
493
|
+
const url = `https://breathecode.herokuapp.com/v1/registry/academy/asset/${assetSlug}`
|
494
|
+
const headers = {
|
495
|
+
Authorization: `Token ${token}`,
|
496
|
+
Academy: academyId,
|
497
|
+
}
|
498
|
+
try {
|
499
|
+
const response = await axios.put(url, asset, { headers })
|
500
|
+
return response.data
|
501
|
+
} catch (error: any) {
|
502
|
+
// console.error("Failed to update asset:", error)
|
503
|
+
// Try to print the data
|
504
|
+
// console.log(error.response.data)
|
505
|
+
throw error.response.data
|
506
|
+
}
|
507
|
+
}
|
508
|
+
|
395
509
|
export default {
|
396
510
|
login,
|
397
511
|
publish,
|
@@ -403,4 +517,7 @@ export default {
|
|
403
517
|
sendStreamTelemetry,
|
404
518
|
listUserAcademies,
|
405
519
|
validateToken,
|
520
|
+
createAsset,
|
521
|
+
doesAssetExists,
|
522
|
+
updateAsset,
|
406
523
|
}
|