diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..b4d11da --- /dev/null +++ b/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +pythonpath = . +addopts = --cov=src --cov-report html +norecursedirs = tmp* diff --git a/requirments.txt b/requirments.txt new file mode 100644 index 0000000..a93ea82 --- /dev/null +++ b/requirments.txt @@ -0,0 +1,3 @@ +pytest +click +psycopg2 diff --git a/src/extract.py b/src/extract.py new file mode 100644 index 0000000..056f121 --- /dev/null +++ b/src/extract.py @@ -0,0 +1,188 @@ +import psycopg2 as pg +from os import environ as env +from typing import TypeVar + +T = TypeVar("T") +U = TypeVar("U") + + +def connect(): + return pg.connect( + dbname=env.get("POSTGRES_DB"), + user=env.get("POSTGRES_USER"), + password=env.get("POSTGRES_PASSWORD"), + host=env.get("POSTGRES_HOST"), + port=env.get("POSTGRES_PORT"), + ) + + +def extract_cols(data: dict, cols: list[str]) -> dict: return {key: data.get(key) for key in cols} + + +def score_to_text(score: list[int]) -> str: + return "-".join(map(str, score)) + + +# maybe could get columns form db +def cols_from_player_stats(player_stats: dict) -> dict: + cols = [ + "id", + "gameId", + "gameFinishedAt", + "steam64Id", + "name", + "preaim", + "reactionTime", + "accuracy", + "accuracyEnemySpotted", + "accuracyHead", + "shotsFiredEnemySpotted", + "shotsFired", + "shotsHitEnemySpotted", + "shotsHitFriend", + "shotsHitFriendHead", + "shotsHitFoe", + "shotsHitFoeHead", + "utilityOnDeathAvg", + "heFoesDamageAvg", + "heFriendsDamageAvg", + "heThrown", + "molotovThrown", + "smokeThrown", + "smokeThrownCT", + "smokeThrownCTGood", + "smokeThrownCTGoodRatio", + "smokeThrownCTFoes", + "counterStrafingShotsAll", + "counterStrafingShotsBad", + "counterStrafingShotsGood", + "counterStrafingShotsGoodRatio", + "flashbangHitFoe", + "flashbangLeadingToKill", + "flashbangHitFoeAvgDuration", + "flashbangHitFriend", + "flashbangThrown", + "flashAssist", + "score", + "initialTeamNumber", + "mvps", + "ctRoundsWon", + "ctRoundsLost", + "tRoundsWon", + "tRoundsLost", + "sprayAccuracy", + "molotovFoesDamageAvg", + "molotovFriendsDamageAvg", + "color", + "totalKills", + "totalDeaths", + "kdRatio", + "multi2k", + "multi3k", + "multi4k", + "multi5k", + "hltvRating", + "hsp", + "roundsSurvived", + "roundsSurvivedPercentage", + "dpr", + "totalAssists", + "totalDamage", + "tradeKillOpportunities", + "tradeKillAttempts", + "tradeKillsSucceeded", + "tradeKillAttemptsPercentage", + "tradeKillsSuccessPercentage", + "tradeKillOpportunitiesPerRound", + "tradedDeathOpportunities", + "tradedDeathAttempts", + "tradedDeathAttemptsPercentage", + "tradedDeathsSucceeded", + "tradedDeathsSuccessPercentage", + "tradedDeathsOpportunitiesPerRound", + "leetifyRating", + "personalPerformanceRating", + "ctLeetifyRating", + "tLeetifyRating", + "leetifyUserId", + "isCollector", + "isProPlan", + "isLeetifyStaff", + ] + + return extract_cols(player_stats, cols) + + +def cols_from_profile_game(game: dict) -> dict: + cols = [ + "ctLeetifyRating", + "ctLeetifyRatingRounds", + "dataSource", + "elo", + "gameFinishedAt", + "gameId", + "isCs2", + "mapName", + "matchResult", + "scores", + "skillLevel", + "tLeetifyRating", + "tLeetifyRatingRounds", + "deaths", + "hasBannedPlayer", + "kills", + "partySize", + ] + return extract_cols(game, cols) + + +def meta_from_profile(profile: dict) -> dict: + meta = profile.get("meta") + if not meta: + raise Exception("Could not get profile metadata", profile) + + cols = [ + "name", + "steam64Id", + "isCollector", + "isLeetifyStaff", + "isProPlan", + "leetifyUserId", + "faceitNickname", + ] + + return extract_cols(meta, cols) + + +def insert_value(data: dict[T, U], key: T, value: U) -> dict[T, U]: + data[key] = value + return data + + +def convert_game_scores(game: dict) -> dict: + score = game.get("scores") + if not score: + raise Exception("Could not get score from prfile game", game) + + score = score_to_text(score) + game["scores"] = score + return game + + +def games_from_profile(profile: dict) -> list: + games = profile.get("games") + if not games and not type(games) == list: + raise Exception("Could not get games from profile", profile) + + meta = profile.get("meta") + if not meta: + raise Exception("Could not get profile metadata", profile) + + id = meta.get("leetifyUserId") + if not id: + raise Exception("Could not get id from profile metadata", meta, profile) + + games = map(cols_from_profile_game, games) + games = map(lambda game: insert_value(game, "leetifyUserId", id), games) + games = map(convert_game_scores, games) + return list(games) diff --git a/src/leetify/__init__.py b/src/leetify/__init__.py new file mode 100644 index 0000000..bb67a43 --- /dev/null +++ b/src/leetify/__init__.py @@ -0,0 +1 @@ +from .core import * diff --git a/src/leetify/core.py b/src/leetify/core.py new file mode 100644 index 0000000..29420de --- /dev/null +++ b/src/leetify/core.py @@ -0,0 +1,19 @@ +import requests + + +class Leetify: + api_base_url = "https://api.leetify.com/api" + profile_base_url = f"{api_base_url}/profile" + match_base_url = f"{api_base_url}/games" + + def __get_page(self, url: str) -> dict: + resp = requests.get(url) + return resp.json() + + def get_profile(self, id: str) -> dict: + url = f"{self.profile_base_url}/{id}" + return self.__get_page(url) + + def get_match(self, id: str) -> dict: + url = f"{self.match_base_url}/{id}" + return self.__get_page(url) diff --git a/test/test_extract.py b/test/test_extract.py new file mode 100644 index 0000000..2a2aa8f --- /dev/null +++ b/test/test_extract.py @@ -0,0 +1,791 @@ +from src import extract as ex +from pytest import fixture + + +@fixture +def profile(): + return { + "highlights": [ + { + "createdAt": "2023-12-10T22:36:26.813Z", + "description": "AK-47 4K on Overpass", + "gameId": "4647ec10-dc9a-4afd-b9e0-144a462970b2", + "id": "7f4fc8a6-6198-47e1-aa96-f455b70b1f04", + "isPinned": True, + "pendingPro": False, + "rankValue": None, + "roundNumber": 20, + "steam64Id": "76561198036388580", + "thumbnailUrl": "https://media.allstar.gg/6269b3881c45be12afd59318/thumbs/657bcaac1a8ab6000d65a27f_thumb.jpg", + "url": "https://allstar.gg/iframe?clip=657bcaac1a8ab6000d65a27f&known=false&platform=L202211&useCase=WC&sid=76561198036388580", + "username": "skaterCS", + }, + { + "createdAt": "2023-12-24T02:15:57.052Z", + "description": "AK-47 4K on Vertigo", + "gameId": "5699e90e-ec76-4ed8-99f3-7905315960ae", + "id": "6e3d2aa4-cf57-44b4-8d85-c771a4d4d5b6", + "isPinned": True, + "pendingPro": False, + "rankValue": None, + "roundNumber": 18, + "steam64Id": "76561198036388580", + "thumbnailUrl": "https://media.allstar.gg/6269b3881c45be12afd59318/thumbs/658e3f6d0c66ff000d4e93a3_thumb.jpg", + "url": "https://allstar.gg/iframe?clip=658e3f6d0c66ff000d4e93a3&known=false&platform=L202211&useCase=WC&sid=76561198036388580", + "username": "skaterCS", + }, + { + "createdAt": "2023-12-31T23:53:11.150Z", + "description": "4K on Anubis", + "gameId": "2466135e-aae5-4966-a11f-477cceee6499", + "id": "51aac0ff-5140-46ad-8e46-db6d752f99b1", + "isPinned": False, + "pendingPro": False, + "rankValue": None, + "roundNumber": 6, + "steam64Id": "76561198036388580", + "thumbnailUrl": "https://media.allstar.gg/6269b3881c45be12afd59318/thumbs/6597a2d4589d590012898af7_thumb.jpg", + "url": "https://allstar.gg/iframe?clip=6597a2d4589d590012898af7&known=false&platform=L202211&useCase=WC&sid=76561198036388580", + "username": "skaterCS", + }, + { + "createdAt": "2024-01-08T00:48:19.753Z", + "description": "AK-47 4K on Inferno", + "gameId": "6691ea4b-4d5d-4ffc-aabd-ac6f2ce291c0", + "id": "e85ca957-e6cb-4d96-9f02-1850af23d5b0", + "isPinned": False, + "pendingPro": False, + "rankValue": None, + "roundNumber": 22, + "steam64Id": "76561198036388580", + "thumbnailUrl": "https://media.allstar.gg/6269b3881c45be12afd59318/thumbs/65a108eba0d42f000c9af008_thumb.jpg", + "url": "https://allstar.gg/iframe?clip=65a108eba0d42f000c9af008&known=false&platform=L202211&useCase=WC&sid=76561198036388580", + "username": "skaterCS", + }, + { + "createdAt": "2024-01-13T20:50:07.002Z", + "description": "AK-47 4K on Ancient", + "gameId": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "id": "90af8cd2-3224-4bc6-9dc9-d778ed93339c", + "isPinned": False, + "pendingPro": False, + "rankValue": None, + "roundNumber": 10, + "steam64Id": "76561198036388580", + "thumbnailUrl": "https://media.allstar.gg/6269b3881c45be12afd59318/thumbs/65ac1f0b230e6e000dba9cbc_thumb.jpg", + "url": "https://allstar.gg/iframe?clip=65ac1f0b230e6e000dba9cbc&known=false&platform=L202211&useCase=WC&sid=76561198036388580", + "username": "skaterCS", + }, + ], + "personalBests": [], + "recentGameRatings": { + "aim": 67.72418696226975, + "positioning": 36.31694139929697, + "utility": 51.595349880463615, + "gamesPlayed": 30, + "leetifyRatingRounds": 620, + "clutch": 0.13, + "ctLeetify": -0.0114, + "leetify": -0.0121, + "opening": -0.0598, + "tLeetify": -0.0128, + }, + "teammates": [ + { + "isCollector": False, + "isProPlan": False, + "leetifyUserId": "5e28e0c9-4b01-4fa3-b568-c9ae56ed8ac1", + "isBanned": False, + "isLeetifyStaff": False, + "matchesPlayedTogether": 32, + "profileUserLeetifyRating": -0.0016909883720930246, + "rank": { + "type": "premier", + "dataSource": "matchmaking", + "skillLevel": 15267, + }, + "steam64Id": "76561198228115488", + "steamAvatarUrl": "https://avatars.steamstatic.com/361d26bb315644059663ab9c32479c09bddbcb96_full.jpg", + "steamNickname": "AustinShyd", + "teammateLeetifyRating": 0.013207703488372092, + "winRateTogether": 0.5666666666666667, + }, + { + "isCollector": False, + "isProPlan": True, + "leetifyUserId": "8c3a9cb5-faaf-4401-ae9a-72f5e8528651", + "isBanned": False, + "isLeetifyStaff": False, + "matchesPlayedTogether": 21, + "profileUserLeetifyRating": -0.0037864444444444456, + "rank": {"dataSource": "faceit", "skillLevel": 6}, + "steam64Id": "76561198376400117", + "steamAvatarUrl": "https://avatars.akamai.steamstatic.com/8e0029277f9fe4f57d9319d6143cbf72df0d717f_full.jpg", + "steamNickname": "TiMe_TrAvLeR87", + "teammateLeetifyRating": -0.002907555555555556, + "winRateTogether": 0.5714285714285714, + }, + { + "isCollector": False, + "isProPlan": False, + "leetifyUserId": "163b492d-931d-4021-bdb9-6e6d4f37b2b2", + "isBanned": False, + "isLeetifyStaff": False, + "matchesPlayedTogether": 11, + "profileUserLeetifyRating": 0.01336536964980545, + "rank": { + "type": "premier", + "dataSource": "matchmaking", + "skillLevel": 9135, + }, + "steam64Id": "76561198019127603", + "steamAvatarUrl": "https://avatars.steamstatic.com/b93f04b9194fba8980a2dc74947d47d0087ba113_full.jpg", + "steamNickname": "Lit Taco", + "teammateLeetifyRating": -0.02468832684824903, + "winRateTogether": 0.6363636363636364, + }, + { + "isCollector": False, + "isProPlan": False, + "leetifyUserId": "a47ba360-5fb1-4b88-b701-31f7c7ae4659", + "isBanned": False, + "isLeetifyStaff": False, + "matchesPlayedTogether": 27, + "profileUserLeetifyRating": 0.014388762214983713, + "rank": {"dataSource": "faceit", "skillLevel": 2}, + "steam64Id": "76561197992874735", + "steamAvatarUrl": "https://avatars.steamstatic.com/1982d13a52fa8e8364d681966972a1de70a36c64_full.jpg", + "steamNickname": "Mela", + "teammateLeetifyRating": -0.02852671009771987, + "winRateTogether": 0.5185185185185185, + }, + { + "isCollector": False, + "isProPlan": False, + "leetifyUserId": "f6b4342b-3779-4144-9e53-9d4d408a315c", + "isBanned": False, + "isLeetifyStaff": False, + "matchesPlayedTogether": 22, + "profileUserLeetifyRating": 0.013741448692152916, + "rank": {"dataSource": "faceit", "skillLevel": 6}, + "steam64Id": "76561199022813257", + "steamAvatarUrl": "https://avatars.steamstatic.com/1ce49c3e9b812ab90ef16d34bfaf60193e7a7489_full.jpg", + "steamNickname": "Sharky", + "teammateLeetifyRating": 0.02733762575452716, + "winRateTogether": 0.5, + }, + { + "isCollector": False, + "isProPlan": False, + "leetifyUserId": "95921f4b-e2aa-466a-adce-4b53b220cc2d", + "isBanned": False, + "isLeetifyStaff": False, + "matchesPlayedTogether": 13, + "profileUserLeetifyRating": -0.0076067375886524815, + "rank": { + "type": "premier", + "dataSource": "matchmaking", + "skillLevel": 14568, + }, + "steam64Id": "76561199046277694", + "steamAvatarUrl": "https://avatars.akamai.steamstatic.com/ccd7f5b712406dbbfccc544005fd4731a777c5a1_full.jpg", + "steamNickname": "fwdz", + "teammateLeetifyRating": 0.03853794326241135, + "winRateTogether": 0.5, + }, + { + "isCollector": False, + "isProPlan": False, + "leetifyUserId": "a3619755-fffa-49a3-8074-03e1de9dc2c1", + "isBanned": True, + "isLeetifyStaff": False, + "matchesPlayedTogether": 43, + "profileUserLeetifyRating": -0.00885761802575107, + "rank": { + "type": "premier", + "dataSource": "matchmaking", + "skillLevel": 10001, + }, + "steam64Id": "76561198051811238", + "steamAvatarUrl": "https://avatars.akamai.steamstatic.com/4611b64e6ea807573525239f57e55fc2ccdbedd7_full.jpg", + "steamNickname": "Revolver_FPS", + "teammateLeetifyRating": -0.02219978401727862, + "winRateTogether": 0.5, + }, + { + "isCollector": False, + "isProPlan": False, + "leetifyUserId": "70faf9da-07f9-4a24-afe9-fb84be5d7706", + "isBanned": False, + "isLeetifyStaff": False, + "matchesPlayedTogether": 33, + "profileUserLeetifyRating": 0.00413012729844413, + "rank": { + "type": "premier", + "dataSource": "matchmaking", + "skillLevel": 10243, + }, + "steam64Id": "76561198174606711", + "steamAvatarUrl": "https://avatars.akamai.steamstatic.com/e903300342a9eba51d920af5b2ea10080f270a42_full.jpg", + "steamNickname": "Mqple", + "teammateLeetifyRating": 0.008475536480686696, + "winRateTogether": 0.48484848484848486, + }, + { + "isCollector": False, + "isProPlan": False, + "isBanned": False, + "isLeetifyStaff": False, + "matchesPlayedTogether": 11, + "profileUserLeetifyRating": -0.01507543859649123, + "rank": {"dataSource": "faceit", "skillLevel": 5}, + "steam64Id": "76561198216410960", + "steamAvatarUrl": "https://avatars.akamai.steamstatic.com/2e601d5cd472b63f3b5235364d55e2f6b99ec326_full.jpg", + "steamNickname": "Yaw", + "teammateLeetifyRating": 0.02286578947368421, + "winRateTogether": 0.5454545454545454, + }, + ], + "games": [ + { + "enemyTeamSteam64Ids": [ + "76561198017884049", + "76561198376400117", + "76561198097337225", + "76561198801253208", + "76561198883031817", + ], + "isCompletedLongMatch": False, + "ownTeamSteam64Ids": [ + "76561198060167512", + "76561198036388580", + "76561198048048148", + "76561198246440596", + "76561198108997204", + ], + "ownTeamTotalLeetifyRatingRounds": { + "76561198060167512": 23, + "76561198036388580": 23, + "76561198048048148": 23, + "76561198246440596": 23, + "76561198108997204": 23, + }, + "ownTeamTotalLeetifyRatings": { + "76561198060167512": 0.0473, + "76561198036388580": 0.0773, + "76561198048048148": -0.0426, + "76561198246440596": -0.0048, + "76561198108997204": -0.0049, + }, + "ctLeetifyRating": -0.0157, + "ctLeetifyRatingRounds": 12, + "dataSource": "faceit", + "elo": 1273, + "gameFinishedAt": "2024-01-13T20:45:53.000Z", + "gameId": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "isCs2": True, + "mapName": "de_ancient", + "matchResult": "win", + "rankType": None, + "scores": [13, 10], + "skillLevel": 6, + "tLeetifyRating": 0.1625, + "tLeetifyRatingRounds": 11, + "deaths": 11, + "hasBannedPlayer": False, + "kills": 19, + "partySize": 1, + }, + { + "enemyTeamSteam64Ids": [ + "76561198052273476", + "76561199145898951", + "76561199239125525", + "76561198086636793", + "76561199009125853", + ], + "isCompletedLongMatch": False, + "ownTeamSteam64Ids": [ + "76561198036388580", + "76561198123663481", + "76561198212556913", + "76561198282254268", + "76561198218979692", + ], + "ownTeamTotalLeetifyRatingRounds": { + "76561198036388580": 18, + "76561198123663481": 18, + "76561198212556913": 18, + "76561198282254268": 18, + "76561198218979692": 18, + }, + "ownTeamTotalLeetifyRatings": { + "76561198036388580": 0.0138, + "76561198123663481": 0.0004, + "76561198212556913": -0.0143, + "76561198282254268": 0.0516, + "76561198218979692": 0.1367, + }, + "ctLeetifyRating": -0.015, + "ctLeetifyRatingRounds": 6, + "dataSource": "faceit", + "elo": 1248, + "gameFinishedAt": "2024-01-13T00:51:26.000Z", + "gameId": "ba78c2f5-99b8-4d4d-afbd-cacee7894dbb", + "isCs2": True, + "mapName": "de_vertigo", + "matchResult": "win", + "rankType": None, + "scores": [13, 5], + "skillLevel": 6, + "tLeetifyRating": 0.0715, + "tLeetifyRatingRounds": 12, + "deaths": 12, + "hasBannedPlayer": False, + "kills": 13, + "partySize": 1, + }, + { + "enemyTeamSteam64Ids": [ + "76561198180054591", + "76561198103217250", + "76561198255756012", + "76561199228602800", + "76561198131413139", + ], + "isCompletedLongMatch": False, + "ownTeamSteam64Ids": [ + "76561198799389823", + "76561198068730110", + "76561198086636793", + "76561199145898951", + "76561198036388580", + ], + "ownTeamTotalLeetifyRatingRounds": { + "76561198799389823": 24, + "76561198068730110": 24, + "76561198086636793": 24, + "76561199145898951": 24, + "76561198036388580": 24, + }, + "ownTeamTotalLeetifyRatings": { + "76561198799389823": -0.0014, + "76561198068730110": 0.0375, + "76561198086636793": -0.0134, + "76561199145898951": -0.0543, + "76561198036388580": -0.0161, + }, + "ctLeetifyRating": 0.0091, + "ctLeetifyRatingRounds": 12, + "dataSource": "faceit", + "elo": 1273, + "gameFinishedAt": "2024-01-13T00:11:36.000Z", + "gameId": "f57fc165-8d9d-4cbb-aeaf-3305bf96f6b1", + "isCs2": True, + "mapName": "de_anubis", + "matchResult": "loss", + "rankType": None, + "scores": [11, 13], + "skillLevel": 6, + "tLeetifyRating": -0.0413, + "tLeetifyRatingRounds": 12, + "deaths": 17, + "hasBannedPlayer": False, + "kills": 12, + "partySize": 1, + }, + { + "enemyTeamSteam64Ids": [ + "76561199065317871", + "76561199133043212", + "76561199237862815", + "76561197979349420", + "76561199568936482", + ], + "isCompletedLongMatch": False, + "ownTeamSteam64Ids": [ + "76561197991931943", + "76561198174606711", + "76561199057228627", + "76561198075880354", + "76561198036388580", + ], + "ownTeamTotalLeetifyRatingRounds": { + "76561197991931943": 20, + "76561198174606711": 20, + "76561199057228627": 20, + "76561198075880354": 20, + "76561198036388580": 20, + }, + "ownTeamTotalLeetifyRatings": { + "76561197991931943": -0.062, + "76561198174606711": 0.0301, + "76561199057228627": 0.0457, + "76561198075880354": 0.0723, + "76561198036388580": 0.0185, + }, + "ctLeetifyRating": 0.0273, + "ctLeetifyRatingRounds": 8, + "dataSource": "faceit", + "elo": 962, + "gameFinishedAt": "2023-11-12T19:53:56.000Z", + "gameId": "76bd9c1b-4350-4cba-a85c-853dda2319a3", + "isCs2": True, + "mapName": "de_vertigo", + "matchResult": "win", + "rankType": None, + "scores": [13, 7], + "skillLevel": 4, + "tLeetifyRating": 0.0053, + "tLeetifyRatingRounds": 12, + }, + { + "enemyTeamSteam64Ids": [ + "76561199215625191", + "76561198138569488", + "76561198882489909", + "76561198967893666", + "76561199480114036", + ], + "isCompletedLongMatch": True, + "ownTeamSteam64Ids": [ + "76561198232726872", + "76561198174606711", + "76561198036388580", + "76561198051811238", + "76561198060380124", + ], + "ownTeamTotalLeetifyRatingRounds": { + "76561198232726872": 41, + "76561198174606711": 41, + "76561198036388580": 41, + "76561198051811238": 41, + "76561198060380124": 41, + }, + "ownTeamTotalLeetifyRatings": { + "76561198232726872": 0.0271, + "76561198174606711": 0.0056, + "76561198036388580": 0.0273, + "76561198051811238": -0.0392, + "76561198060380124": -0.0188, + }, + "ctLeetifyRating": 0.0493, + "ctLeetifyRatingRounds": 21, + "dataSource": "faceit", + "elo": 910, + "gameFinishedAt": "2023-11-11T03:35:16.000Z", + "gameId": "fdd3867f-225b-4177-bc99-661a7fa43c41", + "isCs2": True, + "mapName": "de_vertigo", + "matchResult": "win", + "rankType": None, + "scores": [22, 19], + "skillLevel": 4, + "tLeetifyRating": 0.0063, + "tLeetifyRatingRounds": 20, + }, + { + "enemyTeamSteam64Ids": [ + "76561198954974027", + "76561198340039100", + "76561198267258925", + "76561198132032289", + "76561198268422115", + ], + "isCompletedLongMatch": False, + "ownTeamSteam64Ids": [ + "76561197962906363", + "76561197971574216", + "76561198036388580", + "76561198174606711", + "76561198142815385", + ], + "ownTeamTotalLeetifyRatingRounds": { + "76561197962906363": 23, + "76561197971574216": 23, + "76561198036388580": 23, + "76561198174606711": 23, + "76561198142815385": 23, + }, + "ownTeamTotalLeetifyRatings": { + "76561197962906363": -0.0855, + "76561197971574216": -0.004, + "76561198036388580": 0.0142, + "76561198174606711": 0.0311, + "76561198142815385": -0.039, + }, + "ctLeetifyRating": 0.0069, + "ctLeetifyRatingRounds": 12, + "dataSource": "faceit", + "elo": 960, + "gameFinishedAt": "2023-11-10T01:02:34.000Z", + "gameId": "73acee05-c6ce-4a15-9ab1-c4201443d6ff", + "isCs2": True, + "mapName": "de_mirage", + "matchResult": "loss", + "rankType": None, + "scores": [10, 13], + "skillLevel": 4, + "tLeetifyRating": 0.0209, + "tLeetifyRatingRounds": 11, + }, + ], + "meta": { + "name": "Skater", + "steam64Id": "76561198036388580", + "steamAvatarUrl": "https://avatars.akamai.steamstatic.com/ee0e6adb9c075b0b40cbedba2f8699d1c040ca6c_full.jpg", + "isCollector": False, + "isLeetifyStaff": False, + "isProPlan": False, + "leetifyUserId": "6c53f87a-5877-4dd3-ab8f-527119ce4939", + "faceitNickname": "skaterCS", + "platformBans": [], + }, + } + + +@fixture +def games(profile): + return profile["games"] + + +def test_extract_cols(profile): + empty_dict = {} + cols = ["meta"] + + res = ex.extract_cols(empty_dict, []) + assert res == {} + + res = ex.extract_cols(empty_dict, cols) + assert res == {"meta": None} + + res = ex.extract_cols(profile, []) + assert res == {} + + res = ex.extract_cols(profile, cols) + assert res == { + "meta": { + "name": "Skater", + "steam64Id": "76561198036388580", + "steamAvatarUrl": "https://avatars.akamai.steamstatic.com/ee0e6adb9c075b0b40cbedba2f8699d1c040ca6c_full.jpg", + "isCollector": False, + "isLeetifyStaff": False, + "isProPlan": False, + "leetifyUserId": "6c53f87a-5877-4dd3-ab8f-527119ce4939", + "faceitNickname": "skaterCS", + "platformBans": [], + }, + } + + cols.append("recentGameRatings") + res = ex.extract_cols(profile, cols) + assert res == { + "meta": { + "name": "Skater", + "steam64Id": "76561198036388580", + "steamAvatarUrl": "https://avatars.akamai.steamstatic.com/ee0e6adb9c075b0b40cbedba2f8699d1c040ca6c_full.jpg", + "isCollector": False, + "isLeetifyStaff": False, + "isProPlan": False, + "leetifyUserId": "6c53f87a-5877-4dd3-ab8f-527119ce4939", + "faceitNickname": "skaterCS", + "platformBans": [], + }, + "recentGameRatings": { + "aim": 67.72418696226975, + "positioning": 36.31694139929697, + "utility": 51.595349880463615, + "gamesPlayed": 30, + "leetifyRatingRounds": 620, + "clutch": 0.13, + "ctLeetify": -0.0114, + "leetify": -0.0121, + "opening": -0.0598, + "tLeetify": -0.0128, + }, + } + + +def test_score_to_text(): + text = ex.score_to_text([]) + assert text == "" + + text = ex.score_to_text([1]) + assert text == "1" + + text = ex.score_to_text([1, 2]) + assert text == "1-2" + + text = ex.score_to_text([1, 2, 3]) + assert text == "1-2-3" + + +def test_meta_from_profile(profile): + res = ex.meta_from_profile(profile) + assert res == { + "name": "Skater", + "steam64Id": "76561198036388580", + "isCollector": False, + "isLeetifyStaff": False, + "isProPlan": False, + "leetifyUserId": "6c53f87a-5877-4dd3-ab8f-527119ce4939", + "faceitNickname": "skaterCS", + } + + +def test_games_from_profile(profile): + games = profile["games"].copy() + + profile["games"] = [] + res = ex.games_from_profile(profile) + assert res == [] + + profile["games"] = games[:1] + res = ex.games_from_profile(profile) + assert res == [ + { + "ctLeetifyRating": -0.0157, + "ctLeetifyRatingRounds": 12, + "dataSource": "faceit", + "elo": 1273, + "gameFinishedAt": "2024-01-13T20:45:53.000Z", + "gameId": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "isCs2": True, + "mapName": "de_ancient", + "matchResult": "win", + "scores": "13-10", + "skillLevel": 6, + "tLeetifyRating": 0.1625, + "tLeetifyRatingRounds": 11, + "deaths": 11, + "hasBannedPlayer": False, + "kills": 19, + "partySize": 1, + "leetifyUserId": "6c53f87a-5877-4dd3-ab8f-527119ce4939", + } + ] + + profile["games"] = games + res = ex.games_from_profile(profile) + assert res == [ + { + "ctLeetifyRating": -0.0157, + "ctLeetifyRatingRounds": 12, + "dataSource": "faceit", + "elo": 1273, + "gameFinishedAt": "2024-01-13T20:45:53.000Z", + "gameId": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "isCs2": True, + "mapName": "de_ancient", + "matchResult": "win", + "scores": "13-10", + "skillLevel": 6, + "tLeetifyRating": 0.1625, + "tLeetifyRatingRounds": 11, + "deaths": 11, + "hasBannedPlayer": False, + "kills": 19, + "partySize": 1, + "leetifyUserId": "6c53f87a-5877-4dd3-ab8f-527119ce4939", + }, + { + "ctLeetifyRating": -0.015, + "ctLeetifyRatingRounds": 6, + "dataSource": "faceit", + "elo": 1248, + "gameFinishedAt": "2024-01-13T00:51:26.000Z", + "gameId": "ba78c2f5-99b8-4d4d-afbd-cacee7894dbb", + "isCs2": True, + "mapName": "de_vertigo", + "matchResult": "win", + "scores": "13-5", + "skillLevel": 6, + "tLeetifyRating": 0.0715, + "tLeetifyRatingRounds": 12, + "deaths": 12, + "hasBannedPlayer": False, + "kills": 13, + "partySize": 1, + "leetifyUserId": "6c53f87a-5877-4dd3-ab8f-527119ce4939", + }, + { + "ctLeetifyRating": 0.0091, + "ctLeetifyRatingRounds": 12, + "dataSource": "faceit", + "elo": 1273, + "gameFinishedAt": "2024-01-13T00:11:36.000Z", + "gameId": "f57fc165-8d9d-4cbb-aeaf-3305bf96f6b1", + "isCs2": True, + "mapName": "de_anubis", + "matchResult": "loss", + "scores": "11-13", + "skillLevel": 6, + "tLeetifyRating": -0.0413, + "tLeetifyRatingRounds": 12, + "deaths": 17, + "hasBannedPlayer": False, + "kills": 12, + "partySize": 1, + "leetifyUserId": "6c53f87a-5877-4dd3-ab8f-527119ce4939", + }, + { + "ctLeetifyRating": 0.0273, + "ctLeetifyRatingRounds": 8, + "dataSource": "faceit", + "elo": 962, + "gameFinishedAt": "2023-11-12T19:53:56.000Z", + "gameId": "76bd9c1b-4350-4cba-a85c-853dda2319a3", + "isCs2": True, + "mapName": "de_vertigo", + "matchResult": "win", + "scores": "13-7", + "skillLevel": 4, + "tLeetifyRating": 0.0053, + "tLeetifyRatingRounds": 12, + "deaths": None, + "hasBannedPlayer": None, + "kills": None, + "partySize": None, + "leetifyUserId": "6c53f87a-5877-4dd3-ab8f-527119ce4939", + }, + { + "ctLeetifyRating": 0.0493, + "ctLeetifyRatingRounds": 21, + "dataSource": "faceit", + "elo": 910, + "gameFinishedAt": "2023-11-11T03:35:16.000Z", + "gameId": "fdd3867f-225b-4177-bc99-661a7fa43c41", + "isCs2": True, + "mapName": "de_vertigo", + "matchResult": "win", + "scores": "22-19", + "skillLevel": 4, + "tLeetifyRating": 0.0063, + "tLeetifyRatingRounds": 20, + "deaths": None, + "hasBannedPlayer": None, + "kills": None, + "partySize": None, + "leetifyUserId": "6c53f87a-5877-4dd3-ab8f-527119ce4939", + }, + { + "ctLeetifyRating": 0.0069, + "ctLeetifyRatingRounds": 12, + "dataSource": "faceit", + "elo": 960, + "gameFinishedAt": "2023-11-10T01:02:34.000Z", + "gameId": "73acee05-c6ce-4a15-9ab1-c4201443d6ff", + "isCs2": True, + "mapName": "de_mirage", + "matchResult": "loss", + "scores": "10-13", + "skillLevel": 4, + "tLeetifyRating": 0.0209, + "tLeetifyRatingRounds": 11, + "deaths": None, + "hasBannedPlayer": None, + "kills": None, + "partySize": None, + "leetifyUserId": "6c53f87a-5877-4dd3-ab8f-527119ce4939", + }, + ]