-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathscrap.js
More file actions
197 lines (182 loc) · 6.1 KB
/
scrap.js
File metadata and controls
197 lines (182 loc) · 6.1 KB
1
2
3
4
5
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
100
101
102
103
104
105
106
107
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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
const axios = require('axios');
const cheerio = require('cheerio');
const { parse } = require('csv-parse');
const Micp = require('./models/micp');
// Function to get the CodeChef rating of a user
const getCodeChefRating = async (codeChefId) => {
try {
const response = await axios.get(`https://www.codechef.com/users/${codeChefId}`);
if (response.status === 200) {
const $ = cheerio.load(response.data);
try {
const userName = $('.h2-style', 'header').text();
if (userName) {
const rating = parseInt($('.rating-number')?.text() || '0', 10);
return rating;
} else return -1
} catch (err) {
console.log(`Codechef: ${codeChefId} username not found`)
return -1;
}
}
} catch (err) {
console.log(`Error in getting codechef rating of ${codeChefId}`)
return -1;
}
};
// Function to get the CodeForces rating of a user
const getCodeForcesRating = async (codeForcesId) => {
const response = await axios.get(`https://codeforces.com/profile/${codeForcesId}`);
const $ = cheerio.load(response.data);
const rating = parseInt($('#pageContent div.info li span').first().text() || '0', 10);
return rating;
};
const getScore = (ccInitial, ccCurrent, cfInitial, cfCurrent) => {
const deltaCC = (ccCurrent - ccInitial) * 0.8315620555789324;
const deltaCF = cfCurrent - cfInitial;
// Normalize the CodeChef rating by multiplying it by 0.8315
return parseInt(Math.max(deltaCC, deltaCF));
};
// To populate the database with initial rating and score of new users
const populate = async (dat) => {
const micpPromises = [];
dat.forEach((user) => {
const email = user['Email Address']
const promise = new Promise(async (resolve, reject) => {
const response = await Micp.findOne({ email: email });
resolve({ user, response });
});
micpPromises.push(promise);
});
const ratingPromises = [];
await Promise.allSettled(micpPromises).then((data) => {
data.forEach((item) => {
const { response, user } = item.value;
if (response === null) {
const codeChefId = user['Codechef Username (Only username, not the link and no stars)'];
const codeForcesId = user['Codeforces Username (Only username, not the link)'];
const promise = new Promise(async (resolve, reject) => {
try {
const ccInitialRating = await getCodeChefRating(codeChefId);
const cfInitialRating = await getCodeForcesRating(codeForcesId);
if (ccInitialRating !== -1 && cfInitialRating !== -1) {
resolve({
user: user,
codeChefId: codeChefId,
codeForcesId: codeForcesId,
ccInitialRating: ccInitialRating,
cfInitialRating: cfInitialRating,
});
} else {
reject(`Error in getting ratings for user ${user.Name}`)
}
} catch (err) {
console.log(err);
reject("Error in getting rating")
}
});
ratingPromises.push(promise)
}
})
})
// console.log(ratingPromises)
const newUsersPromises = [];
await Promise.allSettled(ratingPromises).then((data) => {
data.forEach((item) => {
try {
const {
user,
codeChefId,
codeForcesId,
ccInitialRating,
cfInitialRating,
} = item.value;
const newUser = new Micp({
email: user['Email Address'],
codeChefId: codeChefId,
codeForcesId: codeForcesId,
ccCurrentRating: ccInitialRating,
ccInitialRating: ccInitialRating,
cfCurrentRating: cfInitialRating,
cfInitialRating: cfInitialRating,
score: 0,
name: user.Name,
});
const promise = new Promise(async (resolve, reject) => {
try {
await newUser.save();
resolve("Done");
} catch (err) {
console.log(err);
reject(Error("Error saving user"));
}
});
newUsersPromises.push(promise);
} catch (err) {
console.log(err)
}
});
});
await Promise.all(newUsersPromises)
.then(() => { })
.catch((err) => {
console.log(err);
});
console.log("Data populated");
};
// cron job to update the score of users every 24 hours
const updateRatingsAndScores = async () => {
const users = await Micp.find({}) || [];
const promises = [];
try {
users.forEach((user) => {
const promise = new Promise(async (resolve, reject) => {
try {
// Get the normalized score for the user
user.ccCurrentRating = await getCodeChefRating(user.codeChefId)
user.cfCurrentRating = await getCodeForcesRating(user.codeForcesId)
if (user.ccCurrentRating != -1 && user.cfCurrentRating != -1) {
const score = getScore(user.ccInitialRating, user.ccCurrentRating, user.cfInitialRating, user.cfCurrentRating)
user.score = score
console.log(score)
await user.save();
resolve('Done');
} else {
reject(`Error in updating ratings of ${user.Name}`)
}
} catch (err) {
console.log("Errors message on user save");
reject(Error('Error updating rating'));
}
});
promises.push(promise);
});
} catch (err) {
console.log(err);
}
await Promise.allSettled(promises).then(() => {
console.log('Ratings updated');
}).catch((err) => {
console.log(err);
});
};
const fetchData = async () => {
const dat = [];
const data = await axios.get('https://docs.google.com/spreadsheets/d/1E4fT40UVM8h1lZ83kNJT25QrOgrM9m7Z4COSAs6IUhE/gviz/tq?tqx=out:csv', { responseType: 'stream' });
data.data.pipe(
parse({
delimiter: ',',
columns: true,
ltrim: true,
}),
).on('data', (row) => {
dat.push(row);
}).on('error', (error) => {
console.log(error.message);
}).on('end', async () => {
console.log('parsed csv data:');
// console.log(dat);
await populate(dat);
});
};
module.exports = { updateRatingsAndScores, populate, fetchData };