Skip to content

Commit c31285b

Browse files
authored
Merge pull request #71 from NeoZ666/npm-package
Fixed the submodule
2 parents 98884c8 + 48e07b7 commit c31285b

File tree

17 files changed

+4589
-1
lines changed

17 files changed

+4589
-1
lines changed

ltsdk

Lines changed: 0 additions & 1 deletion
This file was deleted.

npm_package ltsdk/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
./node_modules
2+
node_modules/
3+
./package-lock.json/
4+
package-lock.json/

npm_package ltsdk/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# [ltsdk](https://www.npmjs.com/package/ltsdk)
2+
3+
This package provides functions to interact with the Zoom API, fetch participant and poll data, process this data, and return the processed results.
4+
5+
## Installation
6+
7+
To install the package, use the following command:
8+
9+
```sh
10+
npm install ltsdk
11+
```
12+
13+
## Usage
14+
Here is an example of how to use the run function from the ltsdk package:
15+
16+
```typescript
17+
import { run } from 'ltsdk';
18+
import * as fs from 'fs';
19+
import * as path from 'path';
20+
21+
(async () => {
22+
const accountId = "YOUR_ACCOUNT_ID";
23+
const clientId = "YOUR_CLIENT_ID";
24+
const clientSecret = "YOUR_CLIENT_SECRET";
25+
const meetingId = "YOUR_MEETING_ID";
26+
try {
27+
const processedData = await run(accountId, clientId, clientSecret, meetingId);
28+
console.log(processedData);
29+
} catch (error) {
30+
console.error('Error:', error);
31+
}
32+
})();
33+
```
34+
35+
Run the script:
36+
37+
```bash
38+
tsc .\index.ts
39+
node .\index.js
40+
```
41+
42+
## Parameters
43+
accountId (string): The Zoom account ID.
44+
clientId (string): The Zoom client ID.
45+
clientSecret (string): The Zoom client secret.
46+
meetingId (string): The ID of the Zoom meeting.
47+
48+
## Returns
49+
A promise that resolves to the processed data.
50+
51+
## License
52+
Linux Foundation
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { run } from './zoomprocessor';
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"use strict";
2+
// index.ts
3+
Object.defineProperty(exports, "__esModule", { value: true });
4+
exports.run = void 0;
5+
var zoomprocessor_1 = require("./zoomprocessor");
6+
Object.defineProperty(exports, "run", { enumerable: true, get: function () { return zoomprocessor_1.run; } });
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export declare function run(accountId: string, clientId: string, clientSecret: string, meetingId: string): Promise<any>;
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
"use strict";
2+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4+
return new (P || (P = Promise))(function (resolve, reject) {
5+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8+
step((generator = generator.apply(thisArg, _arguments || [])).next());
9+
});
10+
};
11+
var __importDefault = (this && this.__importDefault) || function (mod) {
12+
return (mod && mod.__esModule) ? mod : { "default": mod };
13+
};
14+
Object.defineProperty(exports, "__esModule", { value: true });
15+
exports.run = run;
16+
const axios_1 = __importDefault(require("axios"));
17+
function getZoomAccessToken(accountId, clientId, clientSecret) {
18+
return __awaiter(this, void 0, void 0, function* () {
19+
const tokenUrl = `https://zoom.us/oauth/token?grant_type=account_credentials&account_id=${accountId}`;
20+
const authHeader = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
21+
try {
22+
const response = yield axios_1.default.post(tokenUrl, null, {
23+
headers: {
24+
Authorization: `Basic ${authHeader}`,
25+
'Content-Type': 'application/x-www-form-urlencoded',
26+
},
27+
});
28+
const bearerToken = response.data.access_token;
29+
return bearerToken;
30+
}
31+
catch (error) {
32+
console.error('Error obtaining Zoom access token:', error);
33+
throw new Error('Failed to obtain Zoom access token');
34+
}
35+
});
36+
}
37+
function getPastMeetingParticipants(baseUrl, meetingId, bearerToken) {
38+
return __awaiter(this, void 0, void 0, function* () {
39+
var _a, _b;
40+
try {
41+
const url = `${baseUrl}/past_meetings/${meetingId}/participants`;
42+
const response = yield axios_1.default.get(url, {
43+
headers: {
44+
Authorization: `Bearer ${bearerToken}`,
45+
'Content-Type': 'application/json',
46+
},
47+
});
48+
return {
49+
data: response.data,
50+
status: response.status,
51+
statusText: response.statusText,
52+
};
53+
}
54+
catch (error) {
55+
if (axios_1.default.isAxiosError(error)) {
56+
throw new Error(((_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) || error.message);
57+
}
58+
else {
59+
throw new Error('An unknown error occurred');
60+
}
61+
}
62+
});
63+
}
64+
function getMeetingPollsQuestions(baseUrl, meetingId, bearerToken) {
65+
return __awaiter(this, void 0, void 0, function* () {
66+
var _a, _b;
67+
try {
68+
const url = `${baseUrl}/meetings/${meetingId}/polls`;
69+
const response = yield axios_1.default.get(url, {
70+
headers: {
71+
Authorization: `Bearer ${bearerToken}`,
72+
'Content-Type': 'application/json',
73+
},
74+
});
75+
return {
76+
data: response.data,
77+
status: response.status,
78+
statusText: response.statusText,
79+
};
80+
}
81+
catch (error) {
82+
throw new Error(((_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) || error.message);
83+
}
84+
});
85+
}
86+
function getPastMeetingPolls(baseUrl, meetingId, bearerToken) {
87+
return __awaiter(this, void 0, void 0, function* () {
88+
var _a, _b;
89+
try {
90+
const url = `${baseUrl}/past_meetings/${meetingId}/polls`;
91+
const response = yield axios_1.default.get(url, {
92+
headers: {
93+
Authorization: `Bearer ${bearerToken}`,
94+
},
95+
});
96+
return {
97+
data: response.data,
98+
status: response.status,
99+
statusText: response.statusText,
100+
};
101+
}
102+
catch (error) {
103+
throw new Error(((_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) || error.message);
104+
}
105+
});
106+
}
107+
function processParticipantsAndPollsData(participants, pollScores) {
108+
const participantMap = new Map();
109+
participants.forEach(participant => {
110+
const name = participant.name;
111+
const joinTime = new Date(participant.join_time).getTime();
112+
const leaveTime = new Date(participant.leave_time).getTime();
113+
const duration = (leaveTime - joinTime) / 1000;
114+
const mappingData = { Email: participant.user_email || 'NaN', LTId: 'NaN' };
115+
if (participantMap.has(name)) {
116+
participantMap.get(name).totalTime += duration;
117+
}
118+
else {
119+
participantMap.set(name, {
120+
totalTime: duration,
121+
joinTime: joinTime,
122+
leaveTime: leaveTime,
123+
email: mappingData.Email,
124+
LTId: mappingData.LTId,
125+
total_score: 0,
126+
attempted: 0,
127+
total_questions: 0,
128+
});
129+
}
130+
});
131+
pollScores.forEach((data, name) => {
132+
const participantData = participantMap.get(name);
133+
if (participantData) {
134+
participantData.total_score = data.total_score;
135+
participantData.attempted = data.attempted;
136+
participantData.total_questions = data.total_questions;
137+
}
138+
});
139+
return participantMap;
140+
}
141+
function saveProcessedDataToFile(data, meetingId) {
142+
const processedData = {
143+
meetingId: meetingId,
144+
attendees: Array.from(data.entries()).map(([name, participantData]) => ({
145+
name,
146+
totalTime: participantData.totalTime,
147+
joinTime: participantData.joinTime,
148+
leaveTime: participantData.leaveTime,
149+
email: participantData.email,
150+
LTId: participantData.LTId,
151+
total_score: participantData.total_score,
152+
attempted: participantData.attempted,
153+
total_questions: participantData.total_questions,
154+
}))
155+
};
156+
return processedData;
157+
}
158+
function calculateScore(pollsQuestionsResponse, pollsAnswers) {
159+
const participantMap = new Map();
160+
pollsAnswers.questions.forEach((participant) => {
161+
const participantData = {
162+
totalTime: 0,
163+
joinTime: 0,
164+
leaveTime: 0,
165+
email: '',
166+
LTId: '',
167+
total_score: 0,
168+
attempted: 0,
169+
total_questions: 0,
170+
};
171+
participant.question_details.forEach((responseDetail) => {
172+
const pollQuestion = pollsQuestionsResponse.polls.find(poll => poll.id === responseDetail.polling_id);
173+
if (pollQuestion) {
174+
const question = pollQuestion.questions.find(q => q.name == responseDetail.question);
175+
const scoreObj = {
176+
title: pollQuestion.title,
177+
question: (question === null || question === void 0 ? void 0 : question.name) || 'Default',
178+
score: 0
179+
};
180+
if (question) {
181+
participantData.attempted++;
182+
if (!question.right_answers) {
183+
scoreObj.score++;
184+
participantData.total_score++;
185+
}
186+
else {
187+
if (question.right_answers.includes(responseDetail.answer)) {
188+
scoreObj.score++;
189+
participantData.total_score++;
190+
}
191+
}
192+
}
193+
participantData.total_questions = participantData.attempted;
194+
}
195+
});
196+
participantMap.set(participant.name, participantData);
197+
});
198+
return participantMap;
199+
}
200+
function run(accountId, clientId, clientSecret, meetingId) {
201+
return __awaiter(this, void 0, void 0, function* () {
202+
const baseUrl = "https://api.zoom.us/v2";
203+
try {
204+
const bearerToken = yield getZoomAccessToken(accountId, clientId, clientSecret);
205+
const participantsResponse = yield getPastMeetingParticipants(baseUrl, meetingId, bearerToken);
206+
const pollsQuestionResponse = yield getMeetingPollsQuestions(baseUrl, meetingId, bearerToken);
207+
const pollsResponse = yield getPastMeetingPolls(baseUrl, meetingId, bearerToken);
208+
const scores = calculateScore(pollsQuestionResponse.data, pollsResponse.data);
209+
const participantMap = processParticipantsAndPollsData(participantsResponse.data.participants, scores);
210+
const processedData = saveProcessedDataToFile(participantMap, meetingId);
211+
return processedData;
212+
}
213+
catch (error) {
214+
console.error('Error:', error);
215+
}
216+
});
217+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"use strict";
2+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4+
return new (P || (P = Promise))(function (resolve, reject) {
5+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8+
step((generator = generator.apply(thisArg, _arguments || [])).next());
9+
});
10+
};
11+
Object.defineProperty(exports, "__esModule", { value: true });
12+
const zoomprocessor_1 = require("../src/zoomprocessor");
13+
test('fetch and process Zoom data', () => __awaiter(void 0, void 0, void 0, function* () {
14+
const accountId = "YOUR_ACCOUNT_ID";
15+
const clientId = "YOUR_CLIENT_ID";
16+
const clientSecret = "YOUR_CLIENT_SECRET";
17+
const meetingId = 'YOUR_MEETING_ID';
18+
const processedData = yield (0, zoomprocessor_1.run)(accountId, clientId, clientSecret, meetingId);
19+
expect(processedData).toMatchSnapshot();
20+
}));

npm_package ltsdk/jest.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
preset: 'ts-jest',
3+
testEnvironment: 'node',
4+
testMatch: ['**/tests/**/*.test.ts'],
5+
};

0 commit comments

Comments
 (0)