Implement more elements on Insights page

This commit is contained in:
Mark Veidemanis 2022-07-21 13:52:10 +01:00
parent 9de9ddff6f
commit 17d465171b
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
11 changed files with 291 additions and 152 deletions

View File

@ -53,4 +53,4 @@ THRESHOLD_API_KEY = "name"
THRESHOLD_API_TOKEN = "token"
THRESHOLD_API_COUNTER = "counter"
DEBUG = True
DEBUG = True

View File

@ -33,6 +33,8 @@ from core.views.dynamic.drilldown import DrilldownSearch, ThresholdInfoModal
from core.views.dynamic.insights import (
InsightsChannels,
InsightsInfoModal,
InsightsMeta,
InsightsNicks,
InsightsSearch,
)
@ -54,13 +56,18 @@ urlpatterns = [
path("admin/", admin.site.urls),
path("accounts/", include("django.contrib.auth.urls")),
path("accounts/signup/", Signup.as_view(), name="signup"),
##
path("ui/drilldown/", Drilldown.as_view(), name="drilldown"),
path("ui/drilldown/modal/", ThresholdInfoModal.as_view(), name="modal_drilldown"),
path("ui/drilldown/search/", DrilldownSearch.as_view(), name="search_drilldown"),
##
path("ui/insights/", Insights.as_view(), name="insights"),
path("parts/search/drilldown/", DrilldownSearch.as_view(), name="search_drilldown"),
path("parts/search/insights/", InsightsSearch.as_view(), name="search_insights"),
path("parts/channels/insights/", InsightsChannels.as_view(), name="chans_insights"),
path("modal/drilldown/", ThresholdInfoModal.as_view(), name="modal_drilldown"),
path("modal/insights/", InsightsInfoModal.as_view(), name="modal_insights"),
path("ui/insights/search/", InsightsSearch.as_view(), name="search_insights"),
path("ui/insights/channels/", InsightsChannels.as_view(), name="chans_insights"),
path("ui/insights/nicks/", InsightsNicks.as_view(), name="nicks_insights"),
path("ui/insights/meta/", InsightsMeta.as_view(), name="meta_insights"),
path("ui/insights/modal/", InsightsInfoModal.as_view(), name="modal_insights"),
##
path("api/chans/", ThresholdChans.as_view(), name="chans"),
path("api/users/", ThresholdUsers.as_view(), name="users"),
path("api/online/", ThresholdOnline.as_view(), name="online"),

15
core/lib/nicktrace.py Normal file
View File

@ -0,0 +1,15 @@
from core.lib.opensearch import client, run_main_query
def get_nicks(request, net, nick):
"""
Get all related nicknames of the given nickname by tracking nickname changes.
"""
# Get the initial query
query = {}
results = set()
# nicks = query["nicks"]
# for nick in nicks:
# if nick not in results:
# nicks_result = get_nicks(request, net_nick)
# results.add(nick)

View File

@ -93,7 +93,7 @@ def filter_blacklisted(user, response):
response["exemption"] = True
def run_main_query(client, user, query, size=None):
def run_main_query(client, user, query, custom_query=False, size=None):
"""
Low level helper to run an ES query.
Accept a user to pass it to the filter, so we can
@ -101,7 +101,10 @@ def run_main_query(client, user, query, size=None):
Accept fields and size, for the fields we want to match and the
number of results to return.
"""
search_query = construct_query(query, size)
if custom_query:
search_query = query
else:
search_query = construct_query(query, size)
try:
response = client.search(
body=search_query, index=settings.OPENSEARCH_INDEX_MAIN
@ -131,7 +134,7 @@ def query_results(request, size=None):
client,
request.user,
query,
size,
size=size,
)
if not results:
return False

View File

@ -1,12 +1,9 @@
<div class="tile is-parent" id="chans1">
<div class="tile is-child ">
<div class="panel is-primary" style="height: 30rem; overflow: auto">
<p class="panel-heading">
Channels
</p>
{% for chan in chans %}
<div id="channels">
<div class="panel is-primary" style="max-height: 30em; overflow: auto">
<p class="panel-heading">
Channels
</p>
{% for chan in chans %}
<a class="panel-block is-active">
<span class="panel-icon">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
@ -20,9 +17,7 @@
class="button is-small">
{{ chan }}
</span>
</a>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
</div>

View File

@ -0,0 +1,112 @@
{% load static %}
{% load index %}
<div id="info">
<div class="panel is-primary">
<p class="panel-heading">
Information
</p>
<div class="panel-block is-active">
{% if item is not None %}
<div class="table-container">
<table class="table is-fullwidth is-hoverable">
<tbody>
<tr>
<th>src</th>
<td>
{% if item.src == 'irc' %}
<span class="icon" data-tooltip="IRC">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
</span>
IRC
{% elif item.src == 'dis' %}
<span class="icon" data-tooltip="Discord">
<i class="fa-brands fa-discord" aria-hidden="true"></i>
</span>
Discord
{% endif %}
</td>
</tr>
<tr>
<th>nick</th>
<td>
{% if item.online is True %}
<span class="icon has-text-success has-tooltip-success" data-tooltip="Online">
<i class="fa-solid fa-circle"></i>
</span>
{{ item.nick }}
{% elif item.online is False %}
<span class="icon has-text-danger has-tooltip-danger" data-tooltip="Offline">
<i class="fa-solid fa-circle"></i>
</span>
{{ item.nick }}
{% else %}
<span class="icon has-text-warning has-tooltip-warning" data-tooltip="Unknown">
<i class="fa-solid fa-circle"></i>
</span>
{{ item.nick }}
{% endif %}
{% if item.num_chans is not None %}
<span class="tag">
{{ item.num_chans }}
</span>
{% endif %}
</td>
</tr>
<tr>
<th>host</th>
<td>{{ item.host }}</td>
</tr>
<tr>
<th>actions</th>
<td>
{% if item.src == 'irc' %}
<button
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-post="{% url 'modal_insights' %}"
hx-vals='{"net": "{{ item.net }}", "nick": "{{ item.nick }}", "channel": "{{ item.channel }}"}'
hx-target="#modals-here"
hx-trigger="click"
class="button is-small">
Information
</button>
{% endif %}
</td>
</tr>
<tr>
<th>net</th>
<td>{{ item.net }}</td>
</tr>
</tbody>
</table>
</div>
{% endif %}
</div>
<div
style="display: none;"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-vals='{"net": "{{ item.net }}", "nick": "{{ item.nick }}"}'
hx-post="{% url 'chans_insights' %}"
hx-trigger="load"
hx-target="#channels"
hx-swap="outerHTML">
</div>
<div
style="display: none;"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-vals='{"net": "{{ item.net }}", "nick": "{{ item.nick }}"}'
hx-post="{% url 'nicks_insights' %}"
hx-trigger="load"
hx-target="#nicks"
hx-swap="outerHTML">
</div>
<div
style="display: none;"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-vals='{"net": "{{ item.net }}", "nick": "{{ item.nick }}"}'
hx-post="{% url 'meta_insights' %}"
hx-trigger="load"
hx-target="#meta"
hx-swap="outerHTML">
</div>
</div>
</div>

View File

@ -38,46 +38,66 @@
.icon { border-bottom: 0px !important;}
</style>
<div class="tile is-ancestor">
<div class="tile is-parent is-vertical">
<div class="tile is-child box">
<form method="POST">
{% csrf_token %}
<div class="field">
<label class="label">Search</label>
<div class="field-body">
<div class="tile is-vertical is-9">
<div class="tile">
<div class="tile is-parent is-vertical">
<article class="tile is-child box">
<form method="POST">
{% csrf_token %}
<div class="field">
<div class="control is-expanded has-icons-left">
<input name="query" class="input" type="text" placeholder="nickname">
<span class="icon is-small is-left">
<i class="fas fa-magnifying-glass"></i>
</span>
<label class="label">Search</label>
<div class="field-body">
<div class="field">
<div class="control is-expanded has-icons-left">
<input name="query" class="input" type="text" placeholder="nickname">
<span class="icon is-small is-left">
<i class="fas fa-magnifying-glass"></i>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="field">
<div class="control">
<button
class="button is-primary is-fullwidth"
hx-post="{% url 'search_insights' %}"
hx-trigger="click"
hx-target="#results"
hx-swap="innerHTML">
Search
</button>
</div>
</div>
</form>
</div>
<div id="results">
</div>
<div class="field">
<div class="control">
<button
class="button is-primary is-fullwidth"
hx-post="{% url 'search_insights' %}"
hx-trigger="click"
hx-target="#info"
hx-swap="outerHTML">
Search
</button>
</div>
</div>
</form>
</article>
</div>
<div class="tile is-parent">
<article class="tile is-child box">
<div id="nicks"></div>
</article>
</div>
</div>
<div class="tile">
<div class="tile is-parent is-vertical">
<article class="tile is-child box">
<div id="info"></div>
</article>
</div>
<div class="tile is-parent">
<article class="tile is-child box">
<div id="meta"></div>
</article>
</div>
</div>
</div>
<div class="tile is-parent">
<article class="tile is-child box">
<div id="channels"></div>
</article>
</div>
<article id="chans1">
</article>
</div>
<div id="modals-here"></div>
{% endblock %}

View File

@ -0,0 +1,21 @@
<div id="meta">
<div class="panel is-primary" style="max-height: 30em; overflow: auto">
<p class="panel-heading">
Meta
</p>
<a class="panel-block is-active">
<span class="panel-icon">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
</span>
<span
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-post="{% url 'modal_drilldown' %}"
hx-vals='{"net": "{{ net }}", "nick": "{{ nick }}", "channel": "{{ chan }}"}'
hx-target="#modals-here"
hx-trigger="click"
class="button is-small">
bbb
</span>
</a>
</div>
</div>

View File

@ -0,0 +1,21 @@
<div id="nicks">
<div class="panel is-primary" style="max-height: 30em; overflow: auto">
<p class="panel-heading">
Nicks
</p>
<a class="panel-block is-active">
<span class="panel-icon">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
</span>
<span
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-post="{% url 'modal_drilldown' %}"
hx-vals='{"net": "{{ net }}", "nick": "{{ nick }}", "channel": "{{ chan }}"}'
hx-target="#modals-here"
hx-trigger="click"
class="button is-small">
aaa
</span>
</a>
</div>
</div>

View File

@ -1,94 +0,0 @@
{% load static %}
{% load index %}
<div class="panel is-primary">
<p class="panel-heading">
Information
</p>
<div class="panel-block is-active">
<div class="tile is-child">
{% if item is not None %}
<div class="table-container">
<table class="table is-fullwidth is-hoverable">
<tbody>
<tr>
<th>src</th>
<td>
{% if item.src == 'irc' %}
<span class="icon" data-tooltip="IRC">
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
</span>
IRC
{% elif item.src == 'dis' %}
<span class="icon" data-tooltip="Discord">
<i class="fa-brands fa-discord" aria-hidden="true"></i>
</span>
Discord
{% endif %}
</td>
</tr>
<tr>
<th>nick</th>
<td>
{% if item.online is True %}
<span class="icon has-text-success has-tooltip-success" data-tooltip="Online">
<i class="fa-solid fa-circle"></i>
</span>
{{ item.nick }}
{% elif item.online is False %}
<span class="icon has-text-danger has-tooltip-danger" data-tooltip="Offline">
<i class="fa-solid fa-circle"></i>
</span>
{{ item.nick }}
{% else %}
<span class="icon has-text-warning has-tooltip-warning" data-tooltip="Unknown">
<i class="fa-solid fa-circle"></i>
</span>
{{ item.nick }}
{% endif %}
{% if item.num_chans is not None %}
<span class="tag">
{{ item.num_chans }}
</span>
{% endif %}
</td>
</tr>
<tr>
<th>host</th>
<td>{{ item.host }}</td>
</tr>
<tr>
<th>actions</th>
<td>
{% if item.src == 'irc' %}
<button
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-post="{% url 'modal_insights' %}"
hx-vals='{"net": "{{ item.net }}", "nick": "{{ item.nick }}", "channel": "{{ item.channel }}"}'
hx-target="#modals-here"
hx-trigger="click"
class="button is-small">
Information
</button>
{% endif %}
</td>
</tr>
<tr>
<th>net</th>
<td>{{ item.net }}</td>
</tr>
</tbody>
</table>
</div>
{% endif %}
</div>
</div>
</div>
<div
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-vals='{"net": "{{ item.net }}", "nick": "{{ item.nick }}"}'
hx-post="{% url 'chans_insights' %}"
hx-trigger="load"
hx-target="#chans1"
hx-swap="outerHTML">
</div>

View File

@ -5,6 +5,7 @@ from django.views import View
from rest_framework.parsers import FormParser
from rest_framework.views import APIView
from core.lib.nicktrace import get_nicks
from core.lib.opensearch import query_single_result
from core.lib.threshold import (
annotate_num_chans,
@ -16,7 +17,7 @@ from core.lib.threshold import (
class InsightsSearch(LoginRequiredMixin, View):
# parser_classes = [JSONParser]
template_name = "ui/insights/results.html"
template_name = "ui/insights/info.html"
plan_name = "drilldown"
def post(self, request):
@ -57,6 +58,44 @@ class InsightsChannels(LoginRequiredMixin, APIView):
return HttpResponse("No results")
class InsightsNicks(LoginRequiredMixin, APIView):
parser_classes = [FormParser]
template_name = "ui/insights/nicks.html"
plan_name = "drilldown"
def post(self, request):
if not request.user.has_plan(self.plan_name):
return HttpResponseForbidden()
if "net" not in request.data:
return HttpResponse("No net")
if "nick" not in request.data:
return HttpResponse("No nick")
net = request.data["net"]
nick = request.data["nick"]
context = {"net": net, "nick": nick}
return render(request, self.template_name, context)
class InsightsMeta(LoginRequiredMixin, APIView):
parser_classes = [FormParser]
template_name = "ui/insights/meta.html"
plan_name = "drilldown"
def post(self, request):
if not request.user.has_plan(self.plan_name):
return HttpResponseForbidden()
if "net" not in request.data:
return HttpResponse("No net")
if "nick" not in request.data:
return HttpResponse("No nick")
net = request.data["net"]
nick = request.data["nick"]
context = {"net": net, "nick": nick}
return render(request, self.template_name, context)
class InsightsInfoModal(LoginRequiredMixin, APIView):
parser_classes = [FormParser]
plan_name = "drilldown"