Commit 9f40a9a2 authored by Vladislav Rykov's avatar Vladislav Rykov
Browse files

admin:new user added&tested, user dashboard view in progress

parent 49b95dae
......@@ -66,9 +66,8 @@ def get_user_data_count_per_hour_period(cur, username, period):
for a in apps:
devs.append(dd.get_list(a[1])[1])
utc_hour = [utc_roundhour(x) for x in range(period,-1,-1)]
if apps != [] and devs != []:
utc_hour = [utc_roundhour(x) for x in range(period,-1,-1)]
query = 'WITH t AS ('
i = 0
for a in apps:
......@@ -86,7 +85,7 @@ def get_user_data_count_per_hour_period(cur, username, period):
return (True,cur.fetchall())
else:
return (True, (0,))
return (True, [(0,)])
......@@ -145,7 +144,7 @@ def get_user_data_count_per_day_period(cur, username, period):
return (True,cur.fetchall())
else:
return (True, (0,))
return (True, [(0,)])
@with_psql
......@@ -156,21 +155,24 @@ def get_recent_activity(cur, username, n=5):
for a in apps:
devs.append(dd.get_list(a[1])[1])
query = ''
for a in apps:
devs = dd.get_list(a[1])
for d in devs[1]:
query += """
(SELECT timedate, appname, devname, data, utc from
(SELECT utc, timedate, data from dev_{}_{} ORDER BY utc DESC limit 5) AS utc,
(SELECT '{}' as appname) AS appname,
(SELECT '{}' as devname) AS devname)
UNION ALL""".format(a[1],d[1], a[0],d[0])
query = query[0:-9]
query += ' ORDER BY utc DESC LIMIT {}'.format(n)
cur.execute(query, ())
return (True, cur.fetchall())
if apps != [] and devs != []:
query = ''
for a in apps:
devs = dd.get_list(a[1])
for d in devs[1]:
query += """
(SELECT timedate, appname, devname, data, utc from
(SELECT utc, timedate, data from dev_{}_{} ORDER BY utc DESC limit 5) AS utc,
(SELECT '{}' as appname) AS appname,
(SELECT '{}' as devname) AS devname)
UNION ALL""".format(a[1],d[1], a[0],d[0])
query = query[0:-9]
query += ' ORDER BY utc DESC LIMIT {}'.format(n)
cur.execute(query, ())
return (True, cur.fetchall())
else:
return (True, [])
......@@ -94,18 +94,18 @@
</li>
{% if session['role'] == 'admin' %}
<li class="nav-item">
<a class="nav-link " href="./administration">
<a class="nav-link " href="/administration">
<i class="ni ni-briefcase-24 text-pink"></i> Administration
</a>
</li>
<li class="nav-item">
<a class="nav-link " href="./administration/users">
<a class="nav-link " href="/administration/users">
<i class="ni ni-single-02 text-info"></i> Users
</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link " href="./settings">
<a class="nav-link " href="/settings">
<i class="ni ni-settings-gear-65 text-grey"></i> Settings
</a>
</li>
......
{% extends 'logged_layout.html' %}
{% block title %} New User - HPC&amp;A IoT {% endblock %}
{% block location %}
<a class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block" href="/applications">Applications</a>
<p class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block"> &nbsp;-&nbsp; </p>
<a class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block" href="/administration/users">Users</a>
{% endblock %}
{% block body %}
<!-- Page content -->
<div class="container-fluid mt--7">
<!-- Table -->
<div class="row">
<div class="col">
<div class="card shadow">
<div class="card-header bg-transparent">
<h3 class="mb-0">New User</h3>
</div>
<div class="card-body">
<form action="/administration/users/new-user" method="post">
<div class="form-group">
<label>Name:</label><br>
<input type="text" maxlength="30" class="form-control" id="username" name="username" required><br>
</div>
<div class="form-group">
<label>Password:</label><br>
<input class="form-control" placeholder="Password" type="password" minlength="8" id="password" name="password" onkeyup="return validate_password();">
<br>
<input class="form-control" placeholder="Repeat password" type="password" minlength="8" id="rpassword" name="rpassword" onkeyup="return validate_password();">
</div>
<div class="text-muted font-italic"><small>Required password strength: <span class="text-success font-weight-700">At least 8 characters.</span></small></div>
<div class="text-muted font-italic"><small id="passvalidation"></small></div>
<br>
<div class="form-group">
<label for="role"> Role: </label>
<select class="form-control" id="role" name="role">
<option> user </option>
<option> admin </option>
</select>
</div>
<br><br>
<div class="form-group">
<button type="submit" class="btn btn-primary">Create User</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% block script %}
<script type="text/javascript">
var password = document.getElementById("password");
var rpassword = document.getElementById("rpassword");
$("#submit").prop("disabled", true);
function validate_password() {
if (password.value != rpassword.value) {
$("#passvalidation").html("<span class='text-danger font-weight-700'>Passwords do not match.</span>");
$("#submit").prop("disabled", true);
} else {
$("#passvalidation").html("<span class='text-success font-weight-700'>Passwords match.</span>");
$("#submit").prop("disabled", false);
}
}
</script>
{% endblock %}
{% extends 'logged_layout.html' %}
{% block title %} User Dashboard - HPC&amp;A IoT {% endblock %}
{% block location %}
<a class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block" href="/administration">Administration</a>
<p class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block"> &nbsp;-&nbsp; </p>
<a class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block" href="/administration/users">Users</a>
<p class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block"> &nbsp;-&nbsp; </p>
<a class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block" href="/administration/users/{{ user }}">{{ user }}</a>
<p class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block"> &nbsp;-&nbsp; </p>
<a class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block" href="#">Dashboard</a>
{% endblock %}
{% block stats %}
<div class="row">
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Created Apps</h5>
<span class="h2 font-weight-bold mb-0">{{ info[0] }}</span>
</div>
<div class="col-auto">
<div class="icon icon-shape bg-danger text-white rounded-circle shadow">
<i class="fas fa-chart-bar"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Active Devices</h5>
<span class="h2 font-weight-bold mb-0">{{ info[1] }}</span>
</div>
<div class="col-auto">
<div class="icon icon-shape bg-warning text-white rounded-circle shadow">
<i class="fas fa-chart-pie"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Total Activity</h5>
<span class="h2 font-weight-bold mb-0">{{ info[2] }}</span>
</div>
<div class="col-auto">
<div class="icon icon-shape bg-yellow text-white rounded-circle shadow">
<i class="fas fa-users"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Last 24 Hours Activity</h5>
<span class="h2 font-weight-bold mb-0">{{ info[3] }}</span>
</div>
<div class="col-auto">
<div class="icon icon-shape bg-info text-white rounded-circle shadow">
<i class="fas fa-percent"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block body %}
<div class="container-fluid mt--7">
<div class="row">
<div class="col-xl-8 mb-5 mb-xl-0">
<div class="card bg-gradient-default shadow">
<div class="card-header bg-transparent">
<div class="row align-items-center">
<div class="col">
<h6 class="text-uppercase text-light ls-1 mb-1">Day Overview</h6>
<h2 class="text-white mb-0">Devices Activity</h2>
</div>
<div class="col">
<ul class="nav nav-pills justify-content-end">
<li class="nav-item mr-2 mr-md-0" data-toggle="chart" data-target="#chart-sales" data-suffix="messages">
<a href="#" class="nav-link py-2 px-3 active" data-toggle="tab">
<span class="d-none d-md-block">Last 12 Hours</span>
<span class="d-md-none">M</span>
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="card-body">
<!-- Chart -->
<div class="chart">
<!-- Chart wrapper -->
<canvas id="chart-sales" class="chart-canvas"></canvas>
</div>
</div>
</div>
</div>
<div class="col-xl-4">
<div class="card shadow">
<div class="card-header bg-transparent">
<div class="row align-items-center">
<div class="col">
<h6 class="text-uppercase text-muted ls-1 mb-1">Week Overview</h6>
<h2 class="mb-0">Per-day Activity</h2>
</div>
</div>
</div>
<div class="card-body">
<!-- Chart -->
<div class="chart">
<canvas id="chart-orders" class="chart-canvas"></canvas>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-5">
<div class="col-xl-12 mb-5 mb-xl-0">
<div class="card shadow">
<div class="card-header border-0">
<div class="row align-items-center">
<div class="col">
<h3 class="mb-0">Recen Activity</h3>
</div>
</div>
</div>
<div class="table-responsive">
<!-- Projects table -->
<table class="table align-items-center table-flush">
<thead class="thead-light">
<tr>
<th scope="col">App name</th>
<th scope="col">Device name</th>
<th scope="col">Timestamp</th>
<th scope="col">Message</th>
</tr>
</thead>
<tbody id="recent_activity_body">
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endblock %}
{% block script %}
<script type="text/javascript">
(function worker() {
var e = $("#chart-sales");
var e1 = $("#chart-orders");
$.get('/administration/users/{{ user }}/chart-update', function(cdata) {
cdata = eval(cdata);
var a = new Chart(e,
{
type: "line",
options:
{
scales:
{
yAxes: [
{
gridLines:
{
lineWidth: 1,
color: Charts.colors.gray[900],
zeroLineColor: Charts.colors.gray[900]
}
}]
},
tooltips:
{
callbacks:
{
label: function (e, a)
{
var t = a.datasets[e.datasetIndex].label || "",
o = e.yLabel,
n = "";
return 1 < a.datasets.length && (n += '<span class="popover-body-label mr-auto">' + t + "</span>"), n += '<span class="popover-body-value">' + o + "</span>"
}
}
}
},
data:
{
labels: cdata[0][0],
datasets: [
{
label: "Performance",
data: cdata[0][1]
}]
}
});
e.data("chart", a);
var a1 = new Chart(e1,
{
type: "bar",
options:
{
scales:
{
yAxes: [
{
gridLines:
{
lineWidth: 1,
color: "#dfe2e6",
zeroLineColor: "#dfe2e6"
},
ticks:
{
callback: function (e)
{
if (!(e % 10)) return e
}
}
}]
},
tooltips:
{
callbacks:
{
label: function (e, a)
{
var t = a.datasets[e.datasetIndex].label || "",
o = e.yLabel,
n = "";
return 1 < a.datasets.length && (n += '<span class="popover-body-label mr-auto">' + t + "</span>"), n += '<span class="popover-body-value">' + o + "</span>"
}
}
}
},
data:
{
labels: cdata[1][0],
datasets: [
{
label: "Sales",
data: cdata[1][1]
}]
}
});
e1.data("chart", a1);
setTimeout(worker, 600000);
});
})();
$.get("/administration/users/{{ user }}/recent-activity", function(cdata) {
$("#recent_activity_body").html(cdata);
});
</script>
{% endblock %}
......@@ -12,6 +12,48 @@
<a class="h4 mb-0 text-white text-uppercase d-none d-lg-inline-block" href="/administration/users">Users</a>
{% endblock %}
{% block stats %}
<!-- Header -->
<div class="row">
<div class="col-xl-4 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Users</h5>
<span class="h2 font-weight-bold mb-0">{{ info[0] }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Applications</h5>
<span class="h2 font-weight-bold mb-0">{{ info[1] }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Devices</h5>
<span class="h2 font-weight-bold mb-0">{{ info[2] }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block body %}
<!-- Page content -->
<div class="container-fluid mt--7">
......@@ -50,36 +92,12 @@
{% endfor %}
</tbody>
</table>
<center><a href="javascript:void(0);" onclick="return table_load_more();">Load more</a></center>
{% endif %}
</div>
<div class="card-footer py-4">
<nav aria-label="...">
<ul class="pagination justify-content-end mb-0">
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1">
<i class="fas fa-angle-left"></i>
<span class="sr-only">Previous</span>
</a>
</li>
<li class="page-item active">
<a class="page-link" href="#">1</a>
</li>
<li class="page-item">
<a class="page-link" href="#">2 <span class="sr-only">(current)</span></a>
</li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item">
<a class="page-link" href="#">
<i class="fas fa-angle-right"></i>
<span class="sr-only">Next</span>
</a>
</li>
</ul>
</nav>
</div>
<div class="card-body">
<div class="col-lg-4">
<a href="/administration/new-user"><button class="btn btn-primary" type="submit">New User</button></a>
<a href="/administration/users/new-user"><button class="btn btn-primary" type="submit">New User</button></a>
</div>
</div>
......@@ -91,17 +109,32 @@
{% block script %}
<script type="text/javascript">
var next_page = 2;
function users_update() {
$.ajax({
url:"/administration/users/table-filter/1?name="+$("#filter_name").val(),
url:"/administration/users/table/1?name="+$("#filter_name").val(),
type:"get",
success: function(data) {
data = eval(data);
$("#users_body").empty();
data.forEach(function (entry) {
str = "<tr onclick=window.location=\"/administration/users/"+entry[0]+"\"><td>"+entry[0]+"</td>"+"<td>"+entry[1]+"</td></tr>";
str = "<tr onclick=window.location=\"/administration/users/"+entry[0]+"\"><th>"+entry[0]+"</th>"+"<th>"+entry[1]+"</th></tr>";
$("#users_body").append(unescape(str));
});
}
});
}
function table_load_more() {
$.ajax({
url:"/administration/users/table/"+next_page+"?name="+$("#filter_name").val(),
type:"get",
success: function(data) {
data = eval(data);
data.forEach(function (entry) {
str = "<tr onclick=window.location=\"/administration/users/"+entry[0]+"\"><th>"+entry[0]+"</th>"+"<th>"+entry[1]+"</th></tr>";
$("#users_body").append(unescape(str));
});
next_page++;
}
});
}
......
......@@ -36,51 +36,36 @@ def index():
info = [created_apps, active_devices, total_activity, last_activity]
return render_template('new/public/dashboard.html', info=info)
else:
return render_template('new/public/login.html', users_signup=app.config['USERS_SIGNUP'])
return redirect(url_for('login'))
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'GET':
if 'role' in session and session['role'] == 'admin':
return render_template('old/admin/signup.html', users_signup=app.config['USERS_SIGNUP'])
else:
if app.config['USERS_SIGNUP']:
return render_template('new/public/register.html', users_signup=app.config['USERS_SIGNUP'])
else:
return redirect(url_for('index', users_signup=app.config['USERS_SIGNUP']))
else:
if app.config['USERS_SIGNUP'] or ('role' in session and session['role'] == 'admin'):
if app.config['USERS_SIGNUP']:
if request.method == 'GET':
return render_template('new/public/register.html')
elif request.method == 'POST':
username = request.form['username']
password = request.form['password'].encode('utf-8')
if (username == '' or password == ''):
flash('Username or password fields cannot be empty', 'danger')
return redirect(url_for('register', users_signup=app.config['USERS_SIGNUP']))
return redirect(request.url)
elif (len(password) < 8):
flash('Password length must be at least 8 characters.', 'danger')
return redirect(url_for('register', users_signup=app.config['USERS_SIGNUP']))
return redirect(request.url)
else:
role = 'user'
if 'role' in request.form and request.form['role'] == 'administrator':
role = 'admin'
res = ud.create(username, password, role)
res = ud.create(username, password, 'user')
if (not res[0]):
flash('Error: {}'.format(res[1]), 'danger')
return redirect(request.url)
else:
session['name'] = username
flash('User successfully created.', 'success')
session['role'] = 'user'
return redirect(url_for('index'))
else:
return redirect(url_for('login'))
if 'role' in session and session['role'] == 'admin':
return redirect(url_for('administration'))
else:
return redirect(url_for('index'))
else:
return redirect(url_for('index'))
@app.route('/login', methods=['GET', 'POST'])
......@@ -121,7 +106,7 @@ def applications():
return render_template('new/public/applications.html', apps=apps[1])
else:
return redirect(url_for('login', users_signup=app.config['USERS_SIGNUP']))
return redirect(url_for('login'))
@app.route('/application/<appkey>')
......@@ -133,7 +118,7 @@ def application(appkey):
return render_template('new/public/application.html', app=ap, devs=devs)
else:
return redirect(url_for('login', users_signup=app.config['USERS_SIGNUP']))
return redirect(url_for('login'))
@app.route('/new-application', methods=['GET', 'POST'])
......@@ -168,7 +153,7 @@ def application_create():
return redirect(url_for('applications'))
else:
return redirect(url_for('login', users_signup=app.config['USERS_SIGNUP']))
return redirect(url_for('login'))
@app.route('/application/<appkey>/delete')
......@@ -705,7 +690,7 @@ def user_delete():
def settings():
if request.method == 'GET':
if session['role'] == 'admin':
return render_template('old/admin/settings.html', username=session['name'], users_signup=app.config['USERS_SIGNUP'])
return render_template('old/admin/settings.html', username=session['name'])
else:
return render_template('old/public/settings.html', username=session['name'])
else:
......
......@@ -14,6 +14,7 @@ import app.dao.misc.misc as md
#import app.helpers.misc as misc
from app.helpers.misc import restricted
import app.helpers.misc as misc
#import binascii
......@@ -43,30 +44,90 @@ def administration():
@app.route('/administration/users')
@restricted(access_level='admin')
def administration_users():
user_cnt = ud.get_count()[1][0]
apps_cnt = ad.get_count()[1][0]
devs_cnt = dd.get_count_all()[1][0]
info = [user_cnt, apps_cnt, devs_cnt]
cur_pg = 1
users = ud.get_range([MAX_PG_ENTRIES_USERS, (cur_pg-1)*MAX_PG_ENTRIES_USERS])[1]
return render_template('new/admin/users.html', users=users)
return render_template('new/admin/users.html', users=users, info=info)
@app.route('/administration/users/<name>')
@restricted(access_level='admin')
def administration_users_user(name):
cur_pg = 1
users = ud.get_range([MAX_PG_ENTRIES_USERS, (cur_pg-1)*MAX_PG_ENTRIES_USERS])[1]
created_apps = ad.get_count_by_user(name)[1][0]
active_devices = dd.get_count_by_user(name)
total_activity = md.get_user_data_count(name)[1][0]
last_activity = md.get_user_data_count_per_day(name)[1][0]
info = [created_apps, active_devices, total_activity, last_activity]
return render_template('new/admin/user.html', users=users)
return render_template('new/admin/user-dashboard.html', info=info, user=name)
@app.route('/administration/users/table-<option>/<page>')
@app.route('/administration/users/<name>/chart-update')
@restricted(access_level='admin')
def administration_users_table(option, page):
if option == 'filter':
users = ud.get_range_name(request.args.get('name'), [MAX_PG_ENTRIES_USERS, (int(page)-1)*MAX_PG_ENTRIES_USERS])[1]
elif option == 'page':
users = ud.get_range([MAX_PG_ENTRIES_USERS, (int(page)-1)*MAX_PG_ENTRIES_USERS])[1]
def administration_users_user_chart_update(name):
day_chart_values = md.get_user_data_count_per_hour_period(name, 11)[1]
day_chart_values = [x[0] for x in day_chart_values]
day_chart_labels = [misc.local_hour(x) for x in range(11,-1,-1)]
day_chart = [day_chart_labels, day_chart_values]
week_chart_values = md.get_user_data_count_per_day_period(name, 6)[1]
week_chart_values = [x[0] for x in week_chart_values]
week_chart_labels = [misc.local_weekday(x) for x in range(6,-1,-1)]
week_chart = [week_chart_labels, week_chart_values]
return "[{}, {}]".format(day_chart, week_chart)
@app.route('/administration/users/<name>/recent-activity')
@restricted(access_level='admin')
def administration_users_user_recent_activity(name):
if 'name' in session:
recent_activity = md.get_recent_activity(name)[1]
ra = ''
for r in recent_activity:
ra += '<tr><th scope="row">'+r[1]+'</th><th>'+r[2]+'</th><th>'+r[0]+'</th><th>'+str(r[3])+'</th></tr>'
return ra, 200
else:
return '', 401
@app.route('/administration/users/table/<page>')
@restricted(access_level='admin')
def administration_users_table(page):
users = ud.get_range_name(request.args.get('name'), [MAX_PG_ENTRIES_USERS, (int(page)-1)*MAX_PG_ENTRIES_USERS])[1]
users = [[u[0],u[2]] for u in users]
return str(users), 200
@app.route('/administration/users/new-user', methods=['POST', 'GET'])
@restricted(access_level='admin')
def administration_users_new_user():
if request.method == 'GET':
return render_template('new/admin/new-user.html')
elif request.method == 'POST':
username = request.form['username']
password = request.form['password'].encode('utf-8')
role = request.form['role']
if (username == '' or password == ''):
flash('Username or password fields cannot be empty', 'danger')
return redirect(request.url)
elif (len(password) < 8):
flash('Password length must be at least 8 characters.', 'danger')
return redirect(request.url)
else:
res = ud.create(username, password, role)
if (not res[0]):
flash('Error: {}'.format(res[1]), 'danger')
return redirect(request.url)
else:
return redirect(url_for('administration/users', name=username))
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment