Half SQL completed

Signed-off-by: Etzelia <etzelia@hotmail.com>
develop
Etzelia 2019-08-14 16:56:05 -05:00
parent e41e5fe862
commit 0c0a9a0a0a
No known key found for this signature in database
GPG Key ID: 3CAEB74806C4ADE5
6 changed files with 259 additions and 40 deletions

View File

@ -1,5 +1,6 @@
from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
class CoreProtectUser(User):
@ -287,3 +288,43 @@ class CoWorld(models.Model):
def __str__(self):
return self.world
class CoResult(models.Model):
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()
@property
def display_time(self):
dt = datetime.fromtimestamp(float(self.unix))
return dt.strftime("%b %d, %Y at %I:%M:%S %p")
@property
def display_action(self):
if self.type == "block":
return "Block Break" if self.action == 0 else "Block Place" if self.action == 1 else "Interact/Used"
if self.type == "chat":
return "Chat"
if self.type == "command":
return "Command"
if self.type == "container":
return "Took from Container" if self.action == 0 else "Placed in Container"
return self.action
@property
def display_data(self):
if self.type == "block":
material = self.data.replace("minecraft:", "")
parts = material.split("_")
return " ".join([part.capitalize() for part in parts])
return self.data
class Meta:
managed = False

View File

@ -2,8 +2,30 @@
flatpickr('[type="date"]', {
altInput: true,
altFormat: "F j, Y at H:i",
dateFormat: "Y-m-d H:i",
dateFormat: "U",
enableTime: true,
});
})();
function ajax(method, url, callback) {
let xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState === XMLHttpRequest.DONE) { // XMLHttpRequest.DONE == 4
callback(xmlhttp.status, xmlhttp.responseText);
}
};
xmlhttp.open(method, url, true);
xmlhttp.send();
}
function formURI(formData) {
let pairs = [];
for (let data of formData.entries()) {
pairs.push(encodeURIComponent(data[0]) + '=' + encodeURIComponent(data[1]))
}
return pairs.join("&").replace(/%20/g, '+');
}
function elementHTML(id, html) {
document.getElementById(id).innerHTML = html
}

View File

@ -22,7 +22,7 @@
<hr/>
</div>
<div class="columns">
<form style="margin-left: 7rem;" class="has-text-left column is-one-third">
<form style="margin-left: 7rem;" id="coreprotect_form" name="coreprotect_form" class="has-text-left column is-one-third">
<div class="columns">
<div class="column is-one-half">
<h4 class="title is-5 has-text-primary">
@ -68,8 +68,8 @@
</h4>
{% for world in form.worlds %}
<div class="field">
<input class="is-checkradio is-block is-info" id="{{world.id}}" name="{{world.id}}" type="checkbox" {% if world.checked %}checked{% endif %}>
<label for="{{world.id}}">{{world.name}}</label>
<input class="is-checkradio is-block is-info" id="{{world.world_id}}" name="world" value="{{world.id}}" type="checkbox" {% if world.checked %}checked{% endif %}>
<label for="{{world.world_id}}">{{world.name}}</label>
</div>
{% endfor %}
@ -142,8 +142,8 @@
<h4 class="title is-5 has-text-primary">
Blocks
</h4>
<div class="field tooltip is-tooltip-multiline" data-tooltip="Accepts full names, partial names, or block IDs. Separated by commas.">
<input class="input is-4" id="blocks" name="blocks" type="text" placeholder="Block Names or IDs" value="{{form.blocks}}">
<div class="field tooltip is-tooltip-multiline" data-tooltip="Accepts full or partial names. Separated by commas.">
<input class="input is-4" id="blocks" name="blocks" type="text" placeholder="Block Names" value="{{form.blocks}}">
</div>
<br/>
@ -166,7 +166,7 @@
<div class="field is-grouped">
<p class="control">
<button class="button is-primary" name="search" value="true" type="submit">Search</button>
<button class="button is-primary" id="search" type="button">Search</button>
</p>
<p class="control">
<button class="button is-dark" id="clear" type="button">Clear</button>
@ -175,7 +175,7 @@
</div>
</div>
</form>
<div class="column is-three-fifths">
<div class="column is-three-fifths" id="results">
</div>
</div>
@ -183,6 +183,16 @@
<script src="{% static 'coreprotect/js/bulma-extensions.min.js' %}"></script>
<script src="{% static 'coreprotect/js/main.js' %}"></script>
<script>
document.getElementById("search").addEventListener("click", function() {
elementHTML("results", 'Querying Database...<br/><progress class="progress is-primary"></progress>');
let form = document.getElementById("coreprotect_form");
let formData = new FormData(form);
ajax("GET", "{% url "coreprotect_query" %}?" + formURI(formData), function(status, data) {
elementHTML("results", data);
});
});
document.getElementById("clear").addEventListener("click", function() {
// Actions
document.getElementById("block_break").checked = false;
@ -196,7 +206,7 @@
// Worlds
{% for world in form.worlds %}
document.getElementById("{{world.id}}").checked = false;
document.getElementById("{{world.world_id}}").checked = false;
{% endfor %}
// Options

View File

@ -0,0 +1,28 @@
<table class="table is-fullwidth is-striped is-bordered">
<thead>
<tr>
<th>Time</th>
<th>Player</th>
<th>Action</th>
<th>Data</th>
<th>X</th>
<th>Y</th>
<th>Z</th>
<th>World</th>
</tr>
</thead>
<tbody>
{% for result in results %}
<tr>
<td>{{ result.display_time }}</td>
<td>{{ result.player }}</td>
<td>{{ result.display_action }}</td>
<td>{{ result.display_data }}</td>
<td>{{ result.x }}</td>
<td>{{ result.y }}</td>
<td>{{ result.z }}</td>
<td>{{ result.world }}</td>
</tr>
{% endfor %}
</tbody>
</table>

View File

@ -1,7 +1,8 @@
from django.urls import path
from django.contrib.auth.decorators import permission_required
from django_coreprotect.views import Home
from django_coreprotect.views import Home, Query
urlpatterns = [
path('', permission_required('coreprotect_base')(Home.as_view())),
path('', permission_required('coreprotect_base')(Home.as_view()), name="coreprotect_index"),
path('query/', permission_required('coreprotect_base')(Query.as_view()), name="coreprotect_query"),
]

175
views.py
View File

@ -1,39 +1,57 @@
from django.shortcuts import render
from django.views.generic import View
from django_coreprotect.models import CoWorld
from django.http.response import JsonResponse
from django_coreprotect.models import *
class Home(View):
def get(self, request):
form = form_data(request.GET)
return render(request, "coreprotect/coreprotect.html", {"form": form, "results": result_data(form)})
return render(request, "coreprotect/coreprotect.html", {"form": form})
def post(self, request):
pass
class Query(View):
def get(self, request):
form = form_data(request.GET)
results = result_data(form)
if "format" in request.GET and request.GET["format"] == "json":
return JsonResponse(results)
return render(request, "coreprotect/table.html", {"results": results})
def post(self, request):
pass
class Form:
block_break = False
block_place = False
chat = False
chest_use = False
command = False
interact = False
login_logout = False
sign_place = False
worlds = []
ignore_environment = False
limit_results = "200"
players = ""
x = ""
y = ""
z = ""
radius = ""
blocks = ""
date_from = ""
date_to = ""
search = False
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.start = ""
self.limit_results = ""
self.players = ""
self.x = ""
self.y = ""
self.z = ""
self.radius = ""
self.blocks = ""
self.date_from = ""
self.date_to = ""
def form_data(request_data):
@ -51,11 +69,13 @@ def form_data(request_data):
form.sign_place = checkbox(request_data["sign_place"]) if "sign_place" in request_data else False
# Worlds
request_worlds = request_data.getlist("world")
for world in worlds:
world_id = "world_{}".format(world.id)
w = {
"id": world_id,
"checked": checkbox(request_data[world_id]) if world_id in request_data else False,
"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)
@ -64,6 +84,7 @@ def form_data(request_data):
form.ignore_environment = checkbox(request_data["ignore_environment"]) if "ignore_environment" in request_data else False
# Limit Results
form.start = request_data["start"] if "start" in request_data else "0"
form.limit_results = request_data["limit_results"] if "limit_results" in request_data else "200"
# Players
@ -81,9 +102,10 @@ def form_data(request_data):
# 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 ""
# Search
form.search = "search" in request_data and request_data["search"] == "true"
if form.date_from and not form.date_to:
form.date_to = datetime.now().timestamp()
if form.date_to and not form.date_from:
form.date_from = datetime.now().timestamp()
return form
@ -93,6 +115,101 @@ def checkbox(value):
def result_data(form):
results = {}
queries = []
ignore_environment = " AND player NOT LIKE '#%' " if form.ignore_environment else ""
return results
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 and form.date_to:
time_clause = " AND unix BETWEEN {} AND {} ".format(form.date_from, form.date_to)
# 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}
{coords}
{players}
{worlds}
{time}
'''.format(action=",".join(block_actions), ignore_environment=ignore_environment, coords=coords_clause,
players=players_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 cch.user = cu.id
WHERE 1 = 1
{players}
{time}
'''.format(players=players_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_chat cc
JOIN co_user cu ON cco.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
{coords}
{players}
{worlds}
{time}
'''.format(coords=coords_clause,
players=players_clause, worlds=worlds_clause, time=time_clause))
query = " UNION ".join(queries)
if query and form.limit_results != "-1":
query += " LIMIT {}, {}".format(form.start, form.limit_results)
print(query)
if query:
return CoResult.objects.raw(query)
return []