1+ const User = require ( "../models/users" )
2+ const fetch = require ( 'node-fetch' ) ;
3+ const oneDay = 24 * 60 * 60 * 1000 ;
4+ const fs = require ( "fs" )
5+ const BASE_URL = "https://leetcode.com"
6+ const BASE_CN_URL = "https://leetcode-cn.com"
7+
8+ const fetchUserInfo = async function ( username , dataRegion = "US" ) {
9+ try {
10+ console . log ( `fetching user ${ username } 's info from leetcode...` )
11+ let attenedContestCount , rating , globalRanking
12+ if ( dataRegion == "CN" ) {
13+ var resp = await fetch ( BASE_CN_URL + "/graphql" , {
14+ "headers" : {
15+ "accept" : "*/*" ,
16+ "accept-language" : "en" ,
17+ "content-type" : "application/json" ,
18+ "sec-ch-ua" : "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"90\", \"Google Chrome\";v=\"90\"" ,
19+ "sec-ch-ua-mobile" : "?0" ,
20+ "sec-fetch-dest" : "empty" ,
21+ "sec-fetch-mode" : "cors" ,
22+ "sec-fetch-site" : "same-origin" ,
23+ "sec-gpc" : "1" ,
24+ "x-definition-name" : "userProfilePublicProfile" ,
25+ "x-operation-name" : "userPublicProfile" ,
26+ } ,
27+ "referrer" : "https://leetcode-cn.com/u/ayamt/" ,
28+ "referrerPolicy" : "strict-origin-when-cross-origin" ,
29+ "body" : `{"operationName":"userPublicProfile","variables":{"userSlug":"${ username } "},"query":"query userPublicProfile($userSlug: String!) {\\n userProfilePublicProfile(userSlug: $userSlug) {\\n profile {\\n userSlug\\n realName\\n contestCount\\n ranking {\\n currentLocalRanking\\n currentGlobalRanking\\n currentRating\\n}\\n }\\n}\\n}\\n\"}` ,
30+ "method" : "POST" ,
31+ "mode" : "cors"
32+ } )
33+ resp = await resp . json ( )
34+ if ( resp . errors ) {
35+ return null
36+ }
37+ resp = resp . data . userProfilePublicProfile . profile
38+
39+ attenedContestCount = resp . contestCount
40+ if ( resp . ranking ) {
41+ rating = parseFloat ( resp . ranking . currentRating )
42+ globalRanking = resp . ranking . currentGlobalRanking
43+ }
44+ }
45+ else {
46+ var resp = await fetch ( BASE_URL + "/graphql" , {
47+ "headers" : {
48+ "accept" : "*/*" ,
49+ "accept-language" : "en-GB,en-US;q=0.9,en;q=0.8,hi;q=0.7,ru;q=0.6" ,
50+ "content-type" : "application/json" ,
51+ "sec-ch-ua" : `" Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"` ,
52+ "sec-ch-ua-mobile" : "?0" ,
53+ "sec-fetch-dest" : "empty" ,
54+ "sec-fetch-mode" : "cors" ,
55+ "sec-fetch-site" : "same-origin" ,
56+ "sec-gpc" : "1" ,
57+ "x-newrelic-id" : "UAQDVFVRGwEAXVlbBAg=" ,
58+ } ,
59+ "referrerPolicy" : "strict-origin-when-cross-origin" ,
60+ "body" : `{"operationName":"getContestRankingData","variables":{"username":"${ username } "},"query":"query getContestRankingData($username: String!) {\\n userContestRanking(username: $username) {\\n attendedContestsCount\\n rating\\n globalRanking\\n __typename\\n }\\n}\\n\"}` ,
61+ "method" : "POST" ,
62+ "mode" : "cors"
63+ } )
64+
65+ resp = await resp . json ( )
66+ if ( resp . errors ) {
67+ return null
68+ }
69+ resp = resp . data . userContestRanking
70+ if ( resp ) {
71+ attenedContestCount = resp . attendedContestsCount
72+ rating = resp . rating
73+ globalRanking = resp . globalRanking
74+ }
75+ }
76+ var newUser = new User ( {
77+ _id : username ,
78+ attendedContestsCount : attenedContestCount ,
79+ rating : rating ,
80+ globalRanking : globalRanking ,
81+ lastUpdated : Date . now ( )
82+ } )
83+ const user = await User . findById ( username )
84+ if ( user === null ) {
85+ await newUser . save ( ) ;
86+ console . log ( "created new user: " + username )
87+
88+ } else {
89+ await User . findByIdAndUpdate ( username , newUser )
90+ console . log ( `user ${ username } 's info updated` )
91+ }
92+ return newUser
93+ } catch ( err ) {
94+ console . error ( `Error while fetching user ${ username } 's info` , err )
95+ return null
96+ }
97+ }
98+ const getUser = async ( username , dataRegion = "US" ) => {
99+ let user = await User . findById ( username )
100+ if ( user === null ) {
101+ user = await fetchUserInfo ( username , dataRegion )
102+ }
103+ return user
104+ }
105+ exports . fetchUserInfo = fetchUserInfo
106+ exports . getUser = getUser
0 commit comments