Files
inventory-app/inventory-app/api.py
rasmus 75e9d1ceb8 cleanup unused endpoints
rm /users - not used by any API user
rm /audit - replaced by visibility state few commits ago
2025-06-02 18:12:28 +03:00

118 lines
3.8 KiB
Python

import re
import const
import time
import threading
from datetime import datetime
from functools import wraps
from pymongo import MongoClient
from flask import Blueprint, g, request, jsonify
from common import slack_post
page_api = Blueprint("api", __name__)
db = MongoClient(const.MONGO_URI).get_default_database()
def check_api_key(f):
@wraps(f)
def decorated_function(*args, **kwargs):
request_key = request.headers.get('Authorization', False)
if not request_key:
return "nope", 403
found_key = re.search(r"Basic (.*)", request_key).group(1)
if not found_key or found_key != const.INVENTORY_API_KEY:
return "nope", 403
return f(*args, **kwargs)
return decorated_function
@page_api.route("/cards", methods=["POST"])
@check_api_key
def get_group_cards():
request_groups = request.json.get("groups", False)
if not request_groups:
return "must specify groups in parameter", 400
print(f"found {len(g.users)} users for groups: {request_groups}")
keys = []
for u in g.users:
for group in u.groups:
if group in request_groups:
keys.append(u.username)
break
print(f"{len(keys)} doorkeys")
flt = {
"token.uid_hash": {"$exists": True},
"inventory.owner.username": {"$in": keys}
}
prj = {
"inventory.owner": True,
"token.uid_hash": True
}
found = []
for obj in db.inventory.find(flt, prj):
found.append({"token": obj["token"]})
fl = list(found)
print(f"{len(fl)} doorkey tokens")
return jsonify(fl)
@page_api.route("/api/slack/doorboy", methods=['POST'])
def view_slack_doorboy():
begin_time = time.perf_counter()
if request.form.get("token") != const.SLACK_VERIFICATION_TOKEN:
return "Invalid token was supplied"
if request.form.get("channel_id") not in ("C01CWPF5H8W", "CDL9H8Q9W"):
return "Invalid channel was supplied"
command = request.form.get("command")
try:
door = {
"/open-all-doors": "outsidedoors",
"/open-back-door": "backdoor",
"/open-front-door": "frontdoor",
"/open-ground-door": "grounddoor",
"/open-workshop-door": "workshopdoor"
}[command]
except KeyError:
return "Invalid command was supplied"
member = None
for user in g.users:
if user.slack_id == request.form.get("user_id"):
member = user
if door == "workshopdoor":
access_group = "k-space:workshop"
else:
access_group = "k-space:floor"
approved = access_group in member.groups
doors = [door]
if door == "outsidedoors":
doors = ["backdoor", "frontdoor", "grounddoor"]
status = "Permitted" if approved else "Denied"
subject = member.display_name
threading.Thread(target=handle_slack_door_event, args=(doors, approved, member, door, status, subject)).start()
return_message = "Opening %s for %s" % (door, subject) if approved else "Permission denied"
end_time = time.perf_counter()
print(f"view_slack_doorboy done in {end_time - begin_time:.4f} seconds")
return return_message
def handle_slack_door_event(doors, approved, member, door, status, subject):
begin_time = time.perf_counter()
for d in doors:
db.eventlog.insert_one({
"method": "slack",
"approved": approved,
"duration": 5,
"component": "doorboy",
"type": "open-door",
"door": d,
"member_id": member.username,
"member": member.display_name,
"timestamp": datetime.utcnow(),
})
msg = "%s %s door access for %s via Slack bot" % (status, door, subject)
slack_post(msg, "doorboy")
end_time = time.perf_counter()
print(f"handle_slack_door_event done in {end_time - begin_time:.4f} seconds")