def _authenticate(self, username: str, password: str) -> None: # Build a requests session object s = requests.session() s.headers.update({"User-Agent": "curl/7.67.0"}) # Grab a nonce r = s.get(f"{self.url}/login") if r.status_code != 200: raise AuthenticationError( f"Received status code {r.status_code} from login get") # Parse the nonce nonce = r.text.split('name="nonce"')[1].split('value="')[1].split( '"')[0] # Attempt authentication r = s.post( f"{self.url}/login", data={ "name": username, "password": password, "nonce": nonce }, ) if r.status_code != 200: raise AuthenticationError( f"received status code {r.status_code} from login post") # Grab the CSRF token try: self.csrf_token = r.text.split('csrf_nonce = "')[1].split('"')[0] except IndexError: self.csrf_token = r.text.split("csrfNonce': \"")[1].split('"')[0] # Save requests session self.session = s # Get user profile r = self.session.get(f"{self.url}/api/v1/users/me") if r.status_code != 200: raise RuntimeError(f"failed to retrieve profile") data = r.json()["data"] self.me = User( name=data["name"], score=data["score"], ident=str(data["id"]), team=data["team"] if "team" in data else None, solves=[], )
def scoreboard(self, localize: User = None, count=10, bracket: Bracket = None) -> Dict[int, User]: # Pico lists the scoreboard around your user by default if localize is not None: params = {} else: params = {"page": 1} if bracket is None and localize is not None: # Use this user's bracket bracket = localize.bracket elif bracket is None: # Default to the highest priority bracket bracket = self.brackets[0] # Grab the scoreboard success, board, _ = self._api( f"/scoreboards/{bracket.ident}/scoreboard", params=params) if not success: return [] # Calculate start based on localize if localize is not None: pos = 0 for n, team in enumerate(board["scoreboard"]): if team["name"] == localize.team: pos = n start = pos - int(count / 2) else: start = 0 # Calculate end from start and count end = start + count # Bound start and end within the results if start < 0: end -= start start = 0 if end > len(board["scoreboard"]): start -= end - len(board["scoreboard"]) end = len(board["scoreboard"]) if start < 0: start = 0 return {((board["current_page"] - 1) * 50 + n + 1): User(t["name"], t["score"], None, t["name"], [], bracket) for n, t in enumerate(board["scoreboard"][start:end])}
def scoreboard(self, localize: User = None, count=10, bracket: Bracket = None) -> Dict[int, User]: # Request the scoreboard, which lists all users r = self.session.get(f"{self.url}/api/v1/scoreboard") if r.status_code != 200: raise RuntimeError("failed to get scoreboard") # Extract data data = r.json()["data"] # Assume we are starting at the top start = 0 if localize is not None: for pos, u in enumerate(data): if (u["account_type"] == "team" and u["name"] == localize.team) or (u["account_type"] != "team" and u["name"] == localize.name): start = pos break # Ideal world, grab this section of the scoreboard start -= int(count / 2) end = start + count # Account for under or overflow if start < 0: end -= start start = 0 if end >= len(data): start -= end - len(data) end = len(data) if start < 0: start = 0 return {(pos + start + 1): User( name=u["name"], score=u["score"], ident=str(u["account_id"]), team=u["team"] if "team" in u else u["name"], ) for pos, u in enumerate(data[start:end])}
def _authenticate(self, username: str, password: str) -> None: # Build session self.session = requests.Session() # Attempt authentication success, result, resp = self._api( "/user/login", args={ "username": username, "password": password }, method="POST", ) # Check if we succeeded if not success or not result["success"]: raise AuthenticationError() # Save CSRF token self.token = resp.cookies["token"] # Request the user profile success, result, _ = self._api("/user") if not success: return None self.me = User(result["username"], result["score"], result["tid"]) # Grab the team information success, team, _ = self._api("/team") if not success: return # Grab brackets brackets = self.brackets for b in brackets: if b.ident == team["eligibilities"][0]: self.me.bracket = b # Save team name self.me.team = team["team_name"]
def users(self) -> Generator[User, None, None]: # Request the scoreboard, which lists all users r = self.session.get(f"{self.url}/api/v1/scoreboard") if r.status_code != 200: raise RuntimeError("failed to get scoreboard") # Extract data data = r.json()["data"] # Yield all users for u in data: yield User( name=u["name"], score=u["score"], ident=u["account_id"], team=u["team"] if "team" in u else None, ) return