from datetime import datetime from django.db import connection from django.db.models.query import RawQuerySet from django.http import HttpRequest from django_coreprotect.models import CoWorld, GUIResult from django_coreprotect.utils import safe_int, checkbox, time_to_form class GUIForm: def __init__(self): self.block_break = False self.block_place = False self.chat = False self.chest_use = False self.command = False self.interact = False self.login_logout = False self.sign_place = False self.worlds = [] self.ignore_environment = False self.oldest_first = False self.page = "" self.page_size = "" self.start = "" self.players = "" self.x = "" self.y = "" self.z = "" self.radius = "" self.blocks = "" self.date_from = "" self.date_to = "" def gui_data(request: HttpRequest) -> GUIForm: request_data = request.GET form = GUIForm() worlds = CoWorld.objects.all() # Actions form.block_break = checkbox(request_data["block_break"]) if "block_break" in request_data else False form.block_place = checkbox(request_data["block_place"]) if "block_place" in request_data else False form.chat = checkbox(request_data["chat"]) if "chat" in request_data else False form.chest_use = checkbox(request_data["chest_use"]) if "chest_use" in request_data else False form.command = checkbox(request_data["command"]) if "command" in request_data else False form.interact = checkbox(request_data["interact"]) if "interact" in request_data else False form.login_logout = checkbox(request_data["login_logout"]) if "login_logout" in request_data else False form.sign_place = checkbox(request_data["sign_place"]) if "sign_place" in request_data else False # Permissions if not request.user.has_perm("django_coreprotect.gui_extra"): form.chat = False form.command = False # Worlds request_worlds = request_data.getlist("world") for world in worlds: world_id = f"world_{world.id}" w = { "id": str(world.id), "world_id": world_id, "checked": True if str(world.id) in request_worlds else False, "name": world.world } form.worlds.append(w) # Options form.ignore_environment = checkbox(request_data["ignore_environment"]) if "ignore_environment" in request_data else False form.oldest_first = checkbox(request_data["oldest_first"]) if "oldest_first" in request_data else False # Limit Results form.page = request_data["page"] if "page" in request_data else "0" form.page_size = request_data["page_size"] if "page_size" in request_data else "20" if safe_int(form.page_size) == 0 or safe_int(form.page_size) > 1000: form.page_size = "1000" form.start = (safe_int(form.page) * safe_int(form.page_size)) # Players form.players = request_data["players"] if "players" in request_data else "" # Coordinates form.x = request_data["x"] if "x" in request_data else "" form.y = request_data["y"] if "y" in request_data else "" form.z = request_data["z"] if "z" in request_data else "" form.radius = request_data["radius"] if "radius" in request_data else "" # Blocks form.blocks = request_data["blocks"] if "blocks" in request_data else "" # Date and Time form.date_from = time_to_form(request_data["date_from"]) if "date_from" in request_data else "" if form.date_from: form.date_from = form.date_from.timestamp() form.date_to = time_to_form(request_data["date_to"]) if "date_to" in request_data else "" if form.date_to: form.date_to = form.date_to.timestamp() return form def gui_results(form: GUIForm) -> RawQuerySet: queries = [] ignore_environment = " AND cu.user NOT LIKE '#%%' " if form.ignore_environment else "" oldest_first = " ASC " if form.oldest_first else " DESC " coords = [] radius = form.radius if form.radius else "0" if form.x: coords.append(f" x BETWEEN {form.x} - {radius} AND {form.x} + {radius}") if form.y: coords.append(f" y BETWEEN {form.y} - {radius} AND {form.y} + {radius}") if form.z: coords.append(f" z BETWEEN {form.z} - {radius} AND {form.z} + {radius}") coords_clause = "" if coords: clause = " AND ".join(coords) coords_clause = f" AND ({clause})" players = [] players_clause = "" if form.players: for player in form.players.split(","): players.append(player.strip()) clause = " OR ".join([f"cu.user LIKE '{p}%%'" for p in players]) players_clause = f" AND ({clause})" blocks = [] blocks_clause = "" chat_clause = "" command_clause = "" if form.blocks: for block in form.blocks.split(","): blocks.append(block.strip()) clause = " OR ".join([f"cmm.material LIKE 'minecraft:{b}%%'" for b in blocks]) blocks_clause = f" AND ({clause})" clause = " OR ".join([f"cc.message LIKE '%%{b}%%'" for b in blocks]) chat_clause = f" AND ({clause})" clause = " OR ".join([f"cc.message LIKE '%%{b}%%'" for b in blocks]) command_clause = f" AND ({clause})" worlds_clause = "" worlds = [world["id"] for world in form.worlds if world["checked"]] if len(worlds): clause = ",".join(worlds) worlds_clause = f" AND cw.rowid IN ({clause})" time_clause = "" if form.date_from or form.date_to: df, dt = form.date_from, form.date_to if form.date_from and not form.date_to: dt = datetime.now().timestamp() if form.date_to and not form.date_from: df = datetime.now().timestamp() time_clause = f" GROUP BY unix HAVING unix BETWEEN {df} AND {dt} " # Block Break, Block Place, and Interact block_actions = [] if form.block_break: block_actions.append("0") if form.block_place: block_actions.append("1") if form.interact: block_actions.append("2") if len(block_actions): queries.append(f'''SELECT 0 AS id, "block" AS type, cb.time AS unix, cu.user AS player, cb.action, cmm.material AS data, cb.x, cb.y, cb.z, cw.world FROM co_block cb JOIN co_user cu ON cb.user = cu.rowid JOIN co_material_map cmm ON cb.type = cmm.rowid JOIN co_world cw ON cb.wid = cw.rowid WHERE cb.action IN ({",".join(block_actions)}) {ignore_environment} {players_clause} {coords_clause} {blocks_clause} {worlds_clause} {time_clause} ''') # Chat if form.chat: queries.append(f'''SELECT 0 AS id, "chat" AS type, cc.time AS unix, cu.user AS player, "" AS action, cc.message AS data, "" AS x, "" AS y, "" AS z, "" AS world FROM co_chat cc JOIN co_user cu ON cc.user = cu.rowid WHERE 1 = 1 {players_clause} {chat_clause} {time_clause} ''') # Chest Use if form.chest_use: concat = 'CONCAT(cc.amount, " ", cmm.material)' if connection.vendor == "sqlite": concat = 'cc.amount || " " || cmm.material' queries.append(f'''SELECT 0 AS id, "container" AS type, cc.time AS unix, cu.user AS player, cc.action, {concat} AS data, cc.x, cc.y, cc.z, cw.world FROM co_container cc JOIN co_user cu ON cc.user = cu.rowid JOIN co_material_map cmm ON cc.type = cmm.rowid JOIN co_world cw ON cc.wid = cw.rowid WHERE 1 = 1 {worlds_clause} {players_clause} {coords_clause} {blocks_clause} {time_clause} ''') # Commands if form.command: queries.append(f'''SELECT 0 AS id, "command" AS type, cc.time AS unix, cu.user AS player, "" AS action, cc.message AS data, "" AS x, "" AS y, "" AS z, "" AS world FROM co_command cc JOIN co_user cu ON cc.user = cu.rowid WHERE 1 = 1 {players_clause} {command_clause} {coords_clause} {time_clause} ''') # Login/Logout if form.login_logout: queries.append(f'''SELECT 0 AS id, "session" AS type, cs.time AS unix, cu.user AS player, cs.action, "" AS data, cs.x, cs.y, cs.z, cw.world FROM co_session cs JOIN co_user cu ON cs.user = cu.rowid JOIN co_world cw ON cs.wid = cw.rowid WHERE 1 = 1 {worlds_clause} {players_clause} {coords_clause} {time_clause} ''') # Sign Place if form.sign_place: queries.append(f'''SELECT 0 AS id, "sign" AS type, cs.time AS unix, cu.user AS player, "" AS action, cs.line_1 || "|" || cs.line_2 || "|" || cs.line_3 || "|" || cs.line_4 AS data, cs.x, cs.y, cs.z, cw.world FROM co_sign cs JOIN co_user cu ON cs.user = cu.rowid JOIN co_world cw ON cs.wid = cw.rowid WHERE 1 = 1 {worlds_clause} {players_clause} {coords_clause} {time_clause} ''') query = " UNION ALL ".join(queries) if query: query += f" ORDER BY unix {oldest_first} LIMIT {form.start}, {form.page_size}" return GUIResult.objects.raw(query) return GUIResult.objects.none()