@insignia-education/api-sdk-js 0.15.62 → 0.15.63
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/coverage/clover.xml +132 -1524
- package/coverage/coverage-final.json +1 -45
- package/coverage/lcov-report/Client.js.html +1 -1
- package/coverage/lcov-report/index.html +20 -65
- package/coverage/lcov.info +138 -2554
- package/coverage/test-report.html +1 -586
- package/package.json +1 -1
- package/src/api/v1/Courses.js +2 -0
- package/src/api/v1/Telegram.js +6 -0
- package/src/api/v1/Users.js +12 -0
- package/tests/integration/api/v1/telegram.test.js +33 -0
- package/tests/integration/api/v1/users/telegram.test.js +36 -0
package/package.json
CHANGED
package/src/api/v1/Courses.js
CHANGED
|
@@ -45,6 +45,8 @@ export default class Courses {
|
|
|
45
45
|
syncTelegramToUsers: (id) => this.#client.post(`${base}/${id}/sync-user-courses`),
|
|
46
46
|
/** Reconciles this date's sessions with its current teacher/config set: creates missing ones, reassigns the teacher on existing ones, deletes untouched ones that no longer match the schedule. Safe to re-run any time the config, date range or teacher changes. */
|
|
47
47
|
syncSessions: (id) => this.#client.post(`${base}/${id}/sync-sessions`),
|
|
48
|
+
/** Reconciles per-student attendance rows for this date's generated sessions against who's currently enrolled (UserCourse). Safe to re-run any time the roster changes. */
|
|
49
|
+
syncAttendances: (id) => this.#client.post(`${base}/${id}/sync-attendances`),
|
|
48
50
|
/** Sessions already generated for this date. */
|
|
49
51
|
sessions: (id) => this.#client.get(`${base}/${id}/sessions`),
|
|
50
52
|
/** Create a Zoom meeting for one of this date's generated sessions. */
|
package/src/api/v1/Telegram.js
CHANGED
|
@@ -10,4 +10,10 @@ export default class Telegram {
|
|
|
10
10
|
|
|
11
11
|
/** Admin-only: starts (or continues) a QR-code login. */
|
|
12
12
|
qrLogin() { return this.#client.post('/telegram/qr-login'); }
|
|
13
|
+
|
|
14
|
+
/** Admin-only: current webhook registration for the main bot (account linking + notifications). */
|
|
15
|
+
webhookStatus() { return this.#client.get('/telegram/webhook'); }
|
|
16
|
+
|
|
17
|
+
/** Admin-only: (re)registers this API's /webhooks/telegram endpoint with Telegram. Idempotent. */
|
|
18
|
+
setWebhook() { return this.#client.post('/telegram/webhook'); }
|
|
13
19
|
}
|
package/src/api/v1/Users.js
CHANGED
|
@@ -202,4 +202,16 @@ export default class Users {
|
|
|
202
202
|
reject: () => client.post(`${base}/reject`),
|
|
203
203
|
};
|
|
204
204
|
}
|
|
205
|
+
|
|
206
|
+
/** Verified Telegram account linking for this user. Owner or staff only. */
|
|
207
|
+
telegram(userId) {
|
|
208
|
+
const base = `/users/${userId}/telegram`;
|
|
209
|
+
const client = this.#client;
|
|
210
|
+
return {
|
|
211
|
+
/** Mints a { hash, link, expires_at } deep link — tapping it in Telegram links this user's chat_id via the bot webhook. */
|
|
212
|
+
linkToken: () => client.post(`${base}/link-token`),
|
|
213
|
+
/** Fallback flow: completes a link the bot proposed after an organic (no-payload) /start, given the { chat_id, username, expires_at, signature } it replied with. */
|
|
214
|
+
connect: (data) => client.post(`${base}/connect`, data),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
205
217
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
api,
|
|
3
|
+
loginAdmin,
|
|
4
|
+
loginCustomer,
|
|
5
|
+
} from '../../../helpers.js';
|
|
6
|
+
|
|
7
|
+
describe('api/v1/telegram', () => {
|
|
8
|
+
test('webhookStatus | requires authentication', async () => {
|
|
9
|
+
await expect(api.telegram.webhookStatus()).rejects.toMatchObject({ status: 401 });
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('webhookStatus | forbidden below admin', async () => {
|
|
13
|
+
await loginCustomer();
|
|
14
|
+
await expect(api.telegram.webhookStatus()).rejects.toMatchObject({ status: 403 });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('webhookStatus | reachable by admin', async () => {
|
|
18
|
+
await loginAdmin();
|
|
19
|
+
await api.telegram.webhookStatus()
|
|
20
|
+
.then(response => {
|
|
21
|
+
expect(typeof response).toBe('object');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('setWebhook | requires authentication', async () => {
|
|
26
|
+
await expect(api.telegram.setWebhook()).rejects.toMatchObject({ status: 401 });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('setWebhook | forbidden below admin', async () => {
|
|
30
|
+
await loginCustomer();
|
|
31
|
+
await expect(api.telegram.setWebhook()).rejects.toMatchObject({ status: 403 });
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
api,
|
|
3
|
+
loginCustomer,
|
|
4
|
+
} from '../../../../helpers.js';
|
|
5
|
+
|
|
6
|
+
describe('api/v1/users/{id}/telegram', () => {
|
|
7
|
+
test('linkToken | authenticated owner returns a deep link', async () => {
|
|
8
|
+
await loginCustomer();
|
|
9
|
+
const me = await api.users.get();
|
|
10
|
+
await api.users.telegram(me["id"]).linkToken()
|
|
11
|
+
.then(response => {
|
|
12
|
+
expect(response["hash"]).toBeDefined();
|
|
13
|
+
expect(response["link"]).toContain(response["hash"]);
|
|
14
|
+
expect(response["link"]).toMatch(/^https:\/\/t\.me\//);
|
|
15
|
+
expect(response["expires_at"]).toBeDefined();
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('connect | rejects an invalid signature', async () => {
|
|
20
|
+
await loginCustomer();
|
|
21
|
+
const me = await api.users.get();
|
|
22
|
+
await expect(api.users.telegram(me["id"]).connect({
|
|
23
|
+
chat_id: '12345',
|
|
24
|
+
username: 'someuser',
|
|
25
|
+
expires_at: Math.floor(Date.now() / 1000) + 600,
|
|
26
|
+
signature: 'not-a-real-signature',
|
|
27
|
+
})).rejects.toMatchObject({ status: 422 });
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('connect | missing params returns a validation error', async () => {
|
|
31
|
+
await loginCustomer();
|
|
32
|
+
const me = await api.users.get();
|
|
33
|
+
await expect(api.users.telegram(me["id"]).connect({}))
|
|
34
|
+
.rejects.toMatchObject({ status: 422 });
|
|
35
|
+
});
|
|
36
|
+
});
|