def make_login_req(username, password, disconnect_sessions): with HTMLSession() as session: set_session_cookies(session) resp = request(session=session) token = get_csrf_token(resp.html, CSRF_TOKEN_INPUT_ID) if not token: return [{'data': CSRF_TOKEN_MISSING, 'code': 500}] data = { 'name': username, 'pass': password, 'form_id': LOGIN_FORM_ID[1:], 'csrfToken': token } resp = request(session=session, method='POST', data=data) resp_html = resp.html if resp.status_code == 200: if resp_html.find(SESSION_LIMIT_FORM_ID): if disconnect_sessions: resps = disconnect_active_sessions(session, resp_html) save_session_cookies(session, username) return resps else: logout(session=session) return [{'data': SESSION_LIMIT_MSG, 'code': 400}] elif resp_html.find(LOGOUT_BUTTON_CLASS): save_session_cookies(session, username) return [{'data': LOGIN_SUCCESS_MSG}] return [{'data': INCORRECT_CREDS_MSG, 'code': 400}] return [{'code': 503}]
def get_solutions(sort, order, problem_code, page, language, result, username): url = f'/status/{problem_code.upper()}' resp = request(url=url) if resp.status_code != 200: return [{'code': 503}] params = build_request_params(resp.html, language, result, username, page) resp = request(url=url, params=params) if resp.status_code == 200: if problem_code in resp.url: resp_html = resp.html solution_table = resp_html.find('table')[2] page_info = resp_html.find(PAGE_INFO_CLASS, first=True) data_rows = html_to_list(solution_table) for row in data_rows: # remove view solution column del row[-1] # format result column row[3] = ' '.join(row[3].split('\n')) resp = {'data_type': 'table', 'data': data_rows} if page_info: resp['extra'] = f'\nPage: {page_info.text}' return [resp] else: return [{'code': 404, 'data': INVALID_PROBLEM_CODE_MSG}] return [{'code': 503}]
def get_tagged_problems(sort, order, tags): resp = request(url=f'/get/tags/problems/{",".join(tags)}') try: all_tags = resp.json() except ValueError: return [{'code': 503}] if resp.status_code == 200: data_rows = [PROBLEM_LIST_TABLE_HEADINGS] all_tags = all_tags.get('all_problems') if not all_tags: return [{'code': 404, 'extra': "Sorry, there are no problems with the following tags!"}] for _, problem in all_tags.items(): problem_info = [ problem.get('code', ''), problem.get('name', ''), str(problem.get('attempted_by', '')) ] try: accuracy = (problem.get('solved_by') / problem.get('attempted_by')) * 100 problem_info.append(str(math.floor(accuracy))) except TypeError: problem_info.append('') data_rows.append(problem_info) return [{'data': data_rows, 'data_type': 'table'}] return [{'code': 503}]
def get_all_tags(): resp = request(url='/get/tags/problems') try: all_tags = resp.json() except ValueError: return [{'code': 503}] if resp.status_code == 200: data_rows = [] num_cols = 5 row = [] for index, tag in enumerate(all_tags): tag_name = tag.get('tag', '') if len(row) < num_cols: row.append(tag_name) else: data_rows.append(row) row = [tag_name] if len(row): data_rows.append(row) return [{'data': data_rows, 'data_type': 'table'}] return [{'code': 503}]
def get_contest_problems(sort, order, contest_code): url = f'/api/contests/{contest_code}?' resp = request(url=url) try: resp_json = resp.json() except ValueError: return [{"code": 503}] if resp_json['status'] == "success": problems_table = [[ x.upper() for x in [ "Name", "Code", "URL", "Successful Submissions", "Accuracy", "Scorable?"] ]] for _, problem in resp_json['problems'].items(): problems_table.append([ problem['name'], problem['code'], f"{BASE_URL}{problem['problem_url']}", problem['successful_submissions'], f"{problem['accuracy']} %", "Yes" if problem['category_name'] == 'main' else "No" ]) return [ {'data': f"\n{style_text('Name:', 'BOLD')} {resp_json['name']}\n"}, {'data': problems_table, "data_type": "table"}, {'data': f'\n{style_text("Announcements", "BOLD")}:\n{resp_json["announcements"]}'} ] elif resp_json['status'] == "error": return [{'data': 'Contest doesn\'t exist.', 'code': 404}] return [{"code": 503}]
def get_team(name): if not name: return [] resp = request(url=get_team_url(name)) if resp.status_code == 200: resp_html = resp.html tables = resp_html.find('table') header = tables[1].text.strip() team_info = tables[2].text.strip() team_info = team_info.replace(':\n', ': ') team_info_list = team_info.split('\n') basic_info = "\n".join(team_info_list[:2]) contests_info = "\n".join( [format_contest(item) for item in team_info_list[2:-1]]) problems_solved_table = html_to_list(tables[-1]) team_details = "\n".join([ '', header, '', basic_info, contests_info, '', 'Problems Successfully Solved:', '' ]) return [{ 'data': team_details }, { 'data': problems_solved_table, "data_type": "table", "is_pager": False }] elif resp.status_code == 404: return [{'code': 404, 'data': 'Team not found.'}] return [{'code': 503}]
def logout(session=None): resp = request(session=session, url='/logout') if resp.status_code == 200: if os.path.exists(COOKIES_FILE_PATH): os.remove(COOKIES_FILE_PATH) return [{'data': LOGOUT_SUCCESS_MSG}] return [{'code': 503}]
def get_solution(solution_code): resp = request(url=f'/viewplaintext/{solution_code}') if resp.status_code == 200: err_msg_element = resp.html.find(SOLUTION_ERR_MSG_CLASS, first=True) if err_msg_element and err_msg_element.text == INVALID_SOLUTION_ID_MSG: return [{'code': 404, "data": "Invalid Solution ID"}] return [{'data': f'\n{resp.html.find("pre", first=True).element.text}\n'}] return [{'code': 503}]
def get_ratings(sort, order, country, institution, institution_type, page, lines): csrf_resp = request(url='/ratings/all') if csrf_resp.status_code == 200: csrf_token = get_csrf_token(csrf_resp.html, CSRF_TOKEN_INPUT_ID) else: return [{'code': 503}] url = '/api/ratings/all?sortBy=global_rank&order=asc' params = {'page': str(page), 'itemsPerPage': str(lines), 'filterBy': ''} if country: params['filterBy'] += f'Country={country};' if institution: institution = institution.title() params['filterBy'] += f'Institution={institution};' if institution_type: params['filterBy'] += f'Institution type={institution_type};' resp = request(url=url, params=params, token=csrf_token) if resp.status_code == 200: try: ratings = resp.json() except ValueError: return [{'code': 503}] ratings = ratings.get('list') or [] if len(ratings) == 0: return [{'code': 404, 'data': 'No ratings found'}] data_rows = [RATINGS_TABLE_HEADINGS] for user in ratings: data_rows.append([ f"{str(user['global_rank'])} ({str(user['country_rank'])})", user['username'], str(user['rating']), str(user['diff']) ]) return [{'data': data_rows, 'data_type': 'table'}] return [{'code': 503}]
def disconnect_active_sessions(session, login_resp_html): token = get_csrf_token(login_resp_html, CSRF_TOKEN_INPUT_ID) post_url = get_form_url(login_resp_html) other_active_sessions = get_other_active_sessions(login_resp_html) resp = request(session=session, method='POST', url=post_url, data=other_active_sessions, token=token) if resp and hasattr(resp, 'status_code') and resp.status_code == 200: return [{'data': LOGIN_SUCCESS_MSG}] return [{'code': 503}]
def get_user(username): if not username: return [] resp = request(url=f'/users/{username}') if resp.status_code == 200: team_url = get_team_url(username) if resp.url == team_url: return [{ 'data': f'This is a team handle.' f'Run `codechefcli --team {username}` to get team info\n', 'code': 400 }] elif resp.url.rstrip('/') == BASE_URL: return [{'code': 404, 'data': 'User not found.'}] else: resp_html = resp.html details_container = resp_html.find(USER_DETAILS_CONTAINER_CLASS, first=True) # basic info header = details_container.find(HEADER, first=True).text.strip() info_list_items = details_container.find(USER_DETAILS_CLASS, first=True).find('li') # ignore first & last item i.e. username item & teams item respectively info = "\n".join( [format_list_item(li) for li in info_list_items[1:-1]]) # rating star_rating = details_container.find(STAR_RATING_CLASS, first=True).text.strip() rating = resp_html.find(RATING_NUMBER_CLASS, first=True).text.strip() rank_items = resp_html.find(RATING_RANKS_CLASS, first=True).find('li') global_rank = rank_items[0].find('a', first=True).text.strip() country_rank = rank_items[1].find('a', first=True).text.strip() user_details = "\n".join([ '', style_text(f'User Details for {header} ({username}):', 'BOLD'), '', info, f"User's Teams: {get_user_teams_url(username)}", '', f'Rating: {star_rating} {rating}', f'Global Rank: {global_rank}', f'Country Rank: {country_rank}', '', f'Find more at: {resp.url}', '' ]) return [{'data': user_details}] return [{'code': 503}]
def get_contests(show_past): resp = request(url='/contests') if resp.status_code == 200: tables = resp.html.find('table') labels = ['Present', 'Future'] if show_past: labels = ['Past'] tables = [tables[0], tables[-1]] resps = [] for idx, label in enumerate(labels): resps += [ {'data': style_text(f'{label} Contests:\n', 'BOLD')}, {'data': html_to_list(tables[idx + 1]), 'data_type': 'table'} ] return resps return [{'code': 503}]
def get_description(problem_code, contest_code): url = f'/api/contests/{contest_code}/problems/{problem_code}' resp = request(url=url) try: resp_json = resp.json() except ValueError: return [{'code': 503}] if resp_json["status"] == "success": problem = [ '', style_text('Name: ', "BOLD") + resp_json.get('problem_name', ''), style_text("Description:", "BOLD"), re.sub(r'(<|<\/)\w+>', '', resp_json.get("body", '')), '', style_text("Author: ", "BOLD") + resp_json.get('problem_author', ''), style_text("Date Added: ", "BOLD") + resp_json.get('date_added', ''), style_text("Max Time Limit: ", "BOLD") + f"{resp_json.get('max_timelimit', '')} secs", style_text("Source Limit: ", "BOLD") + f"{resp_json.get('source_sizelimit', '')} Bytes", style_text("Languages: ", "BOLD") + resp_json.get('languages_supported', ''), '' ] if resp_json.get('tags'): problem.append( style_text('Tags: ', 'BOLD') + " ".join([tag.text for tag in HTML(html=resp_json['tags']).find('a')]) ) problem.append('') if resp_json.get('editorial_url'): problem.append(style_text('Editorial: ', 'BOLD') + resp_json['editorial_url']) problem.append('') return [{"data": "\n".join(problem)}] elif resp_json["status"] == "error": return [{ 'data': 'Problem not found. Use `--search` to search in a specific contest', 'code': 404 }] return [{'code': 503}]
def submit_problem(problem_code, solution_file, language): url = f'/submit/{problem_code}' get_resp = request(url=url) if not is_logged_in(get_resp): return [{"code": 401, "data": "This session has been disconnected. Login again."}] if get_resp.status_code == 200: rhtml = get_resp.html form_token = get_form_token(rhtml) language_code = get_language_code(rhtml, language) csrf_token = get_csrf_token(rhtml, CSRF_TOKEN_INPUT_ID) if language_code is None: return [{'code': 400, 'data': 'Invalid language.'}] else: return [{'code': 503}] try: solution_file_obj = open(solution_file) except IOError: return [{'data': 'Solution file not found.', 'code': 400}] data = { 'language': language_code, 'problem_code': problem_code, 'form_id': PROBLEM_SUB_DATA_FORM_ID, 'form_token': form_token } files = {'files[sourcefile]': solution_file_obj} post_resp = request(method='POST', url=url, data=data, files=files) if post_resp.status_code == 200: print(style_text('Submitting code...\n', 'BLUE')) status_code = post_resp.url.split('/')[-1] url = f'/get_submission_status/{status_code}' print(style_text('Fetching results...\n', 'BLUE')) max_tries = 3 num_tries = 0 while True: resp = request(url=url, token=csrf_token) num_tries += 1 try: status_json = resp.json() except ValueError: if num_tries == max_tries: return [{'code': 503}] continue result_code = status_json['result_code'] if result_code != 'wait': data = '' if result_code == 'compile': error_msg = get_compilation_error(status_code) data = style_text(f'Compilation error.\n{error_msg}', 'FAIL') elif result_code == 'runtime': data = style_text(f"Runtime error. {status_json.get('signal', '')}\n", 'FAIL') elif result_code == 'wrong': data = style_text('Wrong answer\n', 'FAIL') elif result_code == 'accepted': data = 'Correct answer\n' resps = [{'data': data}] status_table = get_status_table(status_code) if status_table: resps.append({'data_type': 'table', 'data': html_to_list(status_table)}) return resps else: print(style_text('Waiting...\n', 'BLUE')) return [{'code': 503}]
def get_status_table(status_code): resp = request(url=f'/error_status_table/{status_code}') if resp.status_code != 200 or not resp.text: return return resp.html
def get_compilation_error(status_code): resp = request(url=f'/view/error/{status_code}') if resp.status_code == 200: return resp.html.find(COMPILATION_ERROR_CLASS, first=True).text return SERVER_DOWN_MSG
def search_problems(sort, order, search_type): url = f'/problems/{search_type.lower()}' resp = request(url=url) if resp.status_code == 200: return [{'data_type': 'table', 'data': html_to_list(resp.html.find('table')[1])}] return [{"code": 503}]