rewrite user permissions panel

This commit is contained in:
iou1name 2020-11-20 19:32:32 -05:00
parent 976ffe4551
commit fc434f0d62
5 changed files with 63 additions and 78 deletions

View File

@ -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())

View File

@ -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 {}

View File

@ -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;
}
}
console.log("perms_changed = " + perms_changed);
}
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;
}
}
let form_body = {
'form_name': 'change_user_perms',
'perms': JSON.stringify(perms_diff),
}
console.log(row_perms);
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('&');
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();
});
}

View File

@ -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 %}

View File

@ -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