diff --git a/common/__init__.py b/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/common/init_logging.py b/common/init_logging.py new file mode 100644 index 0000000..0c3da3f --- /dev/null +++ b/common/init_logging.py @@ -0,0 +1,53 @@ +import logging +import os + + +class CustomFormatter(logging.Formatter): + grey = "\x1b[38;5;240m" + white = "\x1b[38;5;15m" + yellow = "\x1b[33;20m" + green = "\x1b[32;20m" + red = "\x1b[31;20m" + bold_red = "\x1b[31;1m" + reset = "\x1b[0m" + format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + error_format = "%(asctime)s - %(name)s - %(levelname)s - (%(filename)s:%(lineno)d) - %(message)s" + + FORMATS = { + logging.DEBUG: grey + format + reset, + logging.INFO: green + format + reset, + logging.WARNING: yellow + error_format + reset, + logging.ERROR: red + error_format + reset, + logging.CRITICAL: bold_red + error_format + reset, + } + + def format(self, record): + log_fmt = self.FORMATS.get(record.levelno) + formatter = logging.Formatter(log_fmt) + return formatter.format(record) + + +def setup_logger(name): + """ + Set up a logger for the module + :param name: The name of the module + :return: The logger + """ + # Set up logging + logger = logging.getLogger(name) + logger.setLevel(os.environ.get("LOG_LEVEL", "DEBUG")) + + # If the logger already has handlers, we don't need to add them again. + if logger.handlers: + return logger + + # create console handler with a higher log level + ch = logging.StreamHandler() + ch.setLevel(logging.DEBUG) + + # Check if running in AWS Lambda + if os.environ.get("AWS_EXECUTION_ENV") is None: + ch.setFormatter(CustomFormatter()) + logger.addHandler(ch) + + return logger diff --git a/main.py b/main.py index 880cd2f..498bbfb 100644 --- a/main.py +++ b/main.py @@ -8,13 +8,19 @@ import boto3 import requests import ts3 + from sqlalchemy import MetaData from sqlalchemy import create_engine from sqlalchemy import select, insert, update +from common.init_logging import setup_logger + # BEFORE YOU JUDGE THIS SCRIPT... I wrote it while drinking, i swear.... # Test Comment Here -# Total hours wasted on this script: 9 (as of 2023-06-11) +# Total hours wasted on this script: 10 (as of 2023-12-10) + +# Get the logger +logger = setup_logger(__name__) # Get DEBUG environment variable DEBUG = os.environ.get("DEBUG", False) @@ -45,7 +51,6 @@ ts_MessageLog = meta.tables["ts_message_log"] - def incrementUpdateCount(): global updateCount updateCount += 1 @@ -64,8 +69,7 @@ def timeout_handler(signum, frame): raise TimeoutException("Timeout handler triggered!") -signal.signal(signal.SIGALRM, timeout_handler) - +# signal.signal(signal.SIGALRM, timeout_handler) zny_web_instance = "https://nyartcc.org" @@ -90,71 +94,88 @@ def updatePos(ts3conn, conn): # Dictionary of all the users currently connected to the TS3 server trackedUsers = {} + # Get the list of all online controllers from the ZNY website positionInfo = requests.get(zny_web_instance + '/api/positions/online').json() + + # Parse the list of online controllers for position in positionInfo['data']: + + # If the position is not in the dictionary of online controllers, add it if position['identifier'] not in onlineController: onlineController[position['identifier']] = [] + + # Get the user info for the controller from the ZNY website userInfo = requests.get( - zny_web_instance+ '/api/teamspeak/userIdentity?cid={}'.format(position['cid'])).json() + zny_web_instance + '/api/teamspeak/userIdentity?cid={}'.format(position['cid'])).json() + + # Add the user to the position in the dictionary for that position for uid in userInfo: onlineController[position['identifier']].append(uid) + # Connect to the database conn = engine.connect() + + # Get the list of all positions from the database positionsAll = conn.execute(select([table])).fetchall() + + # Add all positions to the list of positions for position in positionsAll: positions.append(position["identifier"]) + + # Get the list of all TS3 groups resp = ts3conn.servergrouplist() + + # Add all TS3 groups to the dictionary of groups for group in resp: groups[group["name"]] = int(group["sgid"]) for group in groups: if group in positions and group not in onlineController: try: - print('del ' + group) + logger.info(f"Removing {group} from TS3 server group") ts3conn.servergroupdel(sgid=groups[group], force=1) except: pass for position in onlineController: trackedUsers[position] = [] - print(trackedUsers[position]) + logger.info(f"Currently tracked users: {trackedUsers[position]}") time.sleep(.1) - # print(position) + if position not in groups: resp = ts3conn.servergroupcopy( ssgid=sourceGroup, tsgid=0, name=position, type_=1 ) groups[position] = int(resp.parsed[0]["sgid"]) for controller in onlineController[position]: - print(controller) + logger.info(f"Current controller info: {controller}") resp = ts3conn.clientgetdbidfromuid(cluid=controller) dibUser = resp.parsed[0]["cldbid"] try: time.sleep(.1) - print(dibUser) - print("add " + controller + " to " + position) + logger.info(f"dibUser: {dibUser}") + logger.info(f"Add {controller} to {position}") ts3conn.servergroupaddclient( sgid=groups[position], cldbid=dibUser ) incrementUpdateCount() except: - print("FAILED add " + controller + " to " + position) + logger.error(f"FAILED to add {controller} to {position}") incrementFailCount() finally: trackedUsers[position].append(dibUser) resp = ts3conn.servergroupclientlist(sgid=groups[position]) - # print('CHECK REMOVE') + for user in resp.parsed: - print(user) - # print(resp.parsed[0]['name'][-4:]) - # print(onlineController[position]) + logger.info(f"USER: {user}") + if user["cldbid"] not in trackedUsers[position]: ts3conn.servergroupdelclient( sgid=groups[position], cldbid=user["cldbid"] ) incrementUpdateCount() - print(groups) + logger.info(f"Removed {user['cldbid']} from {position}") def updateUsers(ts3conn, conn): @@ -166,9 +187,14 @@ def updateUsers(ts3conn, conn): """ conn = conn - def sendMessageReg(client_unique_identifier, clid): + """ + Send a message to a user to register on the ZNY website. + :param client_unique_identifier: The client unique identifier from TS3. + :param clid: The client ID from TS3. + :return: + """ # give UID send mmessage to user (DONT RESEND FOR X TIME) # This works. Only issue is you Laraval cant accept a slash in Unicode and treats it as a normal slash in the url. Instead we need to pass with a get param or within a post. I am down for either, Post may be easier as it allows it to forward through. ts3conn.sendtextmessage( @@ -178,19 +204,30 @@ def sendMessageReg(client_unique_identifier, clid): urllib.parse.quote_plus(client_unique_identifier) ), ) - # print('send message') - return + logger.debug(f"Sent welcome message to {clid}") + + return True def sendBadUsername(): + """ + Send a message to a user to change their username. + :return: + """ # give UID send mmessage to user (DONT RESEND FOR X TIME) pass # get all users in TS and return as resp # getAllActiveUsers select from TS users link to users via CID. Allows for multiple Idents - # get all users in TS and retrun as resp + # get all users in TS and return as resp # getAllActiveUsers select from TS users link to users via CID. Allows for multiple Idents def checkLastMessage(uid, messageType): + """ + Check the last message time for a user + :param uid: + :param messageType: + :return: + """ dbuserInfo = conn.execute( select([ts_MessageLog]).where(ts_MessageLog.c.uid == uid) ).fetchone() @@ -218,7 +255,7 @@ def updateLastMessage(uid, messageType, time): .where(ts_MessageLog.c.uid == uid) .values(time=time) ) - return + return True resp = ts3conn.clientlist() @@ -231,14 +268,13 @@ def updateLastMessage(uid, messageType, time): groupsTracked = artccInfo['data']['tagsTracked'] for user in resp.parsed: - print(user) + logger.info(f"Variable USER is currently: {user}") if user["client_database_id"] == 1: pass userInfo = ts3conn.clientinfo(clid=user["clid"]) - # print( userInfo.parsed[0]['client_type']) + if userInfo.parsed[0]["client_type"] != "0": pass - # checkDB for user in by user prim key of UID which will link CID to user elif userInfo.parsed[0]["client_unique_identifier"] in allTeamspeakIds: userInfoWebsite = requests.get( @@ -251,10 +287,35 @@ def updateLastMessage(uid, messageType, time): if '11' in userGroupsWebsite: userGroupsWebsite.remove('11') - # Yeah this shit broke the bot. SORRY + # If user is a board member + if userInfoWebsite['data']['isBoardMember']: + # Don't assign the "NY Controller" tag. + logger.info(f"Found a board member!") + logger.info(f"userInfoWebsite['data'] is currently: {userInfoWebsite['data']}") + + if '11' in userGroupsWebsite: + logger.info(f"User has id 11 in list. Removing it.") + try: + userGroupsWebsite.remove('11') + except error as e: + logger.info(f"Failed to remove tag 11. Error: {e}") + logger.info("Removed id 11 successfully!") + + # Add the 'Board Member' tag + userGroupsWebsite.append('17401') + logger.info(f"Sucessfully added id 17401 to user {userInfoWebsite['data']['cid']}") + + # Ignore server groups for 'KM' + # Check if user is KM and if he has the 'I1' tag if so, remove it and add C3. if '73' in userGroupsWebsite and userInfoWebsite['data']['cid'] == 908962: - userGroupsWebsite.remove('73') + logger.info(f"Found user KM and he has id 73. He's a fake I1! Remove it!") + try: + userGroupsWebsite.remove('73') + except error as e: + logger.info(f"Failed to remove group 73. Error: {e}") + userGroupsWebsite.append('72') + logger.info(f"Added group 72 instead.") userAddGroups = list(set(userGroupsWebsite) - set(userGroupsTracked)) userRemoveGroups = list(set(userGroupsTracked) - set(userGroupsWebsite)) @@ -290,8 +351,8 @@ def lambda_handler(event, context): :param context: :return: """ - #profiler = cProfile.Profile() - #profiler.enable() + # profiler = cProfile.Profile() + # profiler.enable() # Get the IP address of the ZNY-Website-Production EC2 instance # zny_web_instance_ip = ZNY_WEB_SERVER_IP @@ -304,9 +365,6 @@ def lambda_handler(event, context): updatePos(ts3conn, conn) updateUsers(ts3conn, conn) - #profiler.disable() - #profiler.print_stats(sort='time') - return { "statusCode": 200, "headers": {},