ail-framework/var/www/templates/chats_explorer/chat_viewer.html

582 lines
23 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>Chats Protocols - AIL</title>
<link rel="icon" href="{{ url_for('static', filename='image/ail-icon.png') }}">
<!-- Core CSS -->
<link href="{{ url_for('static', filename='css/bootstrap4.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/dataTables.bootstrap.min.css') }}" rel="stylesheet">
<!-- JS -->
<script src="{{ url_for('static', filename='js/jquery.js')}}"></script>
<script src="{{ url_for('static', filename='js/popper.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/bootstrap4.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/jquery.dataTables.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/dataTables.bootstrap.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/d3.min.js')}}"></script>
<style>
.chat-message-left,
.chat-message-right {
display: flex;
flex-shrink: 0;
}
.chat-message-right {
flex-direction: row-reverse;
margin-left: auto
}
.divider:after,
.divider:before {
content: "";
flex: 1;
height: 2px;
background: #eee;
}
</style>
</head>
<body>
{% include 'nav_bar.html' %}
<div class="container-fluid">
<div class="row">
{% include 'sidebars/sidebar_objects.html' %}
<div class="col-12 col-lg-10" id="core_content">
<div class="card my-3">
<div class="card-header" style="background-color:#d9edf7;font-size: 15px">
<h4 class="text-secondary">{% if chat['username'] %}{{ chat["username"]["id"] }} {% else %} {{ chat['name'] }}{% endif %} :</h4> {{ chat["id"] }}
<ul class="list-group mb-2">
<li class="list-group-item py-0">
<table class="table">
<thead class="">
<tr>
<th>Icon</th>
<th>Name</th>
<th>ID</th>
<th>Created at</th>
<th>First Seen</th>
<th>Last Seen</th>
<th>NB Sub-Channels</th>
</tr>
</thead>
<tbody style="font-size: 15px;">
<tr>
<td></td>
<td>{{ chat['name'] }}</td>
<td>{{ chat['id'] }}</td>
<td>{{ chat['created_at'] }}</td>
<td>
{% if chat['first_seen'] %}
{{ chat['first_seen'][0:4] }}-{{ chat['first_seen'][4:6] }}-{{ chat['first_seen'][6:8] }}
{% endif %}
</td>
<td>
{% if chat['last_seen'] %}
{{ chat['last_seen'][0:4] }}-{{ chat['last_seen'][4:6] }}-{{ chat['last_seen'][6:8] }}
{% endif %}
</td>
<td>{{ chat['nb_subchannels'] }}</td>
</tr>
</tbody>
</table>
{% if chat['info'] %}
<li class="list-group-item py-0">
<pre class="my-0">{{ chat['info'] }}</pre>
</li>
{% endif %}
</li>
</ul>
</div>
</div>
{% for tag in chat['tags_messages'] %}
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }}">{{ tag }} <span class="badge badge-light">{{ chat['tags_messages'][tag] }}</span></span>
{% endfor %}
{% if chat['subchannels'] %}
<h4>Sub-Channels:</h4>
<table id="tablesubchannels" class="table">
<thead class="bg-dark text-white">
<tr>
<th>Icon</th>
<th>Name</th>
<th>ID</th>
<th>Created at</th>
<th>First Seen</th>
<th>Last Seen</th>
<th>NB Messages</th>
</tr>
</thead>
<tbody style="font-size: 15px;">
{% for meta in chat["subchannels"] %}
<tr>
<td>
<img src="{{ url_for('static', filename='image/ail-icon.png') }}" class="rounded-circle mr-1" alt="{{ meta['id'] }}" width="40" height="40">
</td>
<td><b>{{ meta['name'] }}</b></td>
<td><a href="{{ url_for('chats_explorer.objects_subchannel_messages') }}?uuid={{ meta['subtype'] }}&id={{ meta['id'] }}">{{ meta['id'] }}</a></td>
<td>{{ meta['created_at'] }}</td>
<td>
{% if meta['first_seen'] %}
{{ meta['first_seen'][0:4] }}-{{ meta['first_seen'][4:6] }}-{{ meta['first_seen'][6:8] }}
{% endif %}
</td>
<td>
{% if meta['last_seen'] %}
{{ meta['last_seen'][0:4] }}-{{ meta['last_seen'][4:6] }}-{{ meta['last_seen'][6:8] }}
{% endif %}
</td>
<td>{{ meta['nb_messages'] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
<div id="heatmapweekhour"></div>
{% if chat['messages'] %}
<div class="position-relative">
<div class="chat-messages p-2">
{% for date in chat['messages'] %}
<div class="divider d-flex align-items-center mb-4">
<p class="text-center h2 mx-3 mb-0" style="color: #a2aab7;">
<span class="badge badge-secondary mb-2" id="date_section_{{ date }}">{{ date }}</span>
</p>
</div>
{% for mess in chat['messages'][date] %}
<div class="chat-message-left pb-1">
<div>
<img src="{{ url_for('static', filename='image/ail-icon.png') }}" class="rounded-circle mr-1" alt="{{ mess['user-account']['id'] }}" width="40" height="40">
<div class="text-muted small text-nowrap mt-2">{{ mess['hour'] }}</div>
</div>
<div class="flex-shrink-1 bg-light rounded py-2 px-3 ml-4 pb-4" style="overflow-x: auto">
<div class="font-weight-bold mb-1">
{% if mess['user-account']['username'] %}
{{ mess['user-account']['username']['id'] }}
{% else %}
{{ mess['user-account']['id'] }}
{% endif %}
</div>
{% if mess['reply_to'] %}
<div class="flex-shrink-1 bg-white border rounded py-2 px-3 ml-4 mb-3" style="overflow-x: auto">
<div class="font-weight-bold mb-1">
{% if mess['reply_to']['user-account']['username'] %}
{{ mess['reply_to']['user-account']['username']['id'] }}
{% else %}
{{ mess['reply_to']['user-account']['id'] }}
{% endif %}
</div>
<pre class="my-0">{{ mess['reply_to']['content'] }}</pre>
{% for tag in mess['reply_to']['tags'] %}
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }}">{{ tag }}</span>
{% endfor %}
<div class="text-muted small text-nowrap">{{ mess['reply_to']['full_date'] }}</div>
{# <div class="">#}
{# <a class="btn btn-light btn-sm text-secondary py-0" href="{{ url_for('correlation.show_correlation')}}?type={{ mess['reply_to']['type'] }}&subtype={{ mess['reply_to']['subtype'] }}&id={{ mess['reply_to']['id'] }}"><i class="fas fa-project-diagram"></i></a>#}
{# <a class="btn btn-light btn-sm text-secondary py-0" href="{{ mess['reply_to']['link'] }}"><i class="fas fa-eye"></i></a>#}
{# </div>#}
</div>
{% endif %}
<pre class="my-0">{{ mess['content'] }}</pre>
{% for tag in mess['tags'] %}
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }}">{{ tag }}</span>
{% endfor %}
<div class="">
<a class="btn btn-light btn-sm text-secondary px-1" href="{{ url_for('correlation.show_correlation')}}?type={{ mess['type'] }}&subtype={{ mess['subtype'] }}&id={{ mess['id'] }}"><i class="fas fa-project-diagram"></i></a>
<a class="btn btn-light btn-sm text-secondary px-1" href="{{ mess['link'] }}"><i class="fas fa-eye"></i></a>
</div>
</div>
</div>
{% endfor %}
<br>
{% endfor %}
</div>
</div>
{% endif %}
</div>
</div>
</div>
<script>
$(document).ready(function(){
$("#page-Decoded").addClass("active");
$("#nav_cve").addClass("active");
{% if chat['subchannels'] %}
$('#tablesubchannels').DataTable({
"aLengthMenu": [[5, 10, 15, -1], [5, 10, 15, "All"]],
"iDisplayLength": 10,
"order": [[ 5, "desc" ]]
});
{% endif %}
});
function toggle_sidebar(){
if($('#nav_menu').is(':visible')){
$('#nav_menu').hide();
$('#side_menu').removeClass('border-right')
$('#side_menu').removeClass('col-lg-2')
$('#core_content').removeClass('col-lg-10')
}else{
$('#nav_menu').show();
$('#side_menu').addClass('border-right')
$('#side_menu').addClass('col-lg-2')
$('#core_content').addClass('col-lg-10')
}
}
</script>
<script>
/*
// set the dimensions and margins of the graph
const margin = {top: 30, right: 30, bottom: 30, left: 30},
width = 450 - margin.left - margin.right,
height = 450 - margin.top - margin.bottom;
// append the svg object to the body of the page
const svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
// Labels of row and columns
const myGroups = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
const myVars = ["v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10"]
//Read the data
d3.csv("").then( function(data) {
// Labels of row and columns -> unique identifier of the column called 'group' and 'variable'
const myGroups = Array.from(new Set(data.map(d => d.group)))
const myVars = Array.from(new Set(data.map(d => d.variable)))
// Build X scales and axis:
const x = d3.scaleBand()
.range([ 0, width ])
.domain(myGroups)
.padding(0.05);
svg.append("g")
.style("font-size", 15)
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x).tickSize(0))
.select(".domain").remove()
// Build Y scales and axis:
const y = d3.scaleBand()
.range([ height, 0 ])
.domain(myVars)
.padding(0.01);
svg.append("g")
.style("font-size", 15)
.call(d3.axisLeft(y).tickSize(0))
.select(".domain").remove()
// Build color scale
const myColor = d3.scaleSequential()
.interpolator(d3.interpolateInferno)
.domain([1,100])
// create a tooltip
const tooltip = d3.select("#my_dataviz")
.append("div")
.style("opacity", 0)
.attr("class", "tooltip")
.style("background-color", "white")
.style("border", "solid")
.style("border-width", "2px")
.style("border-radius", "5px")
.style("padding", "5px")
// Three function that change the tooltip when user hover / move / leave a cell
const mouseover = function(event,d) {
tooltip.style("opacity", 1)
d3.select(this)
.style("stroke", "black")
.style("opacity", 1)
}
const mousemove = function(event,d) {
tooltip.html("The exact value of<br>this cell is: " + d)
.style("left", (event.x)/2 + "px")
.style("top", (event.y)/2 + "px")
}
const mouseleave = function(d) {
tooltip.style("opacity", 0)
d3.select(this)
.style("stroke", "none")
.style("opacity", 0.8)
}
svg.selectAll()
.data(data, function(d) {return d.group+':'+d.variable;})
.join("rect")
.attr("x", function(d) { return x(d.group) })
.attr("y", function(d) { return y(d.variable) })
.attr("rx", 4)
.attr("ry", 4)
.attr("width", x.bandwidth() )
.attr("height", y.bandwidth() )
.style("fill", function(d) { return myColor(d.value)} )
.style("stroke-width", 4)
.style("stroke", "none")
.style("opacity", 0.8)
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseleave", mouseleave)
})
*/
</script>
<script>
// based on gist nbremer/62cf60e116ae821c06602793d265eaf6
d3.json("{{ url_for('chats_explorer.chats_explorer_messages_stats_week') }}?uuid={{ chat['subtype'] }}&id={{ chat['id'] }}")
.then(function(data) {
var days = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
times = d3.range(24);
var margin = {
top: 80,
right: 50,
bottom: 20,
left: 50
};
var width = Math.max(Math.min(window.innerWidth, 1000), 500) - margin.left - margin.right - 20,
gridSize = Math.floor(width / times.length),
height = gridSize * (days.length + 2);
var heatmap_font_size = width * 62.5 / 900;
//SVG container
var svg = d3.select('#heatmapweekhour')
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// create a tooltip
const tooltip = d3.select("#heatmapweekhour")
.append("div")
.style("opacity", 0)
.attr("class", "tooltip")
.style("background-color", "white")
.style("border", "solid")
.style("border-width", "2px")
.style("border-radius", "5px")
.style("padding", "5px")
// Three function that change the tooltip when user hover / move / leave a cell
const mouseover = function(d) {
tooltip.style("opacity", 1)
d3.select(this)
.style("stroke", "black")
.style("opacity", 1)
tooltip.html(d.date + " " + d.hour + "-" + (d.hour + 1) + "h: <b>" + d.count + "</b> messages")
}
const mouseleave = function(d) {
console.log(d)
console.log(d.hour)
console.log(d.day)
tooltip.style("opacity", 0)
d3.select(this)
.style("stroke", "none")
.style("opacity", 0.8)
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////// Draw Heatmap /////////////////////////////////
///////////////////////////////////////////////////////////////////////////
var colorScale = d3.scaleLinear()
.domain([0, d3.max(data, function (d) {
return d.count;
}) / 2, d3.max(data, function (d) {
return d.count;
})])
.range(["#FFFFF6", "#3E9583", "#1F2D86"])
//.interpolate(d3.interpolateHcl);
var dayLabels = svg.selectAll(".dayLabel")
.data(days)
.enter().append("text")
.text(function (d) {
return d;
})
.attr("x", 0)
.attr("y", function (d, i) {
return i * gridSize;
})
.style("text-anchor", "end")
.attr("transform", "translate(-36, -11)")
.attr("class", function (d, i) {
return ((i >= 0 && i <= 4) ? "dayLabel mono axis axis-workweek" : "dayLabel mono axis");
})
.style("font-size", heatmap_font_size + "%");
var timeLabels = svg.selectAll(".timeLabel")
.data(times)
.enter().append("text")
.text(function (d) {
return d;
})
.attr("x", function (d, i) {
return i * gridSize;
})
.attr("y", 0)
.style("text-anchor", "middle")
.attr("transform", "translate(-" + gridSize / 2 + ", -36)")
.attr("class", function (d, i) {
return ((i >= 8 && i <= 17) ? "timeLabel mono axis axis-worktime" : "timeLabel mono axis");
})
.style("font-size", heatmap_font_size + "%");
var heatMap = svg.selectAll(".hour")
.data(data)
.enter().append("rect")
.attr("x", function (d) {
return (d.hour - 1) * gridSize;
})
.attr("y", function (d) {
return (d.day - 1) * gridSize;
})
.attr("class", "hour bordered")
.attr("width", gridSize)
.attr("height", gridSize)
.style("stroke", "white")
.style("stroke-opacity", 0.6)
.style("fill", function (d) {
return colorScale(d.count);
})
.on("mouseover", mouseover)
.on("mouseleave", mouseleave);
//Append title to the top
svg.append("text")
.attr("class", "title")
.attr("x", width / 2)
.attr("y", -60)
.style("text-anchor", "middle")
.text("Chat Messages");
///////////////////////////////////////////////////////////////////////////
//////////////// Create the gradient for the legend ///////////////////////
///////////////////////////////////////////////////////////////////////////
//Extra scale since the color scale is interpolated
var countScale = d3.scaleLinear()
.domain([0, d3.max(data, function (d) {
return d.count;
})])
.range([0, width])
//Calculate the variables for the temp gradient
var numStops = 10;
countRange = countScale.domain();
countRange[2] = countRange[1] - countRange[0];
countPoint = [];
for (var i = 0; i < numStops; i++) {
countPoint.push(i * countRange[2] / (numStops - 1) + countRange[0]);
}//for i
//Create the gradient
svg.append("defs")
.append("linearGradient")
.attr("id", "legend-heatmap")
.attr("x1", "0%").attr("y1", "0%")
.attr("x2", "100%").attr("y2", "0%")
.selectAll("stop")
.data(d3.range(numStops))
.enter().append("stop")
.attr("offset", function (d, i) {
return countScale(countPoint[i]) / width;
})
.attr("stop-color", function (d, i) {
return colorScale(countPoint[i]);
});
///////////////////////////////////////////////////////////////////////////
////////////////////////// Draw the legend ////////////////////////////////
///////////////////////////////////////////////////////////////////////////
var legendWidth = Math.min(width * 0.8, 400);
//Color Legend container
var legendsvg = svg.append("g")
.attr("class", "legendWrapper")
.attr("transform", "translate(" + (width / 2) + "," + (gridSize * days.length) + ")"); // 319
//Draw the Rectangle
legendsvg.append("rect")
.attr("class", "legendRect")
.attr("x", -legendWidth / 2)
.attr("y", 0)
//.attr("rx", hexRadius*1.25/2)
.attr("width", legendWidth)
.attr("height", 10)
.style("fill", "url(#legend-heatmap)");
//Append title
legendsvg.append("text")
.attr("class", "legendTitle")
.attr("x", 0)
.attr("y", -10)
.style("text-anchor", "middle")
.text("Number of Messages");
//Set scale for x-axis
var xScale = d3.scaleLinear()
.range([-legendWidth / 2, legendWidth / 2])
.domain([0, d3.max(data, function (d) {
return d.count;
})]);
//Define x-axis
var xAxis = d3.axisBottom(xScale)
//.orient("bottom")
.ticks(5);
//.tickFormat(formatPercent)
//Set up X axis
legendsvg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (10) + ")")
.call(xAxis);
})
</script>
</body>
</html>