Skip to content

Commit 745e8ba

Browse files
committed
get user profile from leetcode
1 parent 770c07e commit 745e8ba

File tree

6 files changed

+89
-6
lines changed

6 files changed

+89
-6
lines changed

jupyterlab_leetcode/handlers/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
from .base_handler import BaseHandler
44
from .cookie_handler import GetCookieHandler
5+
from .leetcode_handler import LeetCodeProfileHandler
56

67

78
def setup_handlers(web_app):
89
host_pattern = ".*$"
910
base_url = web_app.settings["base_url"]
10-
handlers: list[type[BaseHandler]] = [GetCookieHandler]
11+
handlers: list[type[BaseHandler]] = [GetCookieHandler, LeetCodeProfileHandler]
1112

1213
web_app.add_handlers(
1314
host_pattern,

jupyterlab_leetcode/handlers/cookie_handler.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import browser_cookie3
77
import tornado
8+
from tornado.httpclient import AsyncHTTPClient
9+
from tornado.httputil import HTTPHeaders
810

911
from .base_handler import BaseHandler
1012

@@ -60,10 +62,25 @@ def get(self):
6062
else 3600 * 24 * 14
6163
)
6264
self.set_cookie("leetcode_browser", browser, max_age=max_age)
65+
leetcode_ua = self.request.headers.get("user-agent")
6366
self.settings.update(
6467
leetcode_browser=browser,
6568
leetcode_cookiejar=cj,
66-
leetcode_ua=self.request.headers.get("user-agent"),
69+
leetcode_headers=HTTPHeaders(
70+
{
71+
"Cookie": "; ".join(f"{c.name}={c.value}" for c in cj),
72+
"Content-Type": "application/json",
73+
"Origin": "https://leetcode.com",
74+
"Referer": "https://leetcode.com/",
75+
"X-CsrfToken": (
76+
cookie_csrf.value
77+
if cookie_csrf and cookie_csrf.value
78+
else ""
79+
),
80+
}
81+
),
82+
leetcode_ua=leetcode_ua,
6783
)
84+
AsyncHTTPClient.configure(None, defaults=dict(user_agent=leetcode_ua))
6885

6986
self.finish(json.dumps(resp))
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import json
2+
3+
import tornado
4+
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
5+
from tornado.httputil import HTTPHeaders
6+
7+
from .base_handler import BaseHandler
8+
9+
LEETCODE_GRAPHQL_URL = "https://leetcode.com/graphql"
10+
11+
12+
class LeetCodeProfileHandler(BaseHandler):
13+
route = r"leetcode/profile"
14+
15+
@tornado.web.authenticated
16+
async def get(self):
17+
client = AsyncHTTPClient()
18+
headers = HTTPHeaders(self.settings.get("leetcode_headers", {}))
19+
req = HTTPRequest(
20+
url=LEETCODE_GRAPHQL_URL,
21+
method="POST",
22+
headers=headers,
23+
body=json.dumps(
24+
{
25+
"operationName": "globalData",
26+
"variables": {},
27+
"query": "query globalData { userStatus { isSignedIn username realName avatar } }",
28+
}
29+
),
30+
)
31+
32+
try:
33+
resp = await client.fetch(req)
34+
except Exception as e:
35+
self.log.error(f"Error fetching LeetCode profile: {e}")
36+
self.set_status(500)
37+
self.finish(json.dumps({"message": "Failed to fetch LeetCode profile"}))
38+
return
39+
else:
40+
self.finish(resp.body)

src/components/LeetCode.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1-
import React, { useState } from 'react';
1+
import React, { useEffect, useState } from 'react';
2+
import { getProfile } from '../services/leetcode';
23

34
const LeetCode = () => {
4-
const [_username, _setUsername] = useState('');
5+
const [username, setUsername] = useState('');
56

6-
// useEffect(() => {}, []);
7+
useEffect(() => {
8+
getProfile().then(profile => {
9+
if (!profile || !profile.isSignedIn) {
10+
alert('Please sign in to LeetCode.');
11+
return;
12+
}
13+
setUsername(profile.username);
14+
});
15+
}, []);
716

817
return (
918
<div>
10-
<p>Welcome username</p>
19+
<p>Welcome {username}</p>
1120
</div>
1221
);
1322
};

src/services/leetcode.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { LeetCodeProfile } from '../types/leetcode';
2+
import { requestAPI } from './handler';
3+
4+
export async function getProfile(): Promise<LeetCodeProfile | null> {
5+
return requestAPI<{ data: { userStatus: LeetCodeProfile } }>(
6+
'/leetcode/profile'
7+
)
8+
.then(d => d.data.userStatus)
9+
.catch(() => null);
10+
}

src/types/leetcode.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export type LeetCodeProfile = {
2+
avatar: string;
3+
isSignedIn: boolean;
4+
realName: string;
5+
username: string;
6+
};

0 commit comments

Comments
 (0)