aboutsummaryrefslogtreecommitdiff
path: root/api/hierarchy.py
blob: 4e065eb630b18267c7980a11b3171d6c32c4ed27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
from flask import request
from auth.login_token import token_login
from db import cursor
from util import all_def, all_notdef
import valid

ranks = ["none", "user", "moderator", "admin", "bot"]


def util_two_person(func):
	'''
	! only used internally !
	func(token_id?: str, explicit_id?: str)

	This decorator doesn't check for hierarchy constraints, but does
	make sure that token_id or explicit_id are valid user_id's
	'''
	def wrapper():
		token_id = None
		explicit_id = None

		token = request.cookies.get("token") or ""
		if token: token_id = token_login(token)

		data = request.get_json()
		if data: explicit_id = data.get("id")

		if explicit_id and not valid.user_id(explicit_id): explicit_id = None

		return func(token_id, explicit_id)

	wrapper.__name__ = func.__name__
	return wrapper


def two_person(func):
	'''
	endpoint should have two parameters:
	endpoint(user_1_id: str, user_2_id: str)

	no authentication, just runs endpoint() if both token_id and
	explicit_id are present from @util_two_person.
	'''
	@util_two_person
	def wrapper(token_id, explicit_id):
		if not all_def([token_id, explicit_id]):
			return "", 400

		return func(token_id, explicit_id)

	wrapper.__name__ = func.__name__
	return wrapper


def one_person(func):
	'''
	endpoint should have two parameters:
	endpoint(user_id: str, viewer?: str)

	uses json data id with token_login id as fallback
	doesn't check for authentication
	expects that func takes these arguments: (user_id, viewer?)
	'''
	@util_two_person
	def wrapper(token_id, explicit_id):
		if all_notdef([token_id, explicit_id]):
			return "", 400

		return func(explicit_id or token_id, token_id)

	wrapper.__name__ = func.__name__
	return wrapper


def auth_required(level):
	'''
	level = "none" | "user" | "moderator" | "admin" | "bot"
	endpoint should have one parameter for the user_id of the request author:
	endpoint(user_id: str) # `user_id` can only be `None` when `level == "none"`

	@auth_required function decorator (use after @flask.Blueprint.route() decorator)
	This decorator only runs endpoint() if token_id from
	@util_two_person is not None and passes hierarchy constraints
	'''
	def decorator(func):
		@util_two_person
		def wrapper(token_id, explicit_id):
			if not token_id:
				if level == ranks[0]:
					return func(None)
				else:
					return "", 400

			user_rank_text = cursor.execute(
				"select type from users where user_id = ?", [token_id]
			).fetchone()[0]

			required_rank = ranks.index(level)
			user_rank = ranks.index(user_rank_text)
			if required_rank > user_rank: return "", 403

			return func(token_id)

		wrapper.__name__ = func.__name__
		return wrapper

	return decorator