예제 #1
0
def ban_if_blacklisted(rcon, steam_id_64, name):
    with enter_session() as sess:
        player = get_player(sess, steam_id_64)

        if not player:
            logger.error("Can't check blacklist, player not found %s",
                         steam_id_64)
            return

        if player.blacklist and player.blacklist.is_blacklisted:
            logger.info("Player %s was banned due blacklist, reason: %s",
                        str(player), player.blacklist.reason)
            rcon.do_perma_ban(name, player.blacklist.reason)
            # TODO save author of blacklist
            safe_save_player_action(rcon=rcon,
                                    player_name=name,
                                    action_type="PERMABAN",
                                    reason=player.blacklist.reason,
                                    by='BLACKLIST',
                                    steam_id_64=steam_id_64)
            try:
                send_to_discord_audit(
                    f"`BLACKLIST` -> {dict_to_discord(dict(player=name, reason=player.blacklist.reason))}",
                    "BLACKLIST")
            except:
                logger.error("Unable to send blacklist to audit log")
예제 #2
0
def ban_if_blacklisted(rcon: RecordedRcon, steam_id_64, name):
    with enter_session() as sess:
        player = get_player(sess, steam_id_64)

        if not player:
            logger.error("Can't check blacklist, player not found %s",
                         steam_id_64)
            return

        if player.blacklist and player.blacklist.is_blacklisted:
            try:
                logger.info("Player %s was banned due blacklist, reason: %s",
                            str(name), player.blacklist.reason)
                rcon.do_perma_ban(player=name,
                                  reason=player.blacklist.reason,
                                  by=f"BLACKLIST: {player.blacklist.by}")
                safe_save_player_action(rcon=rcon,
                                        player_name=name,
                                        action_type="PERMABAN",
                                        reason=player.blacklist.reason,
                                        by=f"BLACKLIST: {player.blacklist.by}",
                                        steam_id_64=steam_id_64)
                try:
                    send_to_discord_audit(
                        f"`BLACKLIST` -> {dict_to_discord(dict(player=name, reason=player.blacklist.reason))}",
                        "BLACKLIST")
                except:
                    logger.error("Unable to send blacklist to audit log")
            except:
                send_to_discord_audit(
                    "Failed to apply ban on blacklisted players, please check the logs and report the error",
                    "ERROR")
예제 #3
0
def add_player_to_blacklist(steam_id_64, reason, name=None, by=None):
    # TODO save author of blacklist
    with enter_session() as sess:
        player = _get_set_player(sess, steam_id_64=steam_id_64, player_name=name)
        if not player:
            raise CommandFailedError(f"Player with steam id {steam_id_64} not found")

        if player.blacklist:
            if player.blacklist.is_blacklisted:
                logger.warning(
                    "Player %s was already blacklisted with %s, updating reason to %s",
                    str(player),
                    player.blacklist.reason,
                    reason,
                )
            player.blacklist.is_blacklisted = True
            player.blacklist.reason = reason
            player.blacklist.by = by
        else:
            logger.info("Player %s blacklisted for %s", str(player), reason)
            sess.add(
                BlacklistedPlayer(
                    steamid=player, is_blacklisted=True, reason=reason, by=by
                )
            )

        sess.commit()
예제 #4
0
def get_player_profile(steam_id_64, nb_sessions):
    with enter_session() as sess:
        player = sess.query(PlayerSteamID).filter(
            PlayerSteamID.steam_id_64 == steam_id_64).one_or_none()
        if player is None:
            return
        return player.to_dict(limit_sessions=nb_sessions)
예제 #5
0
def get_scoreboard_maps(request):
    data = _get_data(request)

    page_size = min(int(data.get("limit", 100)), 1000)
    page = max(1, int(data.get("page", 1)))
    server_number = data.get("server_number", os.getenv("SERVER_NUMBER"))

    with enter_session() as sess:
        query = (sess.query(Maps).filter(
            Maps.server_number == server_number).order_by(Maps.start.desc()))
        total = query.count()
        res = query.limit(page_size).offset((page - 1) * page_size).all()

        return api_response(
            result={
                "page":
                page,
                "page_size":
                page_size,
                "total":
                total,
                "maps": [
                    dict(
                        just_name=map_name(r.map_name),
                        long_name=LONG_HUMAN_MAP_NAMES.get(
                            r.map_name, r.map_name),
                        **r.to_dict(),
                    ) for r in res
                ],
            },
            failed=False,
            command="get_scoreboard_maps",
        )
예제 #6
0
def get_player_profile_by_id(id, nb_sessions):
    with enter_session() as sess:
        player = sess.query(PlayerSteamID).filter(
            PlayerSteamID.id == id).one_or_none()
        if player is None:
            return
        return player.to_dict(limit_sessions=nb_sessions)
예제 #7
0
    def get_players_stats_at_time(self, from_, until, server_number=None):
        server_numer = server_number or os.getenv('SERVER_NUMBER')
        with enter_session() as sess:
            rows = get_historical_logs_records(
                sess, from_=from_, till=until, time_sort="asc", server_filter=server_numer, limit=99999999
            )

            indexed_logs = {}
            players = []
            players_times = {}
            ids = set()
            for r in rows:
                log = r.compatible_dict()
                if player := log.get("player"):
                    self._set_start_end_times(player, players_times, log, from_)
                    indexed_logs.setdefault(player, []).append(log)
                    ids.add(log.get("player1_id"))
                    if steamid := log.get("steam_id_64_1"):
                        players.append(dict(name=player, steam_id_64=steamid))

                if player2 := log.get("player2"):
                    self._set_start_end_times(player2, players_times, log, from_)
                    indexed_logs.setdefault(player2, []).append(log)
                    ids.add(log.get("player2_id"))
                    if steamid2 := log.get("steam_id_64_2"):
                        players.append(dict(name=player2, steam_id_64=steamid2))
예제 #8
0
    def get_current_players_stats(self):
        players = self.rcon.get_players()
        if not players:
            logger.debug("No players")
            return {}

        players = [p for p in players if p.get("steam_id_64")]

        with enter_session() as sess:
            profiles_by_id = {
                profile.steam_id_64: profile
                for profile in _get_profiles(
                    sess, [p["steam_id_64"] for p in players], nb_sessions=1)
            }
            logger.info("%s players, %s profiles loaded", len(players),
                        len(profiles_by_id))
            oldest_session_seconds = self._get_player_session_time(
                max(players, key=self._get_player_session_time))
            logger.debug("Oldest session: %s", oldest_session_seconds)
            now = datetime.datetime.now()
            min_timestamp = (now - datetime.timedelta(
                seconds=oldest_session_seconds)).timestamp()
            logger.debug("Min timestamp: %s", min_timestamp)
            logs = get_recent_logs(min_timestamp=min_timestamp)

            logger.info("%s log lines to process", len(logs["logs"]))

            indexed_players = {p["name"]: p for p in players}
            indexed_logs = self._get_indexed_logs_by_player_for_session(
                now, indexed_players, reversed(logs["logs"]))

            return self.get_stats_by_player(indexed_logs, players,
                                            profiles_by_id)
예제 #9
0
def save_end_player_session(steam_id_64, timestamp):
    with enter_session() as sess:
        player = get_player(sess, steam_id_64)
        if not player:
            logger.error(
                "Can't record player session for %s, player not found", steam_id_64
            )
            return

        last_session = (
            sess.query(PlayerSession)
            .filter(PlayerSession.steamid == player)
            .order_by(PlayerSession.created.desc())
            .first()
        )

        if last_session.end:
            logger.warning(
                "Last session was already ended for %s. Creating a new one instead",
                steam_id_64,
            )
            last_session = PlayerSession(
                steamid=player,
            )
        last_session.end = datetime.datetime.fromtimestamp(timestamp)
        logger.info(
            "Recorded player %s session end at %s", steam_id_64, last_session.end
        )
        sess.commit()
예제 #10
0
def get_user_config(key, default=None):
    logger.debug("Getting user config for %s", key)
    with enter_session() as sess:
        res = _get_conf(sess, key)
        res = res.value if res else default
        logger.debug("User config for %s is %s", key, res)
        return res
예제 #11
0
def seed_default_config():
    with enter_session() as sess:
        AutoBroadcasts().seed_db(sess)
        StandardMessages().seed_db(sess)
        CameraConfig().seed_db(sess)
        AutoVoteKickConfig().seed_db(sess)
        sess.commit()
예제 #12
0
def enrich_db_users(chunk_size=100, update_from_days_old=30):
    from rcon.models import enter_session, SteamInfo, PlayerSteamID
    from sqlalchemy import or_

    max_age = datetime.datetime.utcnow() - datetime.timedelta(
        days=update_from_days_old)
    with enter_session() as sess:
        query = sess.query(PlayerSteamID).outerjoin(SteamInfo).filter(
            or_(PlayerSteamID.steaminfo == None, SteamInfo.updated <= max_age))

        pages = math.ceil(query.count() / chunk_size)
        for page in range(pages):
            by_ids = {p.steam_id_64: p for p in query.limit(chunk_size).all()}
            profiles = get_steam_profiles(list(by_ids.keys()))
            logger.info(
                "Updating steam profiles page %s of %s - result count (query) %s - result count (steam) %s",
                page + 1, pages, len(by_ids), len(profiles))
            if not by_ids:
                logger.warning("Empty query results")
                continue
            for p in profiles:
                player = by_ids.get(p['steamid'])
                if not player:
                    logger.warning("Unable to find player %s", p["steamid"])
                    continue
                #logger.debug("Saving info for %s: %s", player.steam_id_64, p)
                update_db_player_info(player=player, steam_profile=p)

            sess.commit()
            time.sleep(5)
예제 #13
0
def get_map_scoreboard(request):
    data = _get_data(request)
    error = None
    failed = False
    game = None

    try:
        map_id = int(data.get("map_id", None))
        with enter_session() as sess:
            game = sess.query(Maps).filter(Maps.id == map_id).one_or_none()
            #import ipdb; ipdb.set_trace()
            if not game:
                error = "No map for this ID"
                failed = True
            else:
                game = game.to_dict(with_stats=True)
    except Exception as e:
        game = None
        error = repr(e)
        failed = True

    return api_response(result=game,
                        error=error,
                        failed=failed,
                        command="get_map_scoreboard")
예제 #14
0
 def get_all_hook_types(as_dict=False):
     hooks = []
     with enter_session() as sess:
         for name in DiscordHookConfig.expected_hook_types:
             hooks.append(
                 asdict(DiscordHookConfig(for_type=name).get_hooks()))
         return hooks
예제 #15
0
def set_user_config(key, object_):
    with enter_session() as sess:
        conf = _get_conf(sess, key)
        if conf is None:
            _add_conf(sess, key, object_)
        else:
            conf.value = object_
        sess.commit()
예제 #16
0
def ban_if_has_vac_bans(rcon: RecordedRcon, steam_id_64, name):
    try:
        max_days_since_ban = int(MAX_DAYS_SINCE_BAN)
        max_game_bans = (
            float("inf")
            if int(MAX_GAME_BAN_THRESHOLD) <= 0
            else int(MAX_GAME_BAN_THRESHOLD)
        )
    except ValueError:  # No proper value is given
        logger.error(
            "Invalid value given for environment variable BAN_ON_VAC_HISTORY_DAYS or MAX_GAME_BAN_THRESHOLD"
        )
        return

    if max_days_since_ban <= 0:
        return  # Feature is disabled

    with enter_session() as sess:
        player = get_player(sess, steam_id_64)

        if not player:
            logger.error("Can't check VAC history, player not found %s", steam_id_64)
            return

        bans = get_player_bans(steam_id_64)
        if not bans or not isinstance(bans, dict):
            logger.warning(
                "Can't fetch Bans for player %s, received %s", steam_id_64, bans
            )
            # Player couldn't be fetched properly (logged by get_player_bans)
            return

        if should_ban(bans, max_game_bans, max_days_since_ban):
            reason = AUTO_BAN_REASON.format(
                DAYS_SINCE_LAST_BAN=bans.get("DaysSinceLastBan"),
                MAX_DAYS_SINCE_BAN=str(max_days_since_ban),
            )
            logger.info(
                "Player %s was banned due VAC history, last ban: %s days ago",
                str(player),
                bans.get("DaysSinceLastBan"),
            )
            rcon.do_perma_ban(player=name, reason=reason, by="VAC BOT")

            try:
                audit_params = dict(
                    player=name,
                    steam_id_64=player.steam_id_64,
                    reason=reason,
                    days_since_last_ban=bans.get("DaysSinceLastBan"),
                    vac_banned=bans.get("VACBanned"),
                    number_of_game_bans=bans.get("NumberOfGameBans"),
                )
                send_to_discord_audit(
                    f"`VAC/GAME BAN` -> {dict_to_discord(audit_params)}", "AUTOBAN"
                )
            except:
                logger.exception("Unable to send vac ban to audit log")
예제 #17
0
def set_user_config(key, object_):
    logger.debug("Setting user config for %s with %s", key, object_)
    with enter_session() as sess:
        conf = _get_conf(sess, key)
        if conf is None:
            _add_conf(sess, key, object_)
        else:
            conf.value = object_
        sess.commit()
예제 #18
0
def get_profiles(steam_ids, nb_sessions=0):
    with enter_session() as sess:
        players = (
            sess.query(PlayerSteamID)
            .filter(PlayerSteamID.steam_id_64.in_(steam_ids))
            .all()
        )

        return [p.to_dict(limit_sessions=nb_sessions) for p in players]
예제 #19
0
def save_player_action(rcon, action_type, player_name, by, reason=''):
    with enter_session() as sess:
        steam_id_64 = rcon.get_player_info(player_name)['steam_id_64']
        player = _get_set_player(sess, player_name, steam_id_64)
        sess.add(
            PlayersAction(action_type=action_type.upper(),
                          steamid=player,
                          reason=reason,
                          by=by))
예제 #20
0
    def unwatch(self):
        with enter_session() as sess:
            player = get_player(sess, self.steam_id_64)
            if not player:
                raise CommandFailedError(
                    "Can't remove player to wathlist, player not found")
            if player.watchlist:
                player.watchlist.is_watched = False

        return True
예제 #21
0
def _record_stats(map_info):
    stats = TimeWindowStats()

    start = datetime.datetime.utcfromtimestamp(map_info.get('start'))
    end = datetime.datetime.utcfromtimestamp(map_info.get('end'))

    if not start or not end:
        logger.error("Can't record stats, no time info for %s", map_info)
        return

    with enter_session() as sess:
        map = get_or_create_map(sess=sess,
                                start=start,
                                end=end,
                                server_number=os.getenv("SERVER_NUMBER"),
                                map_name=map_info["name"])
        player_stats = stats.get_players_stats_at_time(from_=start, until=end)
        for player, stats in player_stats.items():
            if steam_id_64 := stats.get("steam_id_64"):
                player_record = get_player(sess, steam_id_64=steam_id_64)
                if not player_record:
                    logger.error("Can't find DB record for %s", steam_id_64)
                    continue

                player_stats = dict(
                    playersteamid_id=player_record.id,
                    map_id=map.id,
                    name=stats.get("player"),
                    kills=stats.get("kills"),
                    kills_streak=stats.get("kills_streak"),
                    deaths=stats.get("deaths"),
                    deaths_without_kill_streak=stats.get(
                        "deaths_without_kill_streak"),
                    teamkills=stats.get("teamkills"),
                    teamkills_streak=stats.get("teamkills_streak"),
                    deaths_by_tk=stats.get("deaths_by_tk"),
                    deaths_by_tk_streak=stats.get("deaths_by_tk_streak"),
                    nb_vote_started=stats.get("nb_vote_started"),
                    nb_voted_yes=stats.get("nb_voted_yes"),
                    nb_voted_no=stats.get("nb_voted_no"),
                    time_seconds=stats.get("time_seconds"),
                    kills_per_minute=stats.get("kills_per_minute"),
                    deaths_per_minute=stats.get("deaths_per_minute"),
                    kill_death_ratio=stats.get("kill_death_ratio"),
                    longest_life_secs=stats.get("longest_life_secs"),
                    shortest_life_secs=stats.get("shortest_life_secs"),
                    weapons=stats.get("weapons"),
                    most_killed=stats.get("most_killed"),
                    death_by=stats.get("death_by"))
                logger.debug(f"Saving stats %s", player_stats)
                player_stat_record = PlayerStats(**player_stats)
                sess.add(player_stat_record)
            else:
                logger.error("Stat object does not contain a steam id: %s",
                             stats)
예제 #22
0
def remove_player_from_blacklist(steam_id_64):
    with enter_session() as sess:
        player = get_player(sess, steam_id_64)
        if not player:
            raise CommandFailedError(f"Player with steam id {steam_id_64} not found")

        if not player.blacklist:
            raise CommandFailedError(f"Player {player} was not blacklisted")

        player.blacklist.is_blacklisted = False
        sess.commit()
예제 #23
0
def save_player_action(
    rcon, action_type, player_name, by, reason="", steam_id_64=None, timestamp=None
):
    with enter_session() as sess:
        _steam_id_64 = steam_id_64 or rcon.get_player_info(player_name)["steam_id_64"]
        player = _get_set_player(sess, player_name, _steam_id_64, timestamp=timestamp)
        sess.add(
            PlayersAction(
                action_type=action_type.upper(), steamid=player, reason=reason, by=by
            )
        )
예제 #24
0
def remove_flag(flag_id):
    with enter_session() as sess:
        exits = sess.query(PlayerFlag).filter(
            PlayerFlag.id == int(flag_id)).one_or_none()
        if not exits:
            logger.warning("Flag does not exists")
            raise CommandFailedError("Flag does not exists")
        player = exits.steamid.to_dict()
        flag = exits.to_dict()
        sess.delete(exits)
        sess.commit()

    return player, flag
예제 #25
0
def seed_default_config():
    logger.info('Seeding DB')
    try:
        with enter_session() as sess:
            AutoBroadcasts().seed_db(sess)
            StandardMessages().seed_db(sess)
            CameraConfig().seed_db(sess)
            AutoVoteKickConfig().seed_db(sess)
            VoteMapConfig().seed_db(sess)
            RealVipConfig().seed_db(sess)
            AutoSettingsConfig().seed_db(sess)
            sess.commit()
    except Exception as e:
        logger.exception('Failed to seed DB')
예제 #26
0
def get_players_by_appearance(page=1, page_size=500, last_seen_from: datetime.datetime = None, last_seen_till: datetime.datetime = None, player_name = None, blacklisted = None, steam_id_64 = None):
    if page <= 0:
        raise ValueError('page needs to be >= 1')
    if page_size <= 0:
        raise ValueError('page_size needs to be >= 1')

    with enter_session() as sess:
        sub = sess.query(
            PlayerSession.playersteamid_id,
            func.min(func.coalesce(PlayerSession.start,
                                   PlayerSession.created)).label('first'),
            func.max(func.coalesce(PlayerSession.end,
                                   PlayerSession.created)).label('last')
        ).group_by(PlayerSession.playersteamid_id).subquery()
        query = sess.query(PlayerSteamID, sub.c.first, sub.c.last).outerjoin(
            sub, sub.c.playersteamid_id == PlayerSteamID.id)

        if steam_id_64:
            query = query.filter(PlayerSteamID.steam_id_64.ilike("%{}%".format(steam_id_64)))
        if player_name:
            query = query.join(PlayerSteamID.names).filter(PlayerName.name.ilike("%{}%".format(player_name))).options(contains_eager(PlayerSteamID.names))
        if blacklisted is True:
            query = query.join(PlayerSteamID.blacklist).filter(BlacklistedPlayer.is_blacklisted == True).options(contains_eager(PlayerSteamID.blacklist))
        if last_seen_from:
            query = query.filter(sub.c.last >= last_seen_from)
        if last_seen_till:
            query = query.filter(sub.c.last <= last_seen_till)

        total = query.count()
        page = min(max(math.ceil(total / page_size), 1), page) 
        players = query.order_by(sub.c.last.desc()).limit(
            page_size).offset((page - 1) * page_size).all()
       
        return {
            'total': total,
            'players': [
                {
                    'steam_id_64': p[0].steam_id_64,
                    'names': [n.name for n in p[0].names],
                    'first_seen_timestamp_ms': int(p[1].timestamp() * 1000) if p[1] else None,
                    'last_seen_timestamp_ms': int(p[2].timestamp() * 1000) if p[1] else None,
                    'penalty_count': p[0].get_penalty_count(),
                    'blacklisted': p[0].blacklist.is_blacklisted if p[0].blacklist else False
                }
                for p in players
            ],
            'page': page,
            'page_size': page_size
        }
예제 #27
0
def save_start_player_session(steam_id_64, timestamp):
    with enter_session() as sess:
        player = get_player(sess, steam_id_64)
        if not player:
            logger.error(
                "Can't record player session for %s, player not found",
                steam_id_64)
            return

        sess.add(
            PlayerSession(steamid=player,
                          start=datetime.datetime.fromtimestamp(timestamp)))
        logger.info("Recorded player %s session start at %s", steam_id_64,
                    datetime.datetime.fromtimestamp(timestamp))
        sess.commit()
예제 #28
0
 def watch(self, reason, comment, player_name=""):
     with enter_session() as sess:
         player = _get_set_player(
             sess, player_name=player_name, steam_id_64=self.steam_id_64
         )
         if player.watchlist:
             player.watchlist.is_watched = True
         else:
             watch = WatchList(
                 steamid=player, comment=comment, reason=reason, is_watched=True
             )
             sess.add(watch)
             sess.commit()
             
     return True
예제 #29
0
    def get_players_stats_at_time(self, from_, until, server_number=None):
        server_number = server_number or os.getenv("SERVER_NUMBER")
        with enter_session() as sess:
            # Get the logs from the database for the given time range
            rows = get_historical_logs_records(
                sess,
                from_=from_,
                till=until,
                time_sort="asc",
                server_filter=server_number,
                limit=99999999,
            )

            return self._get_players_stats_for_logs(
                [row.compatible_dict() for row in rows], from_, until)
예제 #30
0
def add_flag_to_player(steam_id_64, flag, comment=None, player_name=None):
    with enter_session() as sess:
        player = _get_set_player(sess, player_name=player_name, steam_id_64=steam_id_64)
        exits = (
            sess.query(PlayerFlag)
            .filter(PlayerFlag.playersteamid_id == player.id, PlayerFlag.flag == flag)
            .all()
        )
        if exits:
            logger.warning("Flag already exists")
            raise CommandFailedError("Flag already exists")
        new = PlayerFlag(flag=flag, comment=comment, steamid=player)
        sess.add(new)
        sess.commit()
        res = player.to_dict()
        return res, new.to_dict()