diff --git a/forms.py b/forms.py new file mode 100644 index 0000000..5cbd740 --- /dev/null +++ b/forms.py @@ -0,0 +1,233 @@ +from django_coreprotect.models import * + + +class Form: + + 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.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 checkbox(value): + return True if value == "on" else False + + +def safe_int(value): + try: + return int(value) + except: + return 0 + + +def form_data(request): + request_data = request.GET + form = Form() + 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 = "world_{}".format(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 + + # 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 = request_data["date_from"] if "date_from" in request_data else "" + form.date_to = request_data["date_to"] if "date_to" in request_data else "" + + return form + + +def result_data(form): + queries = [] + ignore_environment = " AND player NOT LIKE '#%' " if form.ignore_environment else "" + + coords = [] + radius = form.radius if form.radius else "0" + if form.x: + coords.append(" AND x BETWEEN {0} - {1} AND {0} + {1}".format(form.x, radius)) + if form.y: + coords.append(" AND y BETWEEN {0} - {1} AND {0} + {1}".format(form.y, radius)) + if form.z: + coords.append(" AND z BETWEEN {0} - {1} AND {0} + {1}".format(form.z, radius)) + coords_clause = " AND ".join(coords) + + players = [] + players_clause = "" + if form.players: + for player in form.players.split(","): + players.append(player.strip()) + players_clause = " AND ({})".format(" OR ".join(["player LIKE '%{}%'".format(p) for p in players])) + + worlds_clause = "" + worlds = [world["id"] for world in form.worlds if world["checked"]] + if len(worlds): + worlds_clause = " AND cw.id IN ({})".format(",".join(worlds)) + + 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 = " AND unix BETWEEN {} AND {} ".format(df, 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('''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.id + JOIN co_material_map cmm ON cb.type = cmm.id + JOIN co_world cw ON cb.wid = cw.id + WHERE cb.action IN ({action}) + {ignore_environment} + {players} + {coords} + {worlds} + {time} + '''.format(action=",".join(block_actions), ignore_environment=ignore_environment, players=players_clause, + coords=coords_clause, worlds=worlds_clause, time=time_clause)) + + # Chat + if form.chat: + queries.append('''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.id + WHERE 1 = 1 + {players} + {time} + '''.format(players=players_clause, time=time_clause)) + + # Chest Use + if form.chest_use: + queries.append('''SELECT + 0 AS id, "container" AS type, cc.time AS unix, cu.user AS player, cc.action, cc.amount || " " || cmm.material AS data, cc.x, cc.y, cc.z, cw.world + FROM co_container cc + JOIN co_user cu ON cc.user = cu.id + JOIN co_material_map cmm ON cc.type = cmm.id + JOIN co_world cw ON cc.wid = cw.id + WHERE 1 = 1 + {worlds} + {players} + {coords} + {time} + '''.format(worlds=worlds_clause, players=players_clause, coords=coords_clause, time=time_clause)) + + # Commands + if form.command: + queries.append('''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.id + WHERE 1 = 1 + {players} + {coords} + {time} + '''.format(players=players_clause, coords=coords_clause, time=time_clause)) + + # Login/Logout + if form.login_logout: + queries.append('''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.id + JOIN co_world cw ON cs.wid = cw.id + WHERE 1 = 1 + {worlds} + {players} + {coords} + {time} + '''.format(worlds=worlds_clause, players=players_clause, coords=coords_clause, time=time_clause)) + + # Sign Place + if form.sign_place: + queries.append('''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.id + JOIN co_world cw ON cs.wid = cw.id + WHERE 1 = 1 + {worlds} + {players} + {coords} + {time} + '''.format(worlds=worlds_clause, players=players_clause, coords=coords_clause, time=time_clause)) + + query = " UNION ".join(queries) + if query: + query += " ORDER BY unix DESC LIMIT {}, {}".format(form.start, form.page_size) + print(query) + if query: + return CoResult.objects.raw(query) + return [] \ No newline at end of file diff --git a/migrations/0001_initial.py b/migrations/0001_initial.py new file mode 100644 index 0000000..a90384b --- /dev/null +++ b/migrations/0001_initial.py @@ -0,0 +1,322 @@ +# Generated by Django 2.2.3 on 2019-08-16 03:39 + +import django.contrib.auth.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0011_update_proxy_permissions'), + ] + + operations = [ + migrations.CreateModel( + name='CoArtMap', + fields=[ + ('id', models.IntegerField(primary_key=True, serialize=False)), + ('art', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Art Map', + 'verbose_name_plural': 'Art Maps', + 'db_table': 'co_art_map', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoBlock', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.IntegerField(blank=True, null=True)), + ('user', models.IntegerField(blank=True, null=True)), + ('wid', models.IntegerField(blank=True, null=True)), + ('x', models.IntegerField(blank=True, null=True)), + ('y', models.IntegerField(blank=True, null=True)), + ('z', models.IntegerField(blank=True, null=True)), + ('type', models.IntegerField(blank=True, null=True)), + ('data', models.IntegerField(blank=True, null=True)), + ('meta', models.BinaryField(blank=True, null=True)), + ('blockdata', models.BinaryField(blank=True, null=True)), + ('action', models.IntegerField(blank=True, null=True)), + ('rolled_back', models.IntegerField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Block', + 'verbose_name_plural': 'Blocks', + 'db_table': 'co_block', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoBlockdataMap', + fields=[ + ('id', models.IntegerField(primary_key=True, serialize=False)), + ('data', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'BlockData Map', + 'verbose_name_plural': 'BlockData Maps', + 'db_table': 'co_blockdata_map', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoChat', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.IntegerField(blank=True, null=True)), + ('user', models.IntegerField(blank=True, null=True)), + ('message', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Chat Message', + 'verbose_name_plural': 'Chat Messages', + 'db_table': 'co_chat', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoCommand', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.IntegerField(blank=True, null=True)), + ('user', models.IntegerField(blank=True, null=True)), + ('message', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Command', + 'verbose_name_plural': 'Commands', + 'db_table': 'co_command', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoContainer', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.IntegerField(blank=True, null=True)), + ('user', models.IntegerField(blank=True, null=True)), + ('wid', models.IntegerField(blank=True, null=True)), + ('x', models.IntegerField(blank=True, null=True)), + ('y', models.IntegerField(blank=True, null=True)), + ('z', models.IntegerField(blank=True, null=True)), + ('type', models.IntegerField(blank=True, null=True)), + ('data', models.IntegerField(blank=True, null=True)), + ('amount', models.IntegerField(blank=True, null=True)), + ('metadata', models.BinaryField(blank=True, null=True)), + ('action', models.IntegerField(blank=True, null=True)), + ('rolled_back', models.IntegerField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Container Transaction', + 'verbose_name_plural': 'Container Transactions', + 'db_table': 'co_container', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoDatabaseLock', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('status', models.IntegerField(blank=True, null=True)), + ('time', models.IntegerField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Database Lock', + 'verbose_name_plural': 'Database Locks', + 'db_table': 'co_database_lock', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoEntity', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.IntegerField(blank=True, null=True)), + ('data', models.BinaryField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Entity', + 'verbose_name_plural': 'Entities', + 'db_table': 'co_entity', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoEntityMap', + fields=[ + ('id', models.IntegerField(primary_key=True, serialize=False)), + ('entity', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Entity Mapping', + 'verbose_name_plural': 'Entity Mappings', + 'db_table': 'co_entity_map', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoMaterialMap', + fields=[ + ('id', models.IntegerField(primary_key=True, serialize=False)), + ('material', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Material Mapping', + 'verbose_name_plural': 'Material Mappings', + 'db_table': 'co_material_map', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoResult', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('type', models.TextField()), + ('unix', models.TextField()), + ('player', models.TextField()), + ('action', models.TextField()), + ('data', models.TextField()), + ('x', models.TextField()), + ('y', models.TextField()), + ('z', models.TextField()), + ('world', models.TextField()), + ], + options={ + 'verbose_name': 'Result', + 'verbose_name_plural': 'Results', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoSession', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.IntegerField(blank=True, null=True)), + ('user', models.IntegerField(blank=True, null=True)), + ('wid', models.IntegerField(blank=True, null=True)), + ('x', models.IntegerField(blank=True, null=True)), + ('y', models.IntegerField(blank=True, null=True)), + ('z', models.IntegerField(blank=True, null=True)), + ('action', models.IntegerField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Session', + 'verbose_name_plural': 'Sessions', + 'db_table': 'co_session', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoSign', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.IntegerField(blank=True, null=True)), + ('user', models.IntegerField(blank=True, null=True)), + ('wid', models.IntegerField(blank=True, null=True)), + ('x', models.IntegerField(blank=True, null=True)), + ('y', models.IntegerField(blank=True, null=True)), + ('z', models.IntegerField(blank=True, null=True)), + ('color', models.IntegerField(blank=True, null=True)), + ('line_1', models.TextField(blank=True, null=True)), + ('line_2', models.TextField(blank=True, null=True)), + ('line_3', models.TextField(blank=True, null=True)), + ('line_4', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Sign', + 'verbose_name_plural': 'Signs', + 'db_table': 'co_sign', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoSkull', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.IntegerField(blank=True, null=True)), + ('owner', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Skull', + 'verbose_name_plural': 'Skulls', + 'db_table': 'co_skull', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoUser', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.IntegerField(blank=True, null=True)), + ('user', models.TextField(blank=True, null=True)), + ('uuid', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'User', + 'verbose_name_plural': 'Users', + 'db_table': 'co_user', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoUsernameLog', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.IntegerField(blank=True, null=True)), + ('uuid', models.TextField(blank=True, null=True)), + ('user', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Username', + 'verbose_name_plural': 'Usernames', + 'db_table': 'co_username_log', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoVersion', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time', models.IntegerField(blank=True, null=True)), + ('version', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Version', + 'verbose_name_plural': 'Versions', + 'db_table': 'co_version', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoWorld', + fields=[ + ('id', models.IntegerField(primary_key=True, serialize=False)), + ('world', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'World', + 'verbose_name_plural': 'Worlds', + 'db_table': 'co_world', + 'managed': False, + }, + ), + migrations.CreateModel( + name='CoreProtectUser', + fields=[ + ], + options={ + 'permissions': (('gui', 'Can use CoreProtect GUI'), ('gui_extra', 'Can search Chat/Commands'), ('activity', 'Can use CoreProtect Activity Monitor')), + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('auth.user',), + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + ] diff --git a/models.py b/models.py index 5a3cbee..699dd3a 100644 --- a/models.py +++ b/models.py @@ -8,9 +8,9 @@ class CoreProtectUser(User): class Meta: proxy = True permissions = ( - ('coreprotect_base', 'Can use CoreProtect GUI'), - ('coreprotect_extra', 'Can search Chat/Commands'), - ('coreprotect_activity', 'Can use CoreProtect Activity Monitor'), + ('gui', 'Can use CoreProtect GUI'), + ('gui_extra', 'Can search Chat/Commands'), + ('activity', 'Can use CoreProtect Activity Monitor'), ) diff --git a/templates/coreprotect/coreprotect.html b/templates/coreprotect/coreprotect.html index 01d3ca1..49bc6ea 100644 --- a/templates/coreprotect/coreprotect.html +++ b/templates/coreprotect/coreprotect.html @@ -38,7 +38,7 @@