slimming doorboy admin methods
- enable/disable unused and broken, edit is good enough - admin use-case last many years has only been 'when has x' - can be expanded to 'who at x time' - current was broken anyway
This commit is contained in:
@@ -1,16 +1,13 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import const
|
||||
import pytz
|
||||
from bson.objectid import ObjectId
|
||||
from common import User
|
||||
from dateutil.parser import ParserError, parse
|
||||
from flask import Blueprint, abort, g, redirect, render_template, request
|
||||
from flask_wtf import FlaskForm
|
||||
from oidc import login_required, read_user
|
||||
from pymongo import MongoClient
|
||||
from wtforms import (BooleanField, IntegerField, SelectField, StringField,
|
||||
validators)
|
||||
from wtforms import BooleanField, IntegerField, SelectField, StringField, validators
|
||||
from wtforms.validators import DataRequired
|
||||
|
||||
page_doorboy = Blueprint("doorboy", __name__)
|
||||
@@ -41,48 +38,6 @@ def view_doorboy_claim(event_id):
|
||||
|
||||
return redirect("/m/doorboy")
|
||||
|
||||
|
||||
|
||||
@page_doorboy.route("/m/doorboy/<token_id>/disable")
|
||||
@login_required
|
||||
def view_doorboy_disable(token_id):
|
||||
user = read_user()
|
||||
db.inventory.update_one({
|
||||
"component": "doorboy",
|
||||
"type": "token",
|
||||
"_id": ObjectId(token_id),
|
||||
"inventory.owner.username": user["username"]
|
||||
}, {
|
||||
"$set": {
|
||||
"token.disabled": datetime.utcnow()
|
||||
},
|
||||
"$unset": {
|
||||
"token.enabled": ""
|
||||
}
|
||||
|
||||
})
|
||||
return redirect("/m/doorboy")
|
||||
|
||||
@page_doorboy.route("/m/doorboy/<token_id>/enable")
|
||||
@login_required
|
||||
def view_doorboy_enable(token_id):
|
||||
user = read_user()
|
||||
db.inventory.update_one({
|
||||
"component": "doorboy",
|
||||
"type": "token",
|
||||
"_id": ObjectId(token_id),
|
||||
"inventory.owner.username": user["username"]
|
||||
}, {
|
||||
"$set": {
|
||||
"token.enabled": datetime.utcnow(),
|
||||
},
|
||||
"$unset": {
|
||||
"token.disabled": ""
|
||||
}
|
||||
})
|
||||
return redirect("/m/doorboy")
|
||||
|
||||
|
||||
class TokenEditForm(FlaskForm):
|
||||
comment = StringField("Comment")
|
||||
enabled = BooleanField("Enabled")
|
||||
@@ -148,6 +103,7 @@ def view_doorboy_hold():
|
||||
})
|
||||
return redirect("/m/doorboy")
|
||||
|
||||
# Writes open event to log, which is picked up by doorboy-proxy.
|
||||
@page_doorboy.route("/m/doorboy/<door>/open")
|
||||
@login_required
|
||||
def view_doorboy_open(door):
|
||||
@@ -182,14 +138,9 @@ def view_doorboy_open(door):
|
||||
def view_doorboy():
|
||||
user = read_user()
|
||||
workshop_access = "k-space:workshop" in g.users_lookup.get(user["username"], User()).groups
|
||||
# latest_events = db.eventlog.find({"component": "doorboy", "type":"open-door"}).sort([("timestamp", -1)]).limit(10);
|
||||
latest_swipes = db.inventory.find({"component": "doorboy", "type":"token"}).sort([("last_seen", -1)]).limit(10);
|
||||
return render_template("doorboy.html", **locals())
|
||||
|
||||
@page_doorboy.route("/m/doorboy/user/<username>/cards")
|
||||
@login_required(groups=["k-space:board", "k-space:kubernetes:admins"])
|
||||
def view_user_cards(username):
|
||||
return view_user_cards_inner(username)
|
||||
latest_swipes = db.inventory.find({"component": "doorboy", "type":"token"}).sort([("last_seen", -1)]).limit(10)
|
||||
return render_template("doorboy.html", **locals())
|
||||
|
||||
@page_doorboy.route("/m/doorboy/me")
|
||||
@login_required
|
||||
@@ -210,71 +161,9 @@ def view_user_cards_inner(username):
|
||||
}).sort([("last_seen", -1)])
|
||||
return render_template("doorboy_user.html", **locals())
|
||||
|
||||
@page_doorboy.route("/m/doorboy/admin")
|
||||
#TODO: only returns UID opens, not web or slack
|
||||
@page_doorboy.route("/m/doorboy/log/<username>")
|
||||
@login_required(groups=["k-space:board", "k-space:kubernetes: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"},
|
||||
{"old_display_name": "$inventory.owner.display_name"},
|
||||
{"old_foreign_id": "$inventory.owner.foreign_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 g.users if not user_keyfobs.get(u.username)]
|
||||
no_keyfobs = list(filter(lambda u : u.user_type == "person", no_keyfobs))
|
||||
last_seen = {key : max(datetime_handle(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 i : datetime_handle(i[1]), reverse=True))
|
||||
return render_template("doorboy_admin.html", **locals())
|
||||
|
||||
def datetime_handle(item):
|
||||
if not item:
|
||||
dt = datetime.min
|
||||
elif type(item) is str:
|
||||
try:
|
||||
dt = parse(item)
|
||||
except ParserError as e:
|
||||
print(e)
|
||||
dt = datetime.min
|
||||
elif type(item) is datetime:
|
||||
dt = item
|
||||
else:
|
||||
dt = datetime.min
|
||||
|
||||
try:
|
||||
dt = pytz.UTC.localize(dt)
|
||||
except ValueError:
|
||||
pass
|
||||
return dt
|
||||
|
||||
@page_doorboy.route("/m/doorboy/swipes")
|
||||
@login_required
|
||||
def view_doorboy_events():
|
||||
user = read_user()
|
||||
latest_events = db.eventlog.find({"component": "doorboy", "event":"card-swiped"}).sort([("timestamp", -1)]).limit(500);
|
||||
return render_template("doorboy.html", **locals())
|
||||
|
||||
|
||||
@page_doorboy.route("/m/doorboy/<token_id>/events")
|
||||
@login_required
|
||||
def view_doorboy_token_events(token_id):
|
||||
user = read_user()
|
||||
token = db.inventory.find_one({"_id": ObjectId(token_id)})
|
||||
latest_events = db.eventlog.find({"component": "doorboy", "event":"card-swiped", "token.uid_hash": token.get("token").get("uid_hash")}).sort([("timestamp", -1)])
|
||||
return render_template("doorboy.html", **locals())
|
||||
def view_user_events(username):
|
||||
latest_events = db.eventlog.find({"component": "doorboy", "inventory.owner_id": username}).sort([("timestamp", -1)])
|
||||
return render_template("doorboy_log.html", latest_events=latest_events)
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
{% 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">
|
||||
<a href="/m/doorboy/user/{{u}}/cards">
|
||||
<i class="material-icons tiny">person</i>
|
||||
{{u | display_name}}
|
||||
</a>
|
||||
<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>
|
||||
<div class="collapsible-body collapsible-collection">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Comment</th>
|
||||
<th>Hash tail</th>
|
||||
<th>Old ownership info</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for c in orphaned_keyfobs %}
|
||||
<tr>
|
||||
<td>{{c.comment or "unnamed"}}</td>
|
||||
<td><a href="/m/doorboy/{{ c._id }}/events">{{ c.uid_hash[-6:] }}</a></td>
|
||||
<td>
|
||||
{{c.old_display_name}}
|
||||
{% if c.old_foreign_id %}
|
||||
({{c.old_foreign_id}})
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tbody>
|
||||
</table>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
.collapsible-collection {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
29
inventory-app/templates/doorboy_log.html
Normal file
29
inventory-app/templates/doorboy_log.html
Normal file
@@ -0,0 +1,29 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h3>This page only shows UID opens!</h3>
|
||||
<p>Does not include Slack opens, Web opens (via Doorboy/Inventory). Formats need to be unified. <b>Use #door-log Slack channel Ctrl-f instead!</b></p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Approved</th>
|
||||
<th>Timestamp</th>
|
||||
<th>Door</th>
|
||||
<th>Who (UID hash)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for o in latest_events %}
|
||||
<tr>
|
||||
<td>{% if o.approved %}<i class="material-icons">check_circle</i>{% else %}no{% endif %}</td>
|
||||
<td>{{ o.timestamp | timeago }}</td>
|
||||
<td>{{ o.door }}</td>
|
||||
<td>{{ o.inventory.owner_id }} (<a href="/m/doorboy/{{ o._id }}/events">{{ o.token.uid_hash[-6:] }})</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user