rewrite user permissions panel
This commit is contained in:
parent
976ffe4551
commit
fc434f0d62
26
buckler.py
26
buckler.py
|
@ -55,11 +55,13 @@ async def index(request):
|
|||
request['session']['id'])
|
||||
if request['session']['admin']:
|
||||
apps = await conn.fetch(
|
||||
"SELECT id, name FROM app_info")
|
||||
"SELECT id, name FROM app_info ORDER BY id ASC")
|
||||
users = await conn.fetch(
|
||||
"SELECT id, username FROM user_info ORDER BY id ASC")
|
||||
user_perms = await conn.fetch(
|
||||
"SELECT user_info.id, user_info.username, app_user.app_id "
|
||||
"SELECT user_info.id, app_user.app_id "
|
||||
"FROM user_info LEFT JOIN app_user "
|
||||
"ON (user_info.id = app_user.user_id)")
|
||||
"ON (user_info.id = app_user.user_id) ")
|
||||
fido2_keys = await conn.fetch(
|
||||
"SELECT * FROM user_credential WHERE user_id = $1",
|
||||
request['session']['id'])
|
||||
|
@ -70,12 +72,18 @@ async def index(request):
|
|||
request['session']['id'])
|
||||
|
||||
if request['session']['admin']:
|
||||
users = defaultdict(lambda: {app['name']: False for app in apps})
|
||||
for user_perm in user_perms:
|
||||
index = tools.find_dict(apps, 'id', user_perm['app_id'])
|
||||
if index != -1:
|
||||
users[user_perm['username']][apps[index]['name']] = True
|
||||
users_json = json.dumps(users)
|
||||
user_perms_dict = {}
|
||||
for user in users:
|
||||
lst = [up for up in user_perms if up['id'] == user['id']]
|
||||
d = {app['id']: False for app in apps}
|
||||
for perm in lst:
|
||||
if perm['app_id'] not in d:
|
||||
continue
|
||||
d[perm['app_id']] = True
|
||||
user_perms_dict[user['id']] = d
|
||||
users_dict = {user['id']: user['username'] for user in users}
|
||||
apps_dict = {app['id']: app['name'] for app in apps}
|
||||
user_perms_json = json.dumps(user_perms_dict)
|
||||
|
||||
return render_template("index.html", request, locals())
|
||||
|
||||
|
|
33
forms.py
33
forms.py
|
@ -2,6 +2,8 @@
|
|||
"""
|
||||
Co-routines for handling various forms in Buckler.
|
||||
"""
|
||||
import json
|
||||
|
||||
from passlib.hash import argon2
|
||||
|
||||
import tools
|
||||
|
@ -26,33 +28,24 @@ async def invite_user(request):
|
|||
async def change_user_perms(request):
|
||||
"""Allows an admin to change user permissions."""
|
||||
data = await request.post()
|
||||
data = json.loads(data['perms'])
|
||||
|
||||
pluses = []
|
||||
for key, value in data.items():
|
||||
if key == 'form_name':
|
||||
continue
|
||||
username, _, app_name = key.partition('-')
|
||||
pluses.append((username, app_name))
|
||||
minuses = []
|
||||
for user_id, perms in data.items():
|
||||
for app_id, value in perms.items():
|
||||
if value: # TODO: check for TypeError
|
||||
pluses.append((int(user_id), int(app_id)))
|
||||
else:
|
||||
minuses.append((int(user_id), int(app_id)))
|
||||
|
||||
async with request.app['pool'].acquire() as conn:
|
||||
apps = await conn.fetch(
|
||||
"SELECT id, name FROM app_info")
|
||||
users = {p[0] for p in pluses}
|
||||
minuses = []
|
||||
for user in users:
|
||||
for app in apps:
|
||||
minuses.append((user, app['name']))
|
||||
minuses = [m for m in minuses if m not in pluses]
|
||||
|
||||
await conn.executemany(
|
||||
"INSERT INTO app_user (user_id, app_id) "
|
||||
"VALUES ((SELECT id FROM user_info WHERE username = $1), "
|
||||
"(SELECT id FROM app_info WHERE name = $2)) "
|
||||
"INSERT INTO app_user (user_id, app_id) VALUES ($1, $2) "
|
||||
"ON CONFLICT ON CONSTRAINT app_user_pkey DO NOTHING",
|
||||
pluses)
|
||||
await conn.executemany(
|
||||
"DELETE FROM app_user "
|
||||
"WHERE user_id = (SELECT id FROM user_info WHERE username = $1) "
|
||||
"AND app_id = (SELECT id FROM app_info WHERE name = $2)",
|
||||
"DELETE FROM app_user WHERE user_id = $1 AND app_id = $2",
|
||||
minuses)
|
||||
return {}
|
||||
|
||||
|
|
|
@ -15,44 +15,39 @@ function load() {
|
|||
}
|
||||
});
|
||||
});
|
||||
document.querySelector('#user_perm_form').addEventListener('submit', submit_user_perms);
|
||||
}
|
||||
|
||||
function perm_change(row) {
|
||||
let user_perms = users_perms[row.children[0].textContent];
|
||||
let row_perms = {};
|
||||
for (let child of row.children) {
|
||||
if (child.firstChild.type == "checkbox") {
|
||||
if (child.firstChild.checked) {
|
||||
row_perms[child.firstChild.dataset.appName] = true;
|
||||
} else {
|
||||
row_perms[child.firstChild.dataset.appName] = false;
|
||||
}
|
||||
function submit_user_perms(event) {
|
||||
event.preventDefault();
|
||||
let perms_diff = {};
|
||||
for (let input of event.target.querySelectorAll('input[type=checkbox]')) {
|
||||
let user_id = input.dataset['userId'];
|
||||
let app_id = input.dataset['appId'];
|
||||
if (input.checked != user_perms[user_id][app_id]) {
|
||||
let perms = perms_diff[user_id] || {};
|
||||
perms[app_id] = input.checked;
|
||||
perms_diff[user_id] = perms;
|
||||
}
|
||||
}
|
||||
let perms_changed = false;
|
||||
for (let app_name of Object.keys(user_perms)) {
|
||||
if (user_perms[app_name] != row_perms[app_name]) {
|
||||
perms_changed = true;
|
||||
}
|
||||
|
||||
let form_body = {
|
||||
'form_name': 'change_user_perms',
|
||||
'perms': JSON.stringify(perms_diff),
|
||||
}
|
||||
console.log("perms_changed = " + perms_changed);
|
||||
}
|
||||
let payload = [];
|
||||
for (let property in form_body) {
|
||||
let encoded_key = encodeURIComponent(property);
|
||||
let encoded_value = encodeURIComponent(form_body[property]);
|
||||
payload.push(encoded_key + '=' + encoded_value);
|
||||
}
|
||||
payload = payload.join('&');
|
||||
|
||||
function submit_user_perms(row) {
|
||||
let row_perms = {};
|
||||
for (let child of row.children) {
|
||||
if (child.firstChild.type == "checkbox") {
|
||||
if (child.firstChild.checked) {
|
||||
row_perms[child.firstChild.dataset.appName] = true;
|
||||
} else {
|
||||
row_perms[child.firstChild.dataset.appName] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(row_perms);
|
||||
fetch(window.location.pathname, {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: row_perms
|
||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
body: payload,
|
||||
}).then(function(response) {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<title>Buckler</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/buckler.css">
|
||||
<script>
|
||||
var users_perms = {{ users_json|safe }};
|
||||
var user_perms = {{ user_perms_json|safe }};
|
||||
</script>
|
||||
<script type="text/javascript" src="/static/buckler.js"></script>
|
||||
<script>window.onload = load;</script>
|
||||
|
@ -38,23 +38,23 @@
|
|||
<h3>User Permissions</h3>
|
||||
<article style="display: none;">
|
||||
<hr>
|
||||
<form method="post" enctype="application/x-www-form-urlencoded">
|
||||
<form id="user_perm_form">
|
||||
<input name="form_name" type="hidden" value="change_user_perms">
|
||||
<table id="users">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
{% for app in apps %}
|
||||
<th>{{ app['name'] }}</th>
|
||||
<th data-app-id="{{ app['id'] }}">{{ app['name'] }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for username, values in users.items() %}
|
||||
{% for user_id, values in user_perms_dict.items() %}
|
||||
<tr>
|
||||
<td>{{ username }}</td>
|
||||
{% for app_name, value in values.items() %}
|
||||
<td><input aria-label="{{ username }}-{{ app_name }}" name="{{ username }}-{{ app_name }}" data-app-name={{ app_name }} type="checkbox"{% if value %} checked{% endif %}></td>
|
||||
<td data-user-id="{{ user_id }}">{{ users_dict[user_id] }}</td>
|
||||
{% for app_id, value in values.items() %}
|
||||
<td><input aria-label="{{ users_dict[user_id] }}-{{ apps_dict[app_id] }}" data-user-id="{{ user_id }}" data-app-id="{{ app_id }}" type="checkbox"{% if value %} checked{% endif %}></td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
11
tools.py
11
tools.py
|
@ -85,14 +85,3 @@ async def validate_register(request, form):
|
|||
errors['email'].append("Email already in use.")
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
def find_dict(lst, key, value):
|
||||
"""
|
||||
Returns the index of the dictionary in the given `lst` which
|
||||
has d[`key`] == `value`.
|
||||
"""
|
||||
for i, d in enumerate(lst):
|
||||
if d[key] == value:
|
||||
return i
|
||||
return -1
|
||||
|
|
Loading…
Reference in New Issue
Block a user