@learnpack/learnpack 4.0.13 → 4.0.15
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +10 -10
- package/lib/commands/publish.js +1 -1
- package/lib/managers/server/routes.js +54 -0
- package/lib/managers/session.js +14 -5
- package/lib/models/session.d.ts +2 -0
- package/lib/utils/api.js +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/commands/publish.ts +1 -1
- package/src/managers/server/routes.ts +64 -0
- package/src/managers/session.ts +20 -5
- package/src/models/session.ts +36 -34
- package/src/utils/api.ts +304 -303
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/4.0.
|
24
|
+
@learnpack/learnpack/4.0.15 win32-x64 node-v20.16.0
|
25
25
|
$ learnpack --help [COMMAND]
|
26
26
|
USAGE
|
27
27
|
$ learnpack COMMAND
|
@@ -74,7 +74,7 @@ DESCRIPTION
|
|
74
74
|
12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
|
75
75
|
```
|
76
76
|
|
77
|
-
_See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.
|
77
|
+
_See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.15/src\commands\audit.ts)_
|
78
78
|
|
79
79
|
## `learnpack clean`
|
80
80
|
|
@@ -89,7 +89,7 @@ DESCRIPTION
|
|
89
89
|
Extra documentation goes here
|
90
90
|
```
|
91
91
|
|
92
|
-
_See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.
|
92
|
+
_See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.15/src\commands\clean.ts)_
|
93
93
|
|
94
94
|
## `learnpack download [PACKAGE]`
|
95
95
|
|
@@ -107,7 +107,7 @@ DESCRIPTION
|
|
107
107
|
Extra documentation goes here
|
108
108
|
```
|
109
109
|
|
110
|
-
_See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.
|
110
|
+
_See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.15/src\commands\download.ts)_
|
111
111
|
|
112
112
|
## `learnpack help [COMMAND]`
|
113
113
|
|
@@ -138,7 +138,7 @@ OPTIONS
|
|
138
138
|
-h, --grading show CLI help
|
139
139
|
```
|
140
140
|
|
141
|
-
_See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.
|
141
|
+
_See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.15/src\commands\init.ts)_
|
142
142
|
|
143
143
|
## `learnpack login [PACKAGE]`
|
144
144
|
|
@@ -156,7 +156,7 @@ DESCRIPTION
|
|
156
156
|
Extra documentation goes here
|
157
157
|
```
|
158
158
|
|
159
|
-
_See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.
|
159
|
+
_See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.15/src\commands\login.ts)_
|
160
160
|
|
161
161
|
## `learnpack logout [PACKAGE]`
|
162
162
|
|
@@ -174,7 +174,7 @@ DESCRIPTION
|
|
174
174
|
Extra documentation goes here
|
175
175
|
```
|
176
176
|
|
177
|
-
_See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.
|
177
|
+
_See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.15/src\commands\logout.ts)_
|
178
178
|
|
179
179
|
## `learnpack plugins`
|
180
180
|
|
@@ -305,7 +305,7 @@ OPTIONS
|
|
305
305
|
-h, --help show CLI help
|
306
306
|
```
|
307
307
|
|
308
|
-
_See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.
|
308
|
+
_See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.15/src\commands\publish.ts)_
|
309
309
|
|
310
310
|
## `learnpack start`
|
311
311
|
|
@@ -326,7 +326,7 @@ OPTIONS
|
|
326
326
|
-w, --watch Watch for file changes
|
327
327
|
```
|
328
328
|
|
329
|
-
_See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.
|
329
|
+
_See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.15/src\commands\start.ts)_
|
330
330
|
|
331
331
|
## `learnpack test [EXERCISESLUG]`
|
332
332
|
|
@@ -340,7 +340,7 @@ ARGUMENTS
|
|
340
340
|
EXERCISESLUG The name of the exercise to test
|
341
341
|
```
|
342
342
|
|
343
|
-
_See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.
|
343
|
+
_See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v4.0.15/src\commands\test.ts)_
|
344
344
|
<!-- commandsstop -->
|
345
345
|
|
346
346
|
> > > > > > > 0cb3e56d84c197f9d008836bb573eade212b7e57
|
package/lib/commands/publish.js
CHANGED
@@ -11,8 +11,8 @@ const archiver = require("archiver");
|
|
11
11
|
const axios_1 = require("axios");
|
12
12
|
const FormData = require("form-data");
|
13
13
|
const console_1 = require("../utils/console");
|
14
|
-
// const RIGOBOT_HOST = "https://rigobot-test-cca7d841c9d8.herokuapp.com"
|
15
14
|
const RIGOBOT_HOST =
|
15
|
+
// "https://rigobot-test-cca7d841c9d8.herokuapp.com"
|
16
16
|
// "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
|
17
17
|
"https://rigobot.herokuapp.com";
|
18
18
|
const uploadZipEndpont = RIGOBOT_HOST + "/v1/learnpack/upload";
|
@@ -75,6 +75,60 @@ async function default_1(app, configObject, configManager) {
|
|
75
75
|
res.status(500).json({ error: "Internal server error" });
|
76
76
|
}
|
77
77
|
}));
|
78
|
+
app.post("/set-tab-hash", jsonBodyParser, withHandler(async (req, res) => {
|
79
|
+
const hash = req.body.hash;
|
80
|
+
if (!hash) {
|
81
|
+
return res.status(400).json({ error: "Token is required" });
|
82
|
+
}
|
83
|
+
try {
|
84
|
+
const hashSaved = await session_1.default.setTabHash(hash);
|
85
|
+
if (hashSaved) {
|
86
|
+
res.json({ status: "ok" });
|
87
|
+
}
|
88
|
+
else {
|
89
|
+
res.status(500).json({ error: "Failed to save the token" });
|
90
|
+
}
|
91
|
+
}
|
92
|
+
catch (_a) {
|
93
|
+
res.status(500).json({ error: "Internal server error" });
|
94
|
+
}
|
95
|
+
}));
|
96
|
+
app.post("/set-session-key", jsonBodyParser, withHandler(async (req, res) => {
|
97
|
+
const sessionKey = req.body.sessionKey;
|
98
|
+
if (!sessionKey) {
|
99
|
+
return res.status(400).json({ error: "Token is required" });
|
100
|
+
}
|
101
|
+
try {
|
102
|
+
const sessionSaved = await session_1.default.setSessionKey(sessionKey);
|
103
|
+
if (sessionSaved) {
|
104
|
+
res.json({ status: "ok" });
|
105
|
+
}
|
106
|
+
else {
|
107
|
+
res.status(500).json({ error: "Failed to save the token" });
|
108
|
+
}
|
109
|
+
}
|
110
|
+
catch (_a) {
|
111
|
+
res.status(500).json({ error: "Internal server error" });
|
112
|
+
}
|
113
|
+
}));
|
114
|
+
app.post("/set-session", jsonBodyParser, withHandler(async (req, res) => {
|
115
|
+
const payload = req.body.payload;
|
116
|
+
if (!payload) {
|
117
|
+
return res.status(400).json({ error: "Token is required" });
|
118
|
+
}
|
119
|
+
try {
|
120
|
+
const payloadSaved = await session_1.default.setPayload(payload);
|
121
|
+
if (payloadSaved) {
|
122
|
+
res.json({ status: "ok" });
|
123
|
+
}
|
124
|
+
else {
|
125
|
+
res.status(500).json({ error: "Failed to save the token" });
|
126
|
+
}
|
127
|
+
}
|
128
|
+
catch (_a) {
|
129
|
+
res.status(500).json({ error: "Internal server error" });
|
130
|
+
}
|
131
|
+
}));
|
78
132
|
app.get("/check/rigo/status", withHandler(async (_, res) => {
|
79
133
|
const payload = await session_1.default.getPayload();
|
80
134
|
if (payload && payload.rigobot && payload.rigobot.key) {
|
package/lib/managers/session.js
CHANGED
@@ -33,6 +33,20 @@ const Session = {
|
|
33
33
|
console_1.default.debug("Rigobot token successfuly set");
|
34
34
|
return true;
|
35
35
|
},
|
36
|
+
setTabHash: async function (hash) {
|
37
|
+
await this.initialize();
|
38
|
+
const payload = await storage.getItem("bc-payload");
|
39
|
+
await storage.setItem("bc-payload", Object.assign(Object.assign({}, payload), { tabHash: hash }));
|
40
|
+
console_1.default.debug("tabHash successfuly set");
|
41
|
+
return true;
|
42
|
+
},
|
43
|
+
setSessionKey: async function (value) {
|
44
|
+
await this.initialize();
|
45
|
+
const payload = await storage.getItem("bc-payload");
|
46
|
+
await storage.setItem("bc-payload", Object.assign(Object.assign({}, payload), { sessionKey: value }));
|
47
|
+
console_1.default.debug("sessionKey successfuly set");
|
48
|
+
return true;
|
49
|
+
},
|
36
50
|
setPayload: async function (value) {
|
37
51
|
await this.initialize();
|
38
52
|
await storage.setItem("bc-payload", Object.assign({ token: this.token }, value));
|
@@ -51,11 +65,6 @@ const Session = {
|
|
51
65
|
return payload;
|
52
66
|
},
|
53
67
|
isActive: function () {
|
54
|
-
/* if (this.token) {
|
55
|
-
return true
|
56
|
-
} else {
|
57
|
-
return false
|
58
|
-
} */
|
59
68
|
return !!this.token;
|
60
69
|
},
|
61
70
|
get: async function (configObj) {
|
package/lib/models/session.d.ts
CHANGED
@@ -18,6 +18,8 @@ export interface ISession {
|
|
18
18
|
currentCohort: null;
|
19
19
|
initialize: () => Promise<boolean>;
|
20
20
|
setRigoToken: (token: string) => Promise<boolean>;
|
21
|
+
setTabHash: (hash: string) => Promise<boolean>;
|
22
|
+
setSessionKey: (value: string) => Promise<boolean>;
|
21
23
|
setPayload: (value: IPayload) => Promise<boolean>;
|
22
24
|
getPayload: () => Promise<any>;
|
23
25
|
isActive: () => boolean;
|
package/lib/utils/api.js
CHANGED
@@ -5,6 +5,7 @@ const storage = require("node-persist");
|
|
5
5
|
const cli_ux_1 = require("cli-ux");
|
6
6
|
const HOST = "https://breathecode.herokuapp.com";
|
7
7
|
const RIGOBOT_HOST = "https://rigobot.herokuapp.com";
|
8
|
+
// const RIGOBOT_HOST = "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
|
8
9
|
// eslint-disable-next-line
|
9
10
|
const _fetch = require("node-fetch");
|
10
11
|
const fetch = async (url, options = {}, returnAsJson = true) => {
|
package/oclif.manifest.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":"4.0.
|
1
|
+
{"version":"4.0.15","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":{},"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":{"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":{"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":{"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":{},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]}}}
|
package/package.json
CHANGED
package/src/commands/publish.ts
CHANGED
@@ -10,8 +10,8 @@ import axios from "axios"
|
|
10
10
|
import FormData = require("form-data")
|
11
11
|
import Console from "../utils/console"
|
12
12
|
|
13
|
-
// const RIGOBOT_HOST = "https://rigobot-test-cca7d841c9d8.herokuapp.com"
|
14
13
|
const RIGOBOT_HOST =
|
14
|
+
// "https://rigobot-test-cca7d841c9d8.herokuapp.com"
|
15
15
|
// "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
|
16
16
|
"https://rigobot.herokuapp.com"
|
17
17
|
const uploadZipEndpont = RIGOBOT_HOST + "/v1/learnpack/upload"
|
@@ -105,6 +105,70 @@ export default async function (
|
|
105
105
|
}
|
106
106
|
})
|
107
107
|
)
|
108
|
+
app.post(
|
109
|
+
"/set-tab-hash",
|
110
|
+
jsonBodyParser,
|
111
|
+
withHandler(async (req: express.Request, res: express.Response) => {
|
112
|
+
const hash = req.body.hash
|
113
|
+
if (!hash) {
|
114
|
+
return res.status(400).json({ error: "Token is required" })
|
115
|
+
}
|
116
|
+
|
117
|
+
try {
|
118
|
+
const hashSaved = await SessionManager.setTabHash(hash)
|
119
|
+
if (hashSaved) {
|
120
|
+
res.json({ status: "ok" })
|
121
|
+
} else {
|
122
|
+
res.status(500).json({ error: "Failed to save the token" })
|
123
|
+
}
|
124
|
+
} catch {
|
125
|
+
res.status(500).json({ error: "Internal server error" })
|
126
|
+
}
|
127
|
+
})
|
128
|
+
)
|
129
|
+
app.post(
|
130
|
+
"/set-session-key",
|
131
|
+
jsonBodyParser,
|
132
|
+
withHandler(async (req: express.Request, res: express.Response) => {
|
133
|
+
const sessionKey = req.body.sessionKey
|
134
|
+
if (!sessionKey) {
|
135
|
+
return res.status(400).json({ error: "Token is required" })
|
136
|
+
}
|
137
|
+
|
138
|
+
try {
|
139
|
+
const sessionSaved = await SessionManager.setSessionKey(sessionKey)
|
140
|
+
if (sessionSaved) {
|
141
|
+
res.json({ status: "ok" })
|
142
|
+
} else {
|
143
|
+
res.status(500).json({ error: "Failed to save the token" })
|
144
|
+
}
|
145
|
+
} catch {
|
146
|
+
res.status(500).json({ error: "Internal server error" })
|
147
|
+
}
|
148
|
+
})
|
149
|
+
)
|
150
|
+
app.post(
|
151
|
+
"/set-session",
|
152
|
+
jsonBodyParser,
|
153
|
+
withHandler(async (req: express.Request, res: express.Response) => {
|
154
|
+
const payload = req.body.payload
|
155
|
+
if (!payload) {
|
156
|
+
return res.status(400).json({ error: "Token is required" })
|
157
|
+
}
|
158
|
+
|
159
|
+
try {
|
160
|
+
const payloadSaved = await SessionManager.setPayload(payload)
|
161
|
+
if (payloadSaved) {
|
162
|
+
res.json({ status: "ok" })
|
163
|
+
} else {
|
164
|
+
res.status(500).json({ error: "Failed to save the token" })
|
165
|
+
}
|
166
|
+
} catch {
|
167
|
+
res.status(500).json({ error: "Internal server error" })
|
168
|
+
}
|
169
|
+
})
|
170
|
+
)
|
171
|
+
|
108
172
|
app.get(
|
109
173
|
"/check/rigo/status",
|
110
174
|
withHandler(async (_: express.Request, res: express.Response) => {
|
package/src/managers/session.ts
CHANGED
@@ -44,6 +44,26 @@ const Session: ISession = {
|
|
44
44
|
Console.debug("Rigobot token successfuly set")
|
45
45
|
return true
|
46
46
|
},
|
47
|
+
setTabHash: async function (hash: string) {
|
48
|
+
await this.initialize()
|
49
|
+
const payload = await storage.getItem("bc-payload")
|
50
|
+
await storage.setItem("bc-payload", {
|
51
|
+
...payload,
|
52
|
+
tabHash: hash,
|
53
|
+
})
|
54
|
+
Console.debug("tabHash successfuly set")
|
55
|
+
return true
|
56
|
+
},
|
57
|
+
setSessionKey: async function (value: string) {
|
58
|
+
await this.initialize()
|
59
|
+
const payload = await storage.getItem("bc-payload")
|
60
|
+
await storage.setItem("bc-payload", {
|
61
|
+
...payload,
|
62
|
+
sessionKey: value,
|
63
|
+
})
|
64
|
+
Console.debug("sessionKey successfuly set")
|
65
|
+
return true
|
66
|
+
},
|
47
67
|
setPayload: async function (value: IPayload) {
|
48
68
|
await this.initialize()
|
49
69
|
await storage.setItem("bc-payload", { token: this.token, ...value })
|
@@ -62,11 +82,6 @@ const Session: ISession = {
|
|
62
82
|
return payload
|
63
83
|
},
|
64
84
|
isActive: function () {
|
65
|
-
/* if (this.token) {
|
66
|
-
return true
|
67
|
-
} else {
|
68
|
-
return false
|
69
|
-
} */
|
70
85
|
return !!this.token
|
71
86
|
},
|
72
87
|
get: async function (configObj?: IConfigObj) {
|
package/src/models/session.ts
CHANGED
@@ -1,34 +1,36 @@
|
|
1
|
-
import { IConfig, IConfigObj } from "./config"
|
2
|
-
|
3
|
-
export interface IPayload {
|
4
|
-
email: string
|
5
|
-
}
|
6
|
-
|
7
|
-
export interface IStartProps {
|
8
|
-
token: string
|
9
|
-
payload: IPayload | null
|
10
|
-
}
|
11
|
-
|
12
|
-
type TLoginResponse = {
|
13
|
-
token: string
|
14
|
-
user_id: string
|
15
|
-
email: string
|
16
|
-
}
|
17
|
-
|
18
|
-
export interface ISession {
|
19
|
-
sessionStarted: boolean
|
20
|
-
token: string | null
|
21
|
-
config: IConfig | null
|
22
|
-
currentCohort: null
|
23
|
-
initialize: () => Promise<boolean
|
24
|
-
setRigoToken: (token: string) => Promise<boolean
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
}
|
1
|
+
import { IConfig, IConfigObj } from "./config"
|
2
|
+
|
3
|
+
export interface IPayload {
|
4
|
+
email: string
|
5
|
+
}
|
6
|
+
|
7
|
+
export interface IStartProps {
|
8
|
+
token: string
|
9
|
+
payload: IPayload | null
|
10
|
+
}
|
11
|
+
|
12
|
+
type TLoginResponse = {
|
13
|
+
token: string
|
14
|
+
user_id: string
|
15
|
+
email: string
|
16
|
+
}
|
17
|
+
|
18
|
+
export interface ISession {
|
19
|
+
sessionStarted: boolean
|
20
|
+
token: string | null
|
21
|
+
config: IConfig | null
|
22
|
+
currentCohort: null
|
23
|
+
initialize: () => Promise<boolean>
|
24
|
+
setRigoToken: (token: string) => Promise<boolean>
|
25
|
+
setTabHash: (hash: string) => Promise<boolean>
|
26
|
+
setSessionKey: (value: string) => Promise<boolean>
|
27
|
+
setPayload: (value: IPayload) => Promise<boolean>
|
28
|
+
getPayload: () => Promise<any>
|
29
|
+
isActive: () => boolean
|
30
|
+
get: (config?: IConfigObj) => Promise<any>
|
31
|
+
login: () => Promise<void>
|
32
|
+
loginWeb: (email: string, password: string) => Promise<TLoginResponse>
|
33
|
+
sync: () => Promise<void>
|
34
|
+
start: ({ token, payload }: IStartProps) => Promise<void>
|
35
|
+
destroy: () => Promise<void>
|
36
|
+
}
|
package/src/utils/api.ts
CHANGED
@@ -1,303 +1,304 @@
|
|
1
|
-
import Console from "../utils/console"
|
2
|
-
import * as storage from "node-persist"
|
3
|
-
import cli from "cli-ux"
|
4
|
-
const HOST = "https://breathecode.herokuapp.com"
|
5
|
-
const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
}
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
Console.
|
100
|
-
|
101
|
-
}
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
const
|
107
|
-
const
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
}
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
"
|
123
|
-
"
|
124
|
-
"
|
125
|
-
"
|
126
|
-
"
|
127
|
-
"
|
128
|
-
"
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
Console.
|
147
|
-
|
148
|
-
|
149
|
-
}
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
Console.
|
164
|
-
|
165
|
-
|
166
|
-
}
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
}
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
}
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
Console.
|
220
|
-
|
221
|
-
|
222
|
-
}
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
const
|
227
|
-
_err
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
!
|
240
|
-
session
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
}
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
!
|
272
|
-
session
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
}
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
1
|
+
import Console from "../utils/console"
|
2
|
+
import * as storage from "node-persist"
|
3
|
+
import cli from "cli-ux"
|
4
|
+
const HOST = "https://breathecode.herokuapp.com"
|
5
|
+
const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
|
6
|
+
// const RIGOBOT_HOST = "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
|
7
|
+
|
8
|
+
// eslint-disable-next-line
|
9
|
+
const _fetch = require("node-fetch")
|
10
|
+
|
11
|
+
interface IHeaders {
|
12
|
+
"Content-Type"?: string
|
13
|
+
Authorization?: string
|
14
|
+
}
|
15
|
+
|
16
|
+
interface IOptions {
|
17
|
+
headers?: IHeaders
|
18
|
+
method?: string
|
19
|
+
body?: string
|
20
|
+
}
|
21
|
+
|
22
|
+
const fetch = async (
|
23
|
+
url: string,
|
24
|
+
options: IOptions = {},
|
25
|
+
returnAsJson = true
|
26
|
+
) => {
|
27
|
+
const headers: IHeaders = { "Content-Type": "application/json" }
|
28
|
+
Console.debug(`Fetching ${url}`)
|
29
|
+
let session = null
|
30
|
+
try {
|
31
|
+
session = await storage.getItem("bc-payload")
|
32
|
+
if (session.token && session.token !== "" && !url.includes("/token"))
|
33
|
+
headers.Authorization = "Token " + session.token
|
34
|
+
} catch {}
|
35
|
+
|
36
|
+
try {
|
37
|
+
const resp = await _fetch(url, {
|
38
|
+
...options,
|
39
|
+
headers: { ...headers, ...options.headers },
|
40
|
+
} as any)
|
41
|
+
|
42
|
+
if (resp.status >= 200 && resp.status < 300) {
|
43
|
+
return returnAsJson ? await resp.json() : await resp.text()
|
44
|
+
}
|
45
|
+
|
46
|
+
if (resp.status === 401)
|
47
|
+
Console.debug("Invalid authentication credentials", `Code: 401`)
|
48
|
+
// throw APIError("Invalid authentication credentials", 401)
|
49
|
+
else if (resp.status === 404)
|
50
|
+
throw APIError("Package not found", 404)
|
51
|
+
else if (resp.status >= 500)
|
52
|
+
throw APIError("Impossible to connect with the server", 500)
|
53
|
+
else if (resp.status >= 400) {
|
54
|
+
const error = await resp.json()
|
55
|
+
if (error.detail || error.error) {
|
56
|
+
throw APIError(error.detail || error.error)
|
57
|
+
} else if (error.nonFieldErrors) {
|
58
|
+
throw APIError(error.nonFieldErrors[0], error)
|
59
|
+
} else if (typeof error === "object") {
|
60
|
+
if (Object.keys(error).length > 0) {
|
61
|
+
const key = error[Object.keys(error)[0]]
|
62
|
+
throw APIError(`${key}: ${error[key][0]}`, error)
|
63
|
+
}
|
64
|
+
} else {
|
65
|
+
throw APIError("Uknown error")
|
66
|
+
}
|
67
|
+
} else
|
68
|
+
throw APIError("Uknown error")
|
69
|
+
} catch (error) {
|
70
|
+
Console.error((error as TypeError).message)
|
71
|
+
throw error
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
const login = async (identification: string, password: string) => {
|
76
|
+
try {
|
77
|
+
cli.action.start(`Looking for credentials with ${identification}`)
|
78
|
+
await cli.wait(1000)
|
79
|
+
const url = `${HOST}/v1/auth/login/`
|
80
|
+
|
81
|
+
const data = await fetch(url, {
|
82
|
+
body: JSON.stringify({
|
83
|
+
email: identification,
|
84
|
+
password: password,
|
85
|
+
}),
|
86
|
+
method: "post",
|
87
|
+
})
|
88
|
+
cli.action.stop("ready")
|
89
|
+
let rigoPayload = null
|
90
|
+
try {
|
91
|
+
rigoPayload = await loginRigo(data.token)
|
92
|
+
} catch {
|
93
|
+
return { ...data, rigobot: null }
|
94
|
+
}
|
95
|
+
|
96
|
+
return { ...data, rigobot: rigoPayload }
|
97
|
+
} catch (error) {
|
98
|
+
cli.action.stop("error")
|
99
|
+
Console.error((error as TypeError).message)
|
100
|
+
Console.debug(error)
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
const loginRigo = async (token: string) => {
|
105
|
+
try {
|
106
|
+
const rigoUrl = `${RIGOBOT_HOST}/v1/auth/me/token?breathecode_token=${token}`
|
107
|
+
const rigoResp = await _fetch(rigoUrl)
|
108
|
+
const rigobotJson = await rigoResp.json()
|
109
|
+
return rigobotJson
|
110
|
+
} catch (error) {
|
111
|
+
// Handle the error as needed, for example log it or return a custom error message
|
112
|
+
Console.error(
|
113
|
+
"Error logging in to Rigo, did you already accepted Rigobot?:",
|
114
|
+
error
|
115
|
+
)
|
116
|
+
throw new Error("Failed to log in to Rigo")
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
const publish = async (config: any) => {
|
121
|
+
const keys = [
|
122
|
+
"difficulty",
|
123
|
+
"language",
|
124
|
+
"skills",
|
125
|
+
"technologies",
|
126
|
+
"slug",
|
127
|
+
"repository",
|
128
|
+
"author",
|
129
|
+
"title",
|
130
|
+
]
|
131
|
+
|
132
|
+
const payload: { [key: string]: string } = {}
|
133
|
+
for (const k of keys)
|
134
|
+
config[k] ? (payload[k] = config[k]) : null
|
135
|
+
try {
|
136
|
+
console.log("Package to publish:", payload)
|
137
|
+
cli.action.start("Updating package information...")
|
138
|
+
await cli.wait(1000)
|
139
|
+
const data = await fetch(`${HOST}/v1/package/${config.slug}`, {
|
140
|
+
method: "PUT",
|
141
|
+
body: JSON.stringify(payload),
|
142
|
+
})
|
143
|
+
cli.action.stop("ready")
|
144
|
+
return data
|
145
|
+
} catch (error) {
|
146
|
+
Console.error((error as TypeError).message)
|
147
|
+
Console.debug(error)
|
148
|
+
throw error
|
149
|
+
}
|
150
|
+
}
|
151
|
+
|
152
|
+
const update = async (config: any) => {
|
153
|
+
try {
|
154
|
+
cli.action.start("Updating package information...")
|
155
|
+
await cli.wait(1000)
|
156
|
+
const data = await fetch(`${HOST}/v1/package/`, {
|
157
|
+
method: "POST",
|
158
|
+
body: JSON.stringify(config),
|
159
|
+
})
|
160
|
+
cli.action.stop("ready")
|
161
|
+
return data
|
162
|
+
} catch (error) {
|
163
|
+
Console.error((error as any).message)
|
164
|
+
Console.debug(error)
|
165
|
+
throw error
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
const getPackage = async (slug: string) => {
|
170
|
+
try {
|
171
|
+
cli.action.start("Downloading package information...")
|
172
|
+
await cli.wait(1000)
|
173
|
+
const data = await fetch(`${HOST}/v1/package/${slug}`)
|
174
|
+
cli.action.stop("ready")
|
175
|
+
return data
|
176
|
+
} catch (error) {
|
177
|
+
if ((error as any).status === 404)
|
178
|
+
Console.error(`Package ${slug} does not exist`)
|
179
|
+
else
|
180
|
+
Console.error(`Package ${slug} does not exist`)
|
181
|
+
Console.debug(error)
|
182
|
+
throw error
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
const getLangs = async () => {
|
187
|
+
try {
|
188
|
+
cli.action.start("Downloading language options...")
|
189
|
+
await cli.wait(1000)
|
190
|
+
const data = await fetch(`${HOST}/v1/package/language`)
|
191
|
+
cli.action.stop("ready")
|
192
|
+
return data
|
193
|
+
} catch (error) {
|
194
|
+
if ((error as any).status === 404)
|
195
|
+
Console.error("Package slug does not exist")
|
196
|
+
else
|
197
|
+
Console.error("Package slug does not exist")
|
198
|
+
Console.debug(error)
|
199
|
+
throw error
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
const getAllPackages = async ({
|
204
|
+
lang = "",
|
205
|
+
slug = "",
|
206
|
+
}: {
|
207
|
+
lang?: string
|
208
|
+
slug?: string
|
209
|
+
}) => {
|
210
|
+
try {
|
211
|
+
cli.action.start("Downloading packages...")
|
212
|
+
await cli.wait(1000)
|
213
|
+
const data = await fetch(
|
214
|
+
`${HOST}/v1/package/all?limit=100&language=${lang}&slug=${slug}`
|
215
|
+
)
|
216
|
+
cli.action.stop("ready")
|
217
|
+
return data
|
218
|
+
} catch (error) {
|
219
|
+
Console.error(`Package ${slug} does not exist`)
|
220
|
+
Console.debug(error)
|
221
|
+
throw error
|
222
|
+
}
|
223
|
+
}
|
224
|
+
|
225
|
+
const APIError = (error: TypeError | string, code?: number) => {
|
226
|
+
const message: string = (error as TypeError).message || (error as string)
|
227
|
+
const _err = new Error(message) as any
|
228
|
+
_err.status = code || 400
|
229
|
+
return _err
|
230
|
+
}
|
231
|
+
|
232
|
+
const sendBatchTelemetry = async function (url: string, body: object) {
|
233
|
+
if (!url) {
|
234
|
+
return
|
235
|
+
}
|
236
|
+
|
237
|
+
const session = await storage.getItem("bc-payload")
|
238
|
+
if (
|
239
|
+
!session ||
|
240
|
+
!Object.prototype.hasOwnProperty.call(session, "token") ||
|
241
|
+
session.token === ""
|
242
|
+
) {
|
243
|
+
Console.debug("No token found, skipping stream telemetry delivery")
|
244
|
+
return
|
245
|
+
}
|
246
|
+
|
247
|
+
fetch(
|
248
|
+
url,
|
249
|
+
{
|
250
|
+
method: "POST",
|
251
|
+
body: JSON.stringify(body),
|
252
|
+
},
|
253
|
+
false
|
254
|
+
)
|
255
|
+
.then(response => {
|
256
|
+
Console.debug("Telemetry sent successfully")
|
257
|
+
return response.text()
|
258
|
+
})
|
259
|
+
.catch(error => {
|
260
|
+
Console.debug("Error while sending batch Telemetry", error)
|
261
|
+
})
|
262
|
+
}
|
263
|
+
|
264
|
+
const sendStreamTelemetry = async function (url: string, body: object) {
|
265
|
+
if (!url) {
|
266
|
+
return
|
267
|
+
}
|
268
|
+
|
269
|
+
const session = await storage.getItem("bc-payload")
|
270
|
+
if (
|
271
|
+
!session ||
|
272
|
+
!Object.prototype.hasOwnProperty.call(session, "token") ||
|
273
|
+
session.token === ""
|
274
|
+
) {
|
275
|
+
Console.debug("No token found, skipping stream telemetry delivery")
|
276
|
+
return
|
277
|
+
}
|
278
|
+
|
279
|
+
fetch(
|
280
|
+
url,
|
281
|
+
{
|
282
|
+
method: "POST",
|
283
|
+
body: JSON.stringify(body),
|
284
|
+
},
|
285
|
+
false
|
286
|
+
)
|
287
|
+
.then(response => {
|
288
|
+
return response
|
289
|
+
})
|
290
|
+
.catch(error => {
|
291
|
+
Console.debug("Error while sending stream Telemetry", error)
|
292
|
+
})
|
293
|
+
}
|
294
|
+
|
295
|
+
export default {
|
296
|
+
login,
|
297
|
+
publish,
|
298
|
+
update,
|
299
|
+
getPackage,
|
300
|
+
getLangs,
|
301
|
+
getAllPackages,
|
302
|
+
sendBatchTelemetry,
|
303
|
+
sendStreamTelemetry,
|
304
|
+
}
|