forked from Github-Mirrors/canaille
Table search implementation
This commit is contained in:
parent
fbf449edd6
commit
46a346a0d0
17 changed files with 173 additions and 6 deletions
|
@ -47,7 +47,11 @@ class TableForm(FlaskForm):
|
|||
def __init__(self, cls=None, page_size=25, filter=None, **kwargs):
|
||||
filter = filter or {}
|
||||
super().__init__(**kwargs)
|
||||
self.items = cls.query(**filter)
|
||||
if self.query.data:
|
||||
self.items = cls.fuzzy(self.query.data, **filter)
|
||||
else:
|
||||
self.items = cls.query(**filter)
|
||||
|
||||
self.page_size = page_size
|
||||
self.nb_items = len(self.items)
|
||||
self.page_max = max(1, math.ceil(self.nb_items / self.page_size))
|
||||
|
@ -56,6 +60,7 @@ class TableForm(FlaskForm):
|
|||
self.items_slice = self.items[first_item:last_item]
|
||||
|
||||
page = wtforms.IntegerField(default=1)
|
||||
query = wtforms.StringField(default="")
|
||||
|
||||
def validate_page(self, field):
|
||||
if field.data < 1 or field.data > self.page_max:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{% extends theme('base.html') %}
|
||||
{% import "macro/table.html" as table %}
|
||||
|
||||
{% block content %}
|
||||
<div class="ui segment">
|
||||
|
@ -11,6 +12,9 @@
|
|||
{% trans %}Groups{% endtrans %}
|
||||
</div>
|
||||
</h2>
|
||||
<div class="ui attached segment">
|
||||
{{ table.search(table_form) }}
|
||||
</div>
|
||||
{% include "partial/groups.html" %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
{% macro search(form) %}
|
||||
<form id="search" action="{{ url_for(request.url_rule.endpoint, **request.view_args) }}" method="POST" class="ui form">
|
||||
{{ form.hidden_tag() if form.hidden_tag }}
|
||||
<input type="hidden" name="page" value="{{ form.page.data }}">
|
||||
<div class="ui fluid action input">
|
||||
<input type="search" placeholder="{{ _("Search…") }}" name="{{ form.query.name }}" value="{{ form.query.data }}">
|
||||
<button type="submit" class="ui icon button" title="{{ _("Search") }}">
|
||||
<i class="search icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro pagination(form) %}
|
||||
<form id="pagination" action="{{ url_for(request.url_rule.endpoint, **request.view_args) }}" method="POST" class="ui form">
|
||||
{{ form.hidden_tag() if form.hidden_tag }}
|
||||
<input type="hidden" name="query" value="{{ form.query.data }}">
|
||||
<div class="ui right floated stackable buttons">
|
||||
<span class="icon disabled ui button">
|
||||
{% trans %}Page{% endtrans %}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
{% extends theme('base.html') %}
|
||||
{% import "macro/table.html" as table %}
|
||||
|
||||
{% block script %}
|
||||
<script src="/static/js/users.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="ui attached segment">
|
||||
{{ table.search(table_form) }}
|
||||
</div>
|
||||
{% include "partial/oidc/admin/authorization_list.html" %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{% extends theme('base.html') %}
|
||||
{% import "macro/table.html" as table %}
|
||||
|
||||
{% block script %}
|
||||
<script src="/static/js/users.js"></script>
|
||||
|
@ -10,5 +11,8 @@
|
|||
<a class="ui primary button" href="{{ url_for('oidc.clients.add') }}">{% trans %}Add client{% endtrans %}</a>
|
||||
</div>
|
||||
|
||||
<div class="ui attached segment">
|
||||
{{ table.search(table_form) }}
|
||||
</div>
|
||||
{% include "partial/oidc/admin/client_list.html" %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
{% extends theme('base.html') %}
|
||||
{% import "macro/table.html" as table %}
|
||||
|
||||
{% block script %}
|
||||
<script src="/static/js/users.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="ui attached segment">
|
||||
{{ table.search(table_form) }}
|
||||
</div>
|
||||
{% include "partial/oidc/admin/token_list.html" %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% import "macro/table.html" as table %}
|
||||
<table class="ui table groups">
|
||||
<table class="ui attached table groups">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% import "macro/table.html" as table %}
|
||||
<table class="ui table codes">
|
||||
<table class="ui attached table codes">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Code{% endtrans %}</th>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% import "macro/table.html" as table %}
|
||||
<table class="ui table clients">
|
||||
<table class="ui attached table clients">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% import "macro/table.html" as table %}
|
||||
<table class="ui table tokens">
|
||||
<table class="ui attached table tokens">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Token{% endtrans %}</th>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% import "macro/table.html" as table %}
|
||||
<table class="ui table users">
|
||||
<table class="ui attached table users">
|
||||
<thead>
|
||||
<tr>
|
||||
{% if user.can_read("jpegPhoto") %}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{% extends theme('base.html') %}
|
||||
{% import "macro/table.html" as table %}
|
||||
|
||||
{% block script %}
|
||||
<script src="/static/js/users.js"></script>
|
||||
|
@ -13,5 +14,8 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui attached segment">
|
||||
{{ table.search(table_form) }}
|
||||
</div>
|
||||
{% include "partial/users.html" %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -66,6 +66,21 @@ def test_client_list_bad_pages(testclient, logged_admin):
|
|||
)
|
||||
|
||||
|
||||
def test_client_list_search(testclient, logged_admin, client, other_client):
|
||||
res = testclient.get("/admin/client")
|
||||
assert "2 items" in res
|
||||
assert client.client_name in res
|
||||
assert other_client.client_name in res
|
||||
|
||||
form = res.forms["search"]
|
||||
form["query"] = "other"
|
||||
res = form.submit()
|
||||
|
||||
assert "1 items" in res
|
||||
assert other_client.client_name in res
|
||||
assert client.client_name not in res
|
||||
|
||||
|
||||
def test_client_add(testclient, logged_admin):
|
||||
res = testclient.get("/admin/client/add")
|
||||
data = {
|
||||
|
|
|
@ -64,6 +64,29 @@ def test_authorization_list_bad_pages(testclient, logged_admin):
|
|||
)
|
||||
|
||||
|
||||
def test_authorization_list_search(testclient, logged_admin, client):
|
||||
id1 = gen_salt(48)
|
||||
auth1 = AuthorizationCode(authorization_code_id=id1, client=client, subject=client)
|
||||
auth1.save()
|
||||
|
||||
id2 = gen_salt(48)
|
||||
auth2 = AuthorizationCode(authorization_code_id=id2, client=client, subject=client)
|
||||
auth2.save()
|
||||
|
||||
res = testclient.get("/admin/authorization")
|
||||
assert "2 items" in res
|
||||
assert id1 in res
|
||||
assert id2 in res
|
||||
|
||||
form = res.forms["search"]
|
||||
form["query"] = id1
|
||||
res = form.submit()
|
||||
|
||||
assert "1 items" in res
|
||||
assert id1 in res
|
||||
assert id2 not in res
|
||||
|
||||
|
||||
def test_authorizaton_view(testclient, authorization, logged_admin):
|
||||
res = testclient.get("/admin/authorization/" + authorization.authorization_code_id)
|
||||
for attr in authorization.may() + authorization.must():
|
||||
|
|
|
@ -68,6 +68,46 @@ def test_token_list_bad_pages(testclient, logged_admin):
|
|||
)
|
||||
|
||||
|
||||
def test_token_list_search(testclient, logged_admin, client):
|
||||
token1 = Token(
|
||||
token_id=gen_salt(48),
|
||||
access_token="this-token-is-ok",
|
||||
client=client,
|
||||
subject=logged_admin,
|
||||
type=None,
|
||||
refresh_token=gen_salt(48),
|
||||
scope="openid profile",
|
||||
issue_date=(datetime.datetime.now().replace(microsecond=0)),
|
||||
lifetime=3600,
|
||||
)
|
||||
token1.save()
|
||||
token2 = Token(
|
||||
token_id=gen_salt(48),
|
||||
access_token="this-token-is-valid",
|
||||
client=client,
|
||||
subject=logged_admin,
|
||||
type=None,
|
||||
refresh_token=gen_salt(48),
|
||||
scope="openid profile",
|
||||
issue_date=(datetime.datetime.now().replace(microsecond=0)),
|
||||
lifetime=3600,
|
||||
)
|
||||
token2.save()
|
||||
|
||||
res = testclient.get("/admin/token")
|
||||
assert "2 items" in res
|
||||
assert token1.token_id in res
|
||||
assert token2.token_id in res
|
||||
|
||||
form = res.forms["search"]
|
||||
form["query"] = "valid"
|
||||
res = form.submit()
|
||||
|
||||
assert "1 items" in res
|
||||
assert token2.token_id in res
|
||||
assert token1.token_id not in res
|
||||
|
||||
|
||||
def test_token_view(testclient, token, logged_admin):
|
||||
res = testclient.get("/admin/token/" + token.token_id)
|
||||
assert token.access_token in res.text
|
||||
|
|
|
@ -45,6 +45,21 @@ def test_group_list_bad_pages(testclient, logged_admin):
|
|||
)
|
||||
|
||||
|
||||
def test_group_list_search(testclient, logged_admin, foo_group, bar_group):
|
||||
res = testclient.get("/groups")
|
||||
assert "2 items" in res
|
||||
assert foo_group.name in res
|
||||
assert bar_group.name in res
|
||||
|
||||
form = res.forms["search"]
|
||||
form["query"] = "oo"
|
||||
res = form.submit()
|
||||
|
||||
assert "1 items" in res, res.text
|
||||
assert foo_group.name in res
|
||||
assert bar_group.name not in res
|
||||
|
||||
|
||||
def test_set_groups(app, user, foo_group, bar_group):
|
||||
foo_dns = {m.dn for m in foo_group.get_members()}
|
||||
assert user.dn in foo_dns
|
||||
|
@ -227,3 +242,23 @@ def test_user_list_bad_pages(testclient, logged_admin, foo_group):
|
|||
testclient.post(
|
||||
"/groups/foo", {"csrf_token": form["csrf_token"], "page": "-1"}, status=404
|
||||
)
|
||||
|
||||
|
||||
def test_user_list_search(testclient, logged_admin, foo_group, user, moderator):
|
||||
foo_group.add_member(logged_admin)
|
||||
foo_group.add_member(moderator)
|
||||
foo_group.save()
|
||||
|
||||
res = testclient.get("/groups/foo")
|
||||
assert "3 items" in res
|
||||
assert user.name in res
|
||||
assert moderator.name in res
|
||||
|
||||
form = res.forms["search"]
|
||||
form["query"] = "ohn"
|
||||
res = form.submit()
|
||||
|
||||
assert "1 items" in res
|
||||
assert user.name in res
|
||||
assert logged_admin.name not in res
|
||||
assert moderator.name not in res
|
||||
|
|
|
@ -40,6 +40,21 @@ def test_user_list_bad_pages(testclient, logged_admin):
|
|||
)
|
||||
|
||||
|
||||
def test_user_list_search(testclient, logged_admin, user, moderator):
|
||||
res = testclient.get("/users")
|
||||
assert "3 items" in res
|
||||
assert moderator.name in res
|
||||
assert user.name in res
|
||||
|
||||
form = res.forms["search"]
|
||||
form["query"] = "Jack"
|
||||
res = form.submit()
|
||||
|
||||
assert "1 items" in res, res.text
|
||||
assert moderator.name in res
|
||||
assert user.name not in res
|
||||
|
||||
|
||||
def test_edition_permission(
|
||||
testclient,
|
||||
slapd_server,
|
||||
|
|
Loading…
Reference in a new issue