Add doorboy admin view
All checks were successful
ci/woodpecker/manual/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/manual/woodpecker Pipeline was successful
This commit is contained in:
parent
4b79a5e353
commit
73409d175a
@ -9,7 +9,7 @@ from wtforms import StringField, IntegerField, SelectField, BooleanField, DateTi
|
|||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
import const
|
import const
|
||||||
from common import spam, users_lookup, User
|
from common import spam, users_lookup, users, User
|
||||||
from oidc import login_required, read_user
|
from oidc import login_required, read_user
|
||||||
|
|
||||||
page_doorboy = Blueprint("doorboy", __name__)
|
page_doorboy = Blueprint("doorboy", __name__)
|
||||||
@ -194,6 +194,35 @@ def view_doorboy():
|
|||||||
latest_swipes = db.inventory.find({"component": "doorboy", "type":"token"}).sort([("last_seen", -1)]).limit(10);
|
latest_swipes = db.inventory.find({"component": "doorboy", "type":"token"}).sort([("last_seen", -1)]).limit(10);
|
||||||
return render_template("doorboy.html", **locals())
|
return render_template("doorboy.html", **locals())
|
||||||
|
|
||||||
|
@page_doorboy.route("/m/doorboy/admin")
|
||||||
|
@login_required(groups=["k-space:admins"])
|
||||||
|
def view_doorboy_admin():
|
||||||
|
results = db.inventory.aggregate([
|
||||||
|
{ "$match": {"component": "doorboy", "type": "token"} },
|
||||||
|
{
|
||||||
|
"$group": {
|
||||||
|
"_id": "$inventory.owner.username",
|
||||||
|
"cards": {
|
||||||
|
"$push" : {"$mergeObjects": [
|
||||||
|
"$token",
|
||||||
|
{"last_seen": "$last_seen"},
|
||||||
|
{"_id": "$_id"}
|
||||||
|
]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ "$sort": { "_id" : 1 } }
|
||||||
|
])
|
||||||
|
user_keyfobs = {r["_id"] : r["cards"] for r in results}
|
||||||
|
|
||||||
|
orphaned_keyfobs = user_keyfobs.pop(None)
|
||||||
|
no_keyfobs = [u for u in users if not user_keyfobs.get(u.username)]
|
||||||
|
last_seen = {key : max(card.get("last_seen") for card in value) for key, value in user_keyfobs.items()}
|
||||||
|
|
||||||
|
orphaned_keyfobs = sorted(orphaned_keyfobs, key = lambda o : (not bool(o.get("comment")), o.get("comment", "")))
|
||||||
|
no_keyfobs = sorted(no_keyfobs, key = lambda u : u.display_name or u.username)
|
||||||
|
last_seen = dict(sorted(last_seen.items(), key = lambda item: item[1], reverse=True))
|
||||||
|
return render_template("doorboy_admin.html", **locals())
|
||||||
|
|
||||||
@page_doorboy.route("/m/doorboy/swipes")
|
@page_doorboy.route("/m/doorboy/swipes")
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -99,6 +99,9 @@ body {
|
|||||||
|
|
||||||
var elems = document.querySelectorAll('.materialboxed');
|
var elems = document.querySelectorAll('.materialboxed');
|
||||||
var instances = M.Materialbox.init(elems, {});
|
var instances = M.Materialbox.init(elems, {});
|
||||||
|
|
||||||
|
var elems = document.querySelectorAll('.collapsible.expandable');
|
||||||
|
var instances = M.Collapsible.init(elems, {accordion: false});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
65
inventory-app/templates/doorboy_admin.html
Normal file
65
inventory-app/templates/doorboy_admin.html
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<ul class="collapsible expandable">
|
||||||
|
<li class="">
|
||||||
|
<div class="collapsible-header">
|
||||||
|
<i class="material-icons">access_time</i>Last seen
|
||||||
|
<div style="margin-left: auto;">
|
||||||
|
{{last_seen | length}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul class="collapsible-body collection collapsible-collection">
|
||||||
|
{% for u, t in last_seen.items() %}
|
||||||
|
<li class="collection-item">
|
||||||
|
<i class="material-icons tiny">person</i>
|
||||||
|
{{u | display_name}}
|
||||||
|
<div class="secondary-content black-text">
|
||||||
|
<i class="material-icons tiny">access_time</i>
|
||||||
|
{{t | timeago}}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="red lighten-3 collapsible-header">
|
||||||
|
<i class="material-icons">error_outline</i>No keyfobs enrolled
|
||||||
|
<div style="margin-left: auto;">
|
||||||
|
{{no_keyfobs | length}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="collapsible-body collection collapsible-collection">
|
||||||
|
{% for u in no_keyfobs %}
|
||||||
|
<div class="collection-item">{{u.display_name or u.username}}</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="red lighten-3 collapsible-header">
|
||||||
|
<i class="material-icons">error</i>Orphaned keyfobs
|
||||||
|
<div style="margin-left: auto;">
|
||||||
|
{{orphaned_keyfobs | length}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul class="collapsible-body collection collapsible-collection">
|
||||||
|
{% for c in orphaned_keyfobs %}
|
||||||
|
<li class="collection-item">
|
||||||
|
{{c.comment or "unnamed"}}
|
||||||
|
<div class="secondary-content">
|
||||||
|
<a href="/m/doorboy/{{ c._id }}/events">{{ c.uid_hash[-6:] }}</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.collapsible-collection {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user