Skip to content

Commit 0467a68

Browse files
committed
[refactor] 찐막
1 parent 0c25872 commit 0467a68

6 files changed

Lines changed: 343 additions & 35 deletions

File tree

common/boj_utils.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,78 @@ async def get_user_solved_problems_from_solved_ac(baekjoon_id: str, target_probl
191191
return []
192192

193193

194+
async def check_problems_individual_queries(baekjoon_id: str, target_problems: List[int], headers: dict) -> List[int]:
195+
"""
196+
각 문제마다 개별 query를 날려서 해결 여부 확인
197+
https://solved.ac/problems?query=s@{handle}+{problem_id}&page=1
198+
199+
모의테스트처럼 문제 수가 적을 때 사용 (42페이지를 모두 조회할 필요 없음)
200+
"""
201+
try:
202+
import urllib.parse
203+
204+
solved_problems = []
205+
target_set = set(target_problems)
206+
207+
logger.info(f"[개별 문제 확인] {baekjoon_id} - {len(target_problems)}개 문제 개별 확인 시작")
208+
209+
async with aiohttp.ClientSession(headers=headers) as session:
210+
for problem_id in target_problems:
211+
# 각 문제마다 query: s@{handle}+{problem_id}
212+
query = f"s@{baekjoon_id}+{problem_id}"
213+
encoded_query = urllib.parse.quote(query)
214+
url = f"https://solved.ac/problems?query={encoded_query}&page=1"
215+
216+
try:
217+
async with session.get(url) as response:
218+
if response.status != 200:
219+
logger.debug(f"[개별 문제 확인] {baekjoon_id} - 문제 {problem_id}: HTTP {response.status}")
220+
await asyncio.sleep(0.2)
221+
continue
222+
223+
html = await response.text()
224+
soup = BeautifulSoup(html, 'html.parser')
225+
226+
# "해당하는 문제가 없습니다" 메시지 확인
227+
no_problems_text = soup.find(string=re.compile(r'해당하는 문제가 없습니다|문제가 없습니다'))
228+
if no_problems_text:
229+
logger.debug(f"[개별 문제 확인] {baekjoon_id} - 문제 {problem_id}: 미해결")
230+
await asyncio.sleep(0.2)
231+
continue
232+
233+
# 문제 번호가 결과에 있는지 확인
234+
problem_links = soup.find_all('a', href=re.compile(r'(?:www\.)?acmicpc\.net/problem/\d+|/problem/\d+'))
235+
found = False
236+
for link in problem_links:
237+
href = link.get('href', '')
238+
match = re.search(r'(?:www\.)?acmicpc\.net/problem/(\d+)|/problem/(\d+)', href)
239+
if match:
240+
found_id = int(match.group(1) or match.group(2))
241+
if found_id == problem_id:
242+
solved_problems.append(problem_id)
243+
found = True
244+
logger.debug(f"[개별 문제 확인] {baekjoon_id} - 문제 {problem_id}: 해결됨")
245+
break
246+
247+
if not found:
248+
logger.debug(f"[개별 문제 확인] {baekjoon_id} - 문제 {problem_id}: 미해결")
249+
250+
await asyncio.sleep(0.2) # Rate limiting 방지
251+
252+
except Exception as e:
253+
logger.error(f"[개별 문제 확인] {baekjoon_id} - 문제 {problem_id} 확인 중 오류: {e}")
254+
await asyncio.sleep(0.2)
255+
continue
256+
257+
solved_problems = sorted(list(set(solved_problems)))
258+
logger.info(f"[개별 문제 확인] {baekjoon_id} - {len(solved_problems)}/{len(target_problems)}개 해결")
259+
return solved_problems
260+
261+
except Exception as e:
262+
logger.error(f"[개별 문제 확인] 오류: {e}", exc_info=True)
263+
return []
264+
265+
194266
async def _check_problems_via_search_api(baekjoon_id: str, target_problems: List[int], headers: dict) -> List[int]:
195267
"""
196268
solved.ac 문제 검색 API를 사용하여 사용자가 푼 모든 문제를 페이지네이션으로 확인

common/database.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,19 @@ def get_group_all_assignment_status(group_name: str) -> Optional[Dict]:
861861
return dict(row)
862862
return None
863863

864+
def get_group_all_assignment_status_by_message(channel_id: str, message_id: str) -> Optional[Dict]:
865+
"""메시지 기준으로 전체과제현황 가져오기"""
866+
conn = get_connection()
867+
cursor = conn.cursor()
868+
869+
cursor.execute('SELECT * FROM group_all_assignment_status WHERE channel_id = ? AND message_id = ?', (channel_id, message_id))
870+
row = cursor.fetchone()
871+
conn.close()
872+
873+
if row:
874+
return dict(row)
875+
return None
876+
864877
def get_all_group_all_assignment_status() -> List[Dict]:
865878
"""모든 전체과제현황 메시지 목록 가져오기"""
866879
conn = get_connection()

0 commit comments

Comments
 (0)