Files
inventory-app/inventory-app/api.py
2024-10-31 21:20:13 +02:00

127 lines
4.1 KiB
Python

import os
import re
import const
import time
import threading
from datetime import datetime, timedelta
from functools import wraps
from pymongo import MongoClient
from flask import Blueprint, abort, g, make_response, redirect, render_template, request, jsonify
from common import CustomForm, build_query, flatten, format_name, slack_post, User
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("/users")
@check_api_key
def view_users():
resp = g.users
print(resp)
return jsonify(resp)
@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"groups requested are: {request_groups}")
print(f"found users: {g.users}")
keys = []
for u in g.users:
for group in u.groups:
if group in request_groups:
keys.append(u.username)
break
print(f"keys are {keys}")
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"found tokens are: {fl}")
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")