mirror of https://github.com/logos-co/open-law.git
access_tree/
This commit is contained in:
parent
eaebcc9b86
commit
039d9b8fea
|
@ -3,7 +3,7 @@
|
|||
class="fixed top-0 left-0 right-0 z-[150] hidden w-full p-4 overflow-x-hidden overflow-y-auto md:inset-0 h-[calc(100%-1rem)] max-h-full">
|
||||
<div class="relative w-full max-w-2xl max-h-full">
|
||||
<!-- Modal content -->
|
||||
<form action="{{ url_for('permission.set') }}" method="post" class="relative bg-white rounded-lg shadow dark:bg-gray-700">
|
||||
<form action="{{ url_for('permission.set_permissions') }}" method="post" class="relative bg-white rounded-lg shadow dark:bg-gray-700">
|
||||
{{ form_hidden_tag() }}
|
||||
<input type="hidden" name="book_id" id="permission_modal_book_id"/>
|
||||
<input type="hidden" name="user_id" id="permission_modal_user_id"/>
|
||||
|
@ -23,7 +23,13 @@
|
|||
<ul class="ml-6">
|
||||
<li>
|
||||
<div class="flex items-center space-x-2">
|
||||
<input type="checkbox" data-root="true" data-permission="C" data-access-to="book" data-access-to-id="{{ book.id }}" class="w-4 h-4 text-purple-600 bg-purple-100 border-purple-400 rounded focus:ring-purple-500 dark:focus:ring-purple-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-purple-300 dark:border-purple-500" />
|
||||
<input
|
||||
type="checkbox"
|
||||
data-root="true"
|
||||
data-access-to="book"
|
||||
data-access-to-id="{{ book.id }}"
|
||||
class="w-4 h-4 text-purple-600 bg-purple-100 border-purple-400 rounded focus:ring-purple-500 dark:focus:ring-purple-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-purple-300 dark:border-purple-500"
|
||||
/>
|
||||
<span class="text-center dark:text-gray-300">{{ book.label }}</span>
|
||||
</div>
|
||||
{%- for collection in book.last_version.children_collections recursive %}
|
||||
|
@ -43,7 +49,7 @@
|
|||
<ul class="ml-5">
|
||||
<li>
|
||||
<div class="flex items-center space-x-2">
|
||||
<input type="checkbox" data-access-to="sub_collection" data-access-to-id="{{ sub_collection.id }}" class="w-4 h-4 text-blue-600 bg-gray-300 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-400 dark:border-gray-600" />
|
||||
<input type="checkbox" data-access-to="collection" data-access-to-id="{{ sub_collection.id }}" class="w-4 h-4 text-blue-600 bg-gray-300 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-400 dark:border-gray-600" />
|
||||
<span class="text-center dark:text-gray-300">{{ sub_collection.label }}</span>
|
||||
</div>
|
||||
{% for section in sub_collection.sections %}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
class="fixed top-0 left-0 right-0 z-[150] hidden w-full p-4 overflow-x-hidden overflow-y-auto md:inset-0 h-[calc(100%-1rem)] max-h-full">
|
||||
<div class="relative w-full max-w-2xl max-h-full">
|
||||
<!-- Modal content -->
|
||||
<form action="{{ url_for('permission.set') }}" method="post" class="relative bg-white rounded-lg shadow dark:bg-gray-700">
|
||||
<form action="{{ url_for('permission.set_permissions') }}" method="post" class="relative bg-white rounded-lg shadow dark:bg-gray-700">
|
||||
{{ form_hidden_tag() }}
|
||||
<input type="hidden" name="book_id" id="permission_modal_book_id"/>
|
||||
<input type="hidden" name="user_id" id="permission_modal_user_id"/>
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
from flask import redirect, url_for, Blueprint, flash
|
||||
from flask import redirect, url_for, Blueprint, flash, request
|
||||
from flask_login import current_user
|
||||
from sqlalchemy import or_
|
||||
|
||||
from app import forms as f, models as m, db
|
||||
from app.logger import log
|
||||
|
||||
bp = Blueprint("permission", __name__, "/permission")
|
||||
bp = Blueprint("permission", __name__, url_prefix="/permission")
|
||||
|
||||
|
||||
@bp.route("/set", methods=["POST"])
|
||||
def set():
|
||||
def set_permissions():
|
||||
form: f.EditPermissionForm = f.EditPermissionForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
|
@ -37,3 +38,56 @@ def set():
|
|||
# permissions = json.loads(form.permissions.data)
|
||||
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@bp.route("/access_tree", methods=["GET"])
|
||||
def access_tree():
|
||||
user_id = request.args.get("user_id", type=int)
|
||||
book_id = request.args.get("book_id", type=int)
|
||||
if not user_id or not book_id:
|
||||
return {"message": "get parameters user_id and book_id are required"}, 404
|
||||
|
||||
user: m.User = db.session.get(m.User, user_id)
|
||||
if not user:
|
||||
return {"message": f"user with id {user_id} not found"}, 404
|
||||
book: m.Book = db.session.get(m.Book, book_id)
|
||||
if not book:
|
||||
return {"message": f"book with id {user_id} not found"}, 404
|
||||
|
||||
access_tree = {
|
||||
"book": [],
|
||||
"collection": [],
|
||||
"section": [],
|
||||
}
|
||||
|
||||
users_access_groups: list[m.AccessGroup] = list(
|
||||
set(book.list_access_groups).intersection(user.access_groups)
|
||||
)
|
||||
|
||||
if list(set(book.access_groups).intersection(users_access_groups)):
|
||||
access_tree["book"].append(book_id)
|
||||
|
||||
collections = (
|
||||
db.session.query(m.Collection).filter(
|
||||
m.Collection.version_id == book.last_version.id,
|
||||
m.Collection.is_root == False, # noqa: E712
|
||||
m.Collection.is_deleted == False, # noqa: E712
|
||||
)
|
||||
).all()
|
||||
|
||||
for collection in collections:
|
||||
if list(set(collection.access_groups).intersection(users_access_groups)):
|
||||
access_tree["collection"].append(collection.id)
|
||||
|
||||
sections = (
|
||||
db.session.query(m.Section).filter(
|
||||
m.Section.version_id == book.last_version.id,
|
||||
m.Section.is_deleted == False, # noqa: E712
|
||||
)
|
||||
).all()
|
||||
|
||||
for section in sections:
|
||||
if list(set(section.access_groups).intersection(users_access_groups)):
|
||||
access_tree["section"].append(section.id)
|
||||
|
||||
return {"access_tree": access_tree}
|
||||
|
|
|
@ -59,7 +59,6 @@ const handleCheckboxClick = (checkbox: HTMLInputElement) => {
|
|||
export const initCheckBoxTree = () => {
|
||||
const permissionsJSON: Permissions = {
|
||||
book: [],
|
||||
sub_collection: [],
|
||||
collection: [],
|
||||
section: [],
|
||||
};
|
||||
|
|
|
@ -30,6 +30,7 @@ import {slashSearch} from './slashSearch';
|
|||
import {editInterpretations} from './editInterpretations';
|
||||
import {deleteInterpretation} from './deleteInterpretation';
|
||||
import {indeterminateInputs} from './indeterminateInputs';
|
||||
import {initRefreshAccessLevelTree} from './refreshAccessLevelTree';
|
||||
|
||||
initQuillReadOnly();
|
||||
initBooks();
|
||||
|
@ -63,3 +64,4 @@ slashSearch();
|
|||
editInterpretations();
|
||||
deleteInterpretation();
|
||||
indeterminateInputs();
|
||||
initRefreshAccessLevelTree();
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
const refreshAccessLevelTree = async (userId: string, bookId: string) => {
|
||||
const urlParams = new URLSearchParams({
|
||||
user_id: userId,
|
||||
book_id: bookId,
|
||||
});
|
||||
const res = await fetch('/permission/access_tree?' + urlParams);
|
||||
const json = await res.json();
|
||||
|
||||
Object.entries(json.access_tree).map(([key, ids]: [string, number[]]) => {
|
||||
const checkboxes = document.querySelectorAll(
|
||||
`input[type=checkbox][data-access-to=${key}]`,
|
||||
);
|
||||
|
||||
checkboxes.forEach((element: HTMLInputElement) => {
|
||||
const id = parseInt(element.getAttribute('data-access-to-id'));
|
||||
if (ids.includes(id)) {
|
||||
element.checked = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export function initRefreshAccessLevelTree() {
|
||||
const editPermissionsBtns = document.querySelectorAll(
|
||||
'.edit-permissions-btn',
|
||||
);
|
||||
|
||||
editPermissionsBtns.forEach(element => {
|
||||
const userId = element.getAttribute('data-user-id');
|
||||
const bookId = element.getAttribute('data-book-id');
|
||||
element.addEventListener('click', () => {
|
||||
refreshAccessLevelTree(userId, bookId);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -257,3 +257,33 @@ def test_moderator_access_to_entire_book(client):
|
|||
)
|
||||
assert b"You do not have permission" not in response.data
|
||||
assert b"Success!" in response.data
|
||||
|
||||
|
||||
def test_editor_access_tree_entire_book(client):
|
||||
login(client)
|
||||
book = create_book(client)
|
||||
collection_1, _ = create_collection(client, book.id)
|
||||
collection_2, _ = create_collection(client, book.id)
|
||||
|
||||
editor = m.User(username="editor", password="editor").save()
|
||||
response: Response = client.post(
|
||||
f"/book/{book.id}/add_contributor",
|
||||
data=dict(user_id=editor.id, role=m.BookContributor.Roles.EDITOR),
|
||||
follow_redirects=True,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert b"Contributor was added!" in response.data
|
||||
|
||||
response: Response = client.get(
|
||||
f"/permission/access_tree?user_id={editor.id}&book_id={book.id}",
|
||||
follow_redirects=True,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
json = response.json
|
||||
access_tree = json.get("access_tree")
|
||||
assert access_tree
|
||||
assert book.id in access_tree.get("book")
|
||||
collections_ids = access_tree.get("collection")
|
||||
assert collections_ids
|
||||
assert collection_1.id in collections_ids
|
||||
assert collection_2.id in collections_ids
|
||||
|
|
Loading…
Reference in New Issue