forked from Github-Mirrors/canaille
Merge branch 'issue-12-groups' into 'master'
Create, edit and delete groups from interface (moderators only) See merge request yaal/canaille!6
This commit is contained in:
commit
f4d6e723ba
41 changed files with 768 additions and 284 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -19,3 +19,4 @@ canaille/conf/openid-configuration.json
|
||||||
canaille/conf/*.pem
|
canaille/conf/*.pem
|
||||||
canaille/conf/*.pub
|
canaille/conf/*.pub
|
||||||
canaille/conf/*.key
|
canaille/conf/*.key
|
||||||
|
.vscode
|
|
@ -12,6 +12,7 @@ import canaille.consents
|
||||||
import canaille.commands.clean
|
import canaille.commands.clean
|
||||||
import canaille.oauth
|
import canaille.oauth
|
||||||
import canaille.account
|
import canaille.account
|
||||||
|
import canaille.groups
|
||||||
import canaille.well_known
|
import canaille.well_known
|
||||||
|
|
||||||
from cryptography.hazmat.primitives import serialization as crypto_serialization
|
from cryptography.hazmat.primitives import serialization as crypto_serialization
|
||||||
|
@ -136,6 +137,7 @@ def setup_app(app):
|
||||||
config_oauth(app)
|
config_oauth(app)
|
||||||
setup_ldap_tree(app)
|
setup_ldap_tree(app)
|
||||||
app.register_blueprint(canaille.account.bp)
|
app.register_blueprint(canaille.account.bp)
|
||||||
|
app.register_blueprint(canaille.groups.bp, url_prefix="/groups")
|
||||||
app.register_blueprint(canaille.oauth.bp, url_prefix="/oauth")
|
app.register_blueprint(canaille.oauth.bp, url_prefix="/oauth")
|
||||||
app.register_blueprint(canaille.commands.clean.bp)
|
app.register_blueprint(canaille.commands.clean.bp)
|
||||||
app.register_blueprint(canaille.consents.bp, url_prefix="/consent")
|
app.register_blueprint(canaille.consents.bp, url_prefix="/consent")
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
"https://mydomain.tld/oauth/register",
|
"https://mydomain.tld/oauth/register",
|
||||||
"scopes_supported":
|
"scopes_supported":
|
||||||
["openid", "profile", "email", "address",
|
["openid", "profile", "email", "address",
|
||||||
"phone"],
|
"phone", "groups"],
|
||||||
"response_types_supported":
|
"response_types_supported":
|
||||||
["code", "token", "id_token", "code token",
|
["code", "token", "id_token", "code token",
|
||||||
"code id_token", "token id_token"],
|
"code id_token", "token id_token"],
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
"https://mydomain.tld/oauth/register",
|
"https://mydomain.tld/oauth/register",
|
||||||
"scopes_supported":
|
"scopes_supported":
|
||||||
["openid", "profile", "email", "address",
|
["openid", "profile", "email", "address",
|
||||||
"phone"],
|
"phone", "groups"],
|
||||||
"response_types_supported":
|
"response_types_supported":
|
||||||
["code", "token", "id_token", "code token",
|
["code", "token", "id_token", "code token",
|
||||||
"code id_token", "token id_token"],
|
"code id_token", "token id_token"],
|
||||||
|
|
|
@ -145,3 +145,19 @@ def profile_form(field_names):
|
||||||
render_kw={},
|
render_kw={},
|
||||||
)
|
)
|
||||||
return wtforms.form.BaseForm(fields)
|
return wtforms.form.BaseForm(fields)
|
||||||
|
|
||||||
|
|
||||||
|
class GroupForm(FlaskForm):
|
||||||
|
name = wtforms.StringField(
|
||||||
|
_("Name"),
|
||||||
|
validators=[wtforms.validators.DataRequired()],
|
||||||
|
render_kw={
|
||||||
|
"placeholder": _("group"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
def validate_name(self, field):
|
||||||
|
if Group.get(field.data):
|
||||||
|
raise wtforms.ValidationError(
|
||||||
|
_("The group '{group}' already exists").format(group=field.data)
|
||||||
|
)
|
||||||
|
|
89
canaille/groups.py
Normal file
89
canaille/groups.py
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
from flask import (
|
||||||
|
Blueprint,
|
||||||
|
render_template,
|
||||||
|
redirect,
|
||||||
|
url_for,
|
||||||
|
request,
|
||||||
|
flash,
|
||||||
|
current_app,
|
||||||
|
abort,
|
||||||
|
)
|
||||||
|
from flask_babel import gettext as _
|
||||||
|
|
||||||
|
from .flaskutils import moderator_needed
|
||||||
|
from .forms import GroupForm
|
||||||
|
from .models import Group
|
||||||
|
|
||||||
|
bp = Blueprint("groups", __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/")
|
||||||
|
@moderator_needed()
|
||||||
|
def groups(user):
|
||||||
|
groups = Group.filter(objectClass=current_app.config["LDAP"]["GROUP_CLASS"])
|
||||||
|
return render_template("groups.html", groups=groups, menuitem="groups")
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/add", methods=("GET", "POST"))
|
||||||
|
@moderator_needed()
|
||||||
|
def create_group(user):
|
||||||
|
form = GroupForm(request.form or None)
|
||||||
|
try:
|
||||||
|
if "name" in form:
|
||||||
|
del form["name"].render_kw["disabled"]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if request.form:
|
||||||
|
if not form.validate():
|
||||||
|
flash(_("Group creation failed."), "error")
|
||||||
|
else:
|
||||||
|
group = Group(objectClass=current_app.config["LDAP"]["GROUP_CLASS"])
|
||||||
|
group.member = [user.dn]
|
||||||
|
group.cn = [form.name.data]
|
||||||
|
group.save()
|
||||||
|
flash(
|
||||||
|
_("The group %(group)s has been sucessfully created", group=group.name),
|
||||||
|
"success",
|
||||||
|
)
|
||||||
|
return redirect(url_for("groups.group", groupname=group.name))
|
||||||
|
|
||||||
|
return render_template("group.html", form=form, edited_group=None, members=None)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/<groupname>", methods=("GET", "POST"))
|
||||||
|
@moderator_needed()
|
||||||
|
def group(user, groupname):
|
||||||
|
group = Group.get(groupname) or abort(404)
|
||||||
|
|
||||||
|
if request.method == "GET" or request.form.get("action") == "edit":
|
||||||
|
return edit_group(group)
|
||||||
|
|
||||||
|
if request.form.get("action") == "delete":
|
||||||
|
return delete_group(group)
|
||||||
|
|
||||||
|
abort(400)
|
||||||
|
|
||||||
|
|
||||||
|
def edit_group(group):
|
||||||
|
form = GroupForm(request.form or None, data={"name": group.name})
|
||||||
|
form["name"].render_kw["disabled"] = "true"
|
||||||
|
|
||||||
|
if request.form:
|
||||||
|
if form.validate():
|
||||||
|
group.save()
|
||||||
|
else:
|
||||||
|
flash(_("Group edition failed."), "error")
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
"group.html", form=form, edited_group=group, members=group.get_members()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_group(group):
|
||||||
|
flash(
|
||||||
|
_("The group %(group)s has been sucessfully deleted", group=group.name),
|
||||||
|
"success",
|
||||||
|
)
|
||||||
|
group.delete()
|
||||||
|
return redirect(url_for("groups.groups"))
|
|
@ -160,6 +160,11 @@ class Group(LDAPObject):
|
||||||
Group.attr_type_by_name(conn=conn)
|
Group.attr_type_by_name(conn=conn)
|
||||||
return [(group[attribute][0], group.dn) for group in groups]
|
return [(group[attribute][0], group.dn) for group in groups]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
attribute = current_app.config["LDAP"].get("GROUP_NAME_ATTRIBUTE")
|
||||||
|
return self[attribute][0]
|
||||||
|
|
||||||
def get_members(self, conn=None):
|
def get_members(self, conn=None):
|
||||||
return [User.get(dn=user_dn, conn=conn) for user_dn in self.member]
|
return [User.get(dn=user_dn, conn=conn) for user_dn in self.member]
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ CLAIMS = {
|
||||||
"email": ("at", _("Your email address.")),
|
"email": ("at", _("Your email address.")),
|
||||||
"address": ("envelope open outline", _("Your postal address.")),
|
"address": ("envelope open outline", _("Your postal address.")),
|
||||||
"phone": ("phone", _("Your phone number.")),
|
"phone": ("phone", _("Your phone number.")),
|
||||||
|
"groups": ("users", _("Groups you are belonging to")),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,8 @@ def generate_user_info(user, scope):
|
||||||
fields += ["address"]
|
fields += ["address"]
|
||||||
if "phone" in scope:
|
if "phone" in scope:
|
||||||
fields += ["phone_number", "phone_number_verified"]
|
fields += ["phone_number", "phone_number_verified"]
|
||||||
|
if "groups" in scope:
|
||||||
|
fields += ["groups"]
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
for field in fields:
|
for field in fields:
|
||||||
|
@ -69,6 +71,9 @@ def generate_user_info(user, scope):
|
||||||
data[field] = user.__getattr__(ldap_field_match)
|
data[field] = user.__getattr__(ldap_field_match)
|
||||||
if isinstance(data[field], list):
|
if isinstance(data[field], list):
|
||||||
data[field] = data[field][0]
|
data[field] = data[field][0]
|
||||||
|
if field == "groups":
|
||||||
|
group_name_attr = current_app.config["LDAP"]["GROUP_NAME_ATTRIBUTE"]
|
||||||
|
data[field] = [getattr(g, group_name_attr)[0] for g in user.groups]
|
||||||
|
|
||||||
return UserInfo(**data)
|
return UserInfo(**data)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'fomanticui.j2' as sui %}
|
{% import 'fomanticui.j2' as sui %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="ui clearing segment">
|
<div class="ui clearing segment">
|
||||||
|
@ -8,7 +7,6 @@
|
||||||
<img class="ui tiny centered image" src="/static/img/canaille-head.png" alt="{{ website_name }}">
|
<img class="ui tiny centered image" src="/static/img/canaille-head.png" alt="{{ website_name }}">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
<h2 class="ui center aligned header">
|
<h2 class="ui center aligned header">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{{ _("About canaille") }}
|
{{ _("About canaille") }}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'fomanticui.j2' as sui %}
|
{% import 'fomanticui.j2' as sui %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="loginform">
|
<div class="loginform">
|
||||||
|
@ -8,8 +7,6 @@
|
||||||
{% trans %}View a authorization{% endtrans %}
|
{% trans %}View a authorization{% endtrans %}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
|
|
||||||
<div class="ui attached clearing segment">
|
<div class="ui attached clearing segment">
|
||||||
<ul>
|
<ul>
|
||||||
{% for attr in authorization.may %}
|
{% for attr in authorization.may %}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'fomanticui.j2' as sui %}
|
{% import 'fomanticui.j2' as sui %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="loginform">
|
<div class="loginform">
|
||||||
|
@ -8,8 +7,6 @@
|
||||||
{% trans %}Add a client{% endtrans %}
|
{% trans %}Add a client{% endtrans %}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
|
|
||||||
<div class="ui attached clearing segment">
|
<div class="ui attached clearing segment">
|
||||||
{{ sui.render_form(form, _("Confirm")) }}
|
{{ sui.render_form(form, _("Confirm")) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'fomanticui.j2' as sui %}
|
{% import 'fomanticui.j2' as sui %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script src="/static/js/admin/client_edit.js"></script>
|
<script src="/static/js/admin/client_edit.js"></script>
|
||||||
|
@ -26,8 +25,6 @@
|
||||||
{% trans %}Edit a client{% endtrans %}
|
{% trans %}Edit a client{% endtrans %}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
|
|
||||||
<div class="ui attached clearing segment">
|
<div class="ui attached clearing segment">
|
||||||
<div class="ui form">
|
<div class="ui form">
|
||||||
<form id="readonly">
|
<form id="readonly">
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
<link href="/static/datatables/jquery.dataTables.min.css" rel="stylesheet">
|
<link href="/static/datatables/jquery.dataTables.min.css" rel="stylesheet">
|
||||||
|
@ -14,8 +13,6 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
|
|
||||||
<div class="ui segment">
|
<div class="ui segment">
|
||||||
<a class="ui primary button" href="{{ url_for('admin_clients.add') }}">{% trans %}Add client{% endtrans %}</a>
|
<a class="ui primary button" href="{{ url_for('admin_clients.add') }}">{% trans %}Add client{% endtrans %}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'fomanticui.j2' as sui %}
|
{% import 'fomanticui.j2' as sui %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="loginform">
|
<div class="loginform">
|
||||||
|
@ -8,8 +7,6 @@
|
||||||
{% trans %}View a token{% endtrans %}
|
{% trans %}View a token{% endtrans %}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
|
|
||||||
<div class="ui attached clearing segment">
|
<div class="ui attached clearing segment">
|
||||||
<ul>
|
<ul>
|
||||||
{% for attr in token.may %}
|
{% for attr in token.may %}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
{% import 'flask.j2' as flask %}
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
|
@ -47,6 +49,11 @@
|
||||||
<i class="users icon"></i>
|
<i class="users icon"></i>
|
||||||
{% trans %}Users{% endtrans %}
|
{% trans %}Users{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
|
<a class="item {% if menuitem == "groups" %}active{% endif %}"
|
||||||
|
href="{{ url_for('groups.groups') }}">
|
||||||
|
<i class="users cog icon"></i>
|
||||||
|
{% trans %}Groups{% endtrans %}
|
||||||
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.admin %}
|
{% if user.admin %}
|
||||||
<div class="ui dropdown item {% if menuitem == "admin" %}active{% endif %}">
|
<div class="ui dropdown item {% if menuitem == "admin" %}active{% endif %}">
|
||||||
|
@ -82,6 +89,7 @@
|
||||||
|
|
||||||
<div class="ui container">
|
<div class="ui container">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
{{ flask.messages() }}
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
<link href="/static/datatables/jquery.dataTables.min.css" rel="stylesheet">
|
<link href="/static/datatables/jquery.dataTables.min.css" rel="stylesheet">
|
||||||
|
@ -23,8 +22,6 @@
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
|
|
||||||
{% if consents %}
|
{% if consents %}
|
||||||
<div class="ui centered cards">
|
<div class="ui centered cards">
|
||||||
{% for consent in consents %}
|
{% for consent in consents %}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'fomanticui.j2' as sui %}
|
{% import 'fomanticui.j2' as sui %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="loginform">
|
<div class="loginform">
|
||||||
|
@ -13,8 +12,6 @@
|
||||||
</div>
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
|
|
||||||
<div class="ui attached message">
|
<div class="ui attached message">
|
||||||
{% trans %}
|
{% trans %}
|
||||||
It seems this is the first time you are logging here. In order to finalize your
|
It seems this is the first time you are logging here. In order to finalize your
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'fomanticui.j2' as sui %}
|
{% import 'fomanticui.j2' as sui %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="loginform">
|
<div class="loginform">
|
||||||
|
@ -13,8 +12,6 @@
|
||||||
</div>
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
|
|
||||||
<div class="ui attached message">
|
<div class="ui attached message">
|
||||||
{% trans %}
|
{% trans %}
|
||||||
After this form is sent, if the email address or the login you provided
|
After this form is sent, if the email address or the login you provided
|
||||||
|
|
87
canaille/templates/group.html
Normal file
87
canaille/templates/group.html
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% import 'fomanticui.j2' as sui %}
|
||||||
|
|
||||||
|
{% block script %}
|
||||||
|
<script src="/static/js/confirm.js"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% if edited_group %}
|
||||||
|
<div class="ui basic modal">
|
||||||
|
<div class="ui icon header">
|
||||||
|
<i class="trash alternate icon"></i>
|
||||||
|
{% trans %}Group deletion{% endtrans %}
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<p>
|
||||||
|
{% trans %}Are you sure you want to delete this group? This action is unrevokable and all the data about this group will be removed.{% endtrans %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<div class="ui inverted cancel button">{% trans %}Cancel{% endtrans %}</div>
|
||||||
|
<div class="ui inverted red approve button">{% trans %}Delete{% endtrans %}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if edited_group %}
|
||||||
|
<div class="ui segment">
|
||||||
|
<h2 class="ui header">{% trans %}Members{% endtrans %}</h2>
|
||||||
|
<ul>
|
||||||
|
{% for member in members %}
|
||||||
|
<div class="ui left icon">
|
||||||
|
<i class="user icon"></i>
|
||||||
|
<a href="{{ url_for('account.profile_edition', username=member.uid[0]) }}">{{ member.name }}</a></li>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="ui clearing segment">
|
||||||
|
<h2 class="ui center aligned header">
|
||||||
|
<div class="content">
|
||||||
|
{% if not edited_group %}
|
||||||
|
{% trans %}Group creation{% endtrans %}
|
||||||
|
{% else %}
|
||||||
|
{% trans %}Group edition{% endtrans %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sub header">
|
||||||
|
{% if not edited_group %}
|
||||||
|
{% trans %}Create a new group{% endtrans %}
|
||||||
|
{% else %}
|
||||||
|
{% trans %}Edit informations about a group{% endtrans %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<form method="POST"
|
||||||
|
id="{{ form.__class__.__name__|lower }}"
|
||||||
|
action="{{ request.url }}"
|
||||||
|
role="form"
|
||||||
|
class="ui form"
|
||||||
|
>
|
||||||
|
{{ form.hidden_tag() if form.hidden_tag }}
|
||||||
|
{{ sui.render_field(form.name) }}
|
||||||
|
{% if not edited_group %}
|
||||||
|
<p>
|
||||||
|
{% trans %}Because group cannot be empty, you will be added to the group. You can remove you later by editing your profile when you will have added other members to the group.{% endtrans %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<button type="submit" class="ui right floated primary button" name="action" value="edit">
|
||||||
|
{% if not edited_group %}
|
||||||
|
{% trans %}Create group{% endtrans %}
|
||||||
|
{% else %}
|
||||||
|
{% trans %}Submit{% endtrans %}
|
||||||
|
{% endif %}
|
||||||
|
</button>
|
||||||
|
{% if edited_group %}
|
||||||
|
<button type="submit" class="ui right floated basic negative button confirm" name="action" value="delete" id="delete">
|
||||||
|
{% trans %}Delete group{% endtrans %}
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
19
canaille/templates/groups.html
Normal file
19
canaille/templates/groups.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="ui segment">
|
||||||
|
<a class="ui primary button" href="{{ url_for('groups.create_group') }}">{% trans %}Add a group{% endtrans %}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ui segment">
|
||||||
|
<h2 class="ui header">{% trans %}Groups{% endtrans %}</h2>
|
||||||
|
<ul>
|
||||||
|
{% for group in groups %}
|
||||||
|
<div class="ui left icon">
|
||||||
|
<i class="users icon"></i>
|
||||||
|
<a href="{{ url_for('groups.group', groupname=group.name) }}">{{ group.name }}</a>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'fomanticui.j2' as sui %}
|
{% import 'fomanticui.j2' as sui %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="ui clearing segment">
|
<div class="ui clearing segment">
|
||||||
|
@ -19,8 +18,6 @@
|
||||||
<div class="sub header">{% trans %}Log-in and manage your authorizations.{% endtrans %}</div>
|
<div class="sub header">{% trans %}Log-in and manage your authorizations.{% endtrans %}</div>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
|
|
||||||
<form method="POST"
|
<form method="POST"
|
||||||
id="{{ form.id or form.__class__.__name__|lower }}"
|
id="{{ form.id or form.__class__.__name__|lower }}"
|
||||||
action="{{ request.url }}"
|
action="{{ request.url }}"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'fomanticui.j2' as sui %}
|
{% import 'fomanticui.j2' as sui %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="ui clearing segment">
|
<div class="ui clearing segment">
|
||||||
|
@ -19,8 +18,6 @@
|
||||||
<div class="sub header">{% trans %}Please enter your password for this account.{% endtrans %}</div>
|
<div class="sub header">{% trans %}Please enter your password for this account.{% endtrans %}</div>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
|
|
||||||
<form method="POST"
|
<form method="POST"
|
||||||
id="{{ form.id or form.__class__.__name__|lower }}"
|
id="{{ form.id or form.__class__.__name__|lower }}"
|
||||||
action="{{ request.url }}"
|
action="{{ request.url }}"
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'fomanticui.j2' as sui %}
|
{% import 'fomanticui.j2' as sui %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script src="/static/js/profile.js"></script>
|
<script src="/static/js/confirm.js"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
@ -52,8 +51,6 @@
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
|
|
||||||
<form method="POST"
|
<form method="POST"
|
||||||
id="{{ form.__class__.__name__|lower }}"
|
id="{{ form.__class__.__name__|lower }}"
|
||||||
action="{{ request.url }}"
|
action="{{ request.url }}"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% import 'fomanticui.j2' as sui %}
|
{% import 'fomanticui.j2' as sui %}
|
||||||
{% import 'flask.j2' as flask %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="loginform">
|
<div class="loginform">
|
||||||
|
@ -13,8 +12,6 @@
|
||||||
</div>
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{{ flask.messages() }}
|
|
||||||
|
|
||||||
<div class="ui attached clearing segment">
|
<div class="ui attached clearing segment">
|
||||||
{{ sui.render_form(form, _("Password reset"), action=url_for("account.reset", uid=uid, hash=hash)) }}
|
{{ sui.render_form(form, _("Password reset"), action=url_for("account.reset", uid=uid, hash=hash)) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="ui segment">
|
<div class="ui segment">
|
||||||
<a class="ui primary button" href="{{ url_for('account.profile_creation') }}">{% trans %}Add a user{% endtrans %}</a>
|
<a class="ui primary button" href="{{ url_for('account.profile_creation') }}">{% trans %}Add a user{% endtrans %}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
Binary file not shown.
|
@ -3,24 +3,25 @@
|
||||||
# This file is distributed under the same license as the PROJECT project.
|
# This file is distributed under the same license as the PROJECT project.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||||
# Éloi Rivard <eloi.rivard@aquilenet.fr>, 2020-2021.
|
# Éloi Rivard <eloi.rivard@aquilenet.fr>, 2020-2021.
|
||||||
|
# Camille <camille@yaal.coop>, 2021.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PROJECT VERSION\n"
|
"Project-Id-Version: PROJECT VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: contact@yaal.fr\n"
|
"Report-Msgid-Bugs-To: contact@yaal.fr\n"
|
||||||
"POT-Creation-Date: 2021-06-03 15:21+0200\n"
|
"POT-Creation-Date: 2021-07-29 16:09+0200\n"
|
||||||
"PO-Revision-Date: 2021-06-03 15:22+0200\n"
|
"PO-Revision-Date: 2021-07-29 16:31+0200\n"
|
||||||
"Last-Translator: Éloi Rivard <eloi.rivard@aquilenet.fr>\n"
|
"Last-Translator: Camille <camille@yaal.coop>\n"
|
||||||
"Language: fr\n"
|
"Language: fr\n"
|
||||||
"Language-Team: French <traduc@traduc.org>\n"
|
"Language-Team: French <contact@yaal.coop>\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
|
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.9.1\n"
|
"Generated-By: Babel 2.9.1\n"
|
||||||
"X-Generator: Gtranslator 40.0\n"
|
"X-Generator: Gtranslator 3.38.0\n"
|
||||||
|
|
||||||
#: canaille/account.py:62 canaille/account.py:87 canaille/oauth.py:58
|
#: canaille/account.py:62 canaille/account.py:87 canaille/oauth.py:59
|
||||||
msgid "Login failed, please check your information"
|
msgid "Login failed, please check your information"
|
||||||
msgstr "La connexion a échoué, veuillez vérifier vos informations."
|
msgstr "La connexion a échoué, veuillez vérifier vos informations."
|
||||||
|
|
||||||
|
@ -155,9 +156,9 @@ msgstr "Identifiant"
|
||||||
msgid "jdoe"
|
msgid "jdoe"
|
||||||
msgstr "mdupont"
|
msgstr "mdupont"
|
||||||
|
|
||||||
#: canaille/admin/clients.py:23 canaille/forms.py:82
|
#: canaille/admin/clients.py:23 canaille/forms.py:82 canaille/forms.py:152
|
||||||
#: canaille/templates/admin/client_list.html:25
|
#: canaille/templates/admin/client_list.html:22
|
||||||
#: canaille/templates/users.html:22
|
#: canaille/templates/users.html:21
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
|
@ -181,7 +182,7 @@ msgstr "Dupont"
|
||||||
msgid "Email address"
|
msgid "Email address"
|
||||||
msgstr "Courriel"
|
msgstr "Courriel"
|
||||||
|
|
||||||
#: canaille/forms.py:109 canaille/templates/users.html:24
|
#: canaille/forms.py:109 canaille/templates/users.html:23
|
||||||
msgid "Phone number"
|
msgid "Phone number"
|
||||||
msgstr "Numéro de téléphone"
|
msgstr "Numéro de téléphone"
|
||||||
|
|
||||||
|
@ -201,10 +202,37 @@ msgstr "Numéro"
|
||||||
msgid "1234"
|
msgid "1234"
|
||||||
msgstr "1234"
|
msgstr "1234"
|
||||||
|
|
||||||
#: canaille/forms.py:143
|
#: canaille/forms.py:143 canaille/templates/base.html:55
|
||||||
|
#: canaille/templates/groups.html:9
|
||||||
msgid "Groups"
|
msgid "Groups"
|
||||||
msgstr "Groupes"
|
msgstr "Groupes"
|
||||||
|
|
||||||
|
#: canaille/forms.py:155
|
||||||
|
msgid "group"
|
||||||
|
msgstr "groupe"
|
||||||
|
|
||||||
|
#: canaille/forms.py:162
|
||||||
|
msgid "The group '{group}' already exists"
|
||||||
|
msgstr "Le group '{group}' existe déjà"
|
||||||
|
|
||||||
|
#: canaille/groups.py:39
|
||||||
|
msgid "Group creation failed."
|
||||||
|
msgstr "La création du groupe a échoué."
|
||||||
|
|
||||||
|
#: canaille/groups.py:46
|
||||||
|
#, python-format
|
||||||
|
msgid "The group %(group)s has been sucessfully created"
|
||||||
|
msgstr "Le groupe %(group)s a bien été créé"
|
||||||
|
|
||||||
|
#: canaille/groups.py:76
|
||||||
|
msgid "Group edition failed."
|
||||||
|
msgstr "L'édition du groupe a échoué."
|
||||||
|
|
||||||
|
#: canaille/groups.py:85
|
||||||
|
#, python-format
|
||||||
|
msgid "The group %(group)s has been sucessfully deleted"
|
||||||
|
msgstr "Le groupe %(group)s a bien été supprimé"
|
||||||
|
|
||||||
#: canaille/admin/mail.py:27 canaille/mails.py:27
|
#: canaille/admin/mail.py:27 canaille/mails.py:27
|
||||||
msgid "Password reset on {website_name}"
|
msgid "Password reset on {website_name}"
|
||||||
msgstr "Réinitialisation du mot de passe sur {website_name}"
|
msgstr "Réinitialisation du mot de passe sur {website_name}"
|
||||||
|
@ -229,7 +257,11 @@ msgstr "Votre adresse postale."
|
||||||
msgid "Your phone number."
|
msgid "Your phone number."
|
||||||
msgstr "Votre numéro de téléphone."
|
msgstr "Votre numéro de téléphone."
|
||||||
|
|
||||||
#: canaille/oauth.py:97
|
#: canaille/oauth.py:30
|
||||||
|
msgid "Groups you are belonging to"
|
||||||
|
msgstr "Les groupes dans lesquels vous êtes"
|
||||||
|
|
||||||
|
#: canaille/oauth.py:98
|
||||||
msgid "You have been successfully logged out."
|
msgid "You have been successfully logged out."
|
||||||
msgstr "Vous avez été déconnectés."
|
msgstr "Vous avez été déconnectés."
|
||||||
|
|
||||||
|
@ -309,24 +341,24 @@ msgstr "Le client a été édité."
|
||||||
msgid "The client has been deleted."
|
msgid "The client has been deleted."
|
||||||
msgstr "Le client a été supprimé."
|
msgstr "Le client a été supprimé."
|
||||||
|
|
||||||
#: canaille/templates/about.html:14 canaille/templates/base.html:90
|
#: canaille/templates/about.html:12 canaille/templates/base.html:98
|
||||||
msgid "About canaille"
|
msgid "About canaille"
|
||||||
msgstr "À propos de canaille"
|
msgstr "À propos de canaille"
|
||||||
|
|
||||||
#: canaille/templates/about.html:16
|
#: canaille/templates/about.html:14
|
||||||
msgid "Free and open-source identity provider."
|
msgid "Free and open-source identity provider."
|
||||||
msgstr "Fournisseur d'identité numérique libre"
|
msgstr "Fournisseur d'identité numérique libre"
|
||||||
|
|
||||||
#: canaille/templates/about.html:19
|
#: canaille/templates/about.html:17
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Version %(version)s"
|
msgid "Version %(version)s"
|
||||||
msgstr "Version %(version)s"
|
msgstr "Version %(version)s"
|
||||||
|
|
||||||
#: canaille/templates/about.html:20
|
#: canaille/templates/about.html:18
|
||||||
msgid "Source code"
|
msgid "Source code"
|
||||||
msgstr "Code source"
|
msgstr "Code source"
|
||||||
|
|
||||||
#: canaille/templates/about.html:21
|
#: canaille/templates/about.html:19
|
||||||
msgid "Documentation"
|
msgid "Documentation"
|
||||||
msgstr "Documentation"
|
msgstr "Documentation"
|
||||||
|
|
||||||
|
@ -352,67 +384,67 @@ msgstr "Changer d'utilisateur"
|
||||||
msgid "Accept"
|
msgid "Accept"
|
||||||
msgstr "Accepter"
|
msgstr "Accepter"
|
||||||
|
|
||||||
#: canaille/templates/base.html:8
|
#: canaille/templates/base.html:10
|
||||||
msgid "authorization interface"
|
msgid "authorization interface"
|
||||||
msgstr " - Interface de gestion des autorisations"
|
msgstr " - Interface de gestion des autorisations"
|
||||||
|
|
||||||
#: canaille/templates/base.html:37 canaille/templates/profile.html:38
|
#: canaille/templates/base.html:39 canaille/templates/profile.html:37
|
||||||
msgid "My profile"
|
msgid "My profile"
|
||||||
msgstr "Mon profil"
|
msgstr "Mon profil"
|
||||||
|
|
||||||
#: canaille/templates/base.html:42 canaille/templates/consent_list.html:19
|
#: canaille/templates/base.html:44 canaille/templates/consent_list.html:18
|
||||||
msgid "My consents"
|
msgid "My consents"
|
||||||
msgstr "Mes autorisations"
|
msgstr "Mes autorisations"
|
||||||
|
|
||||||
#: canaille/templates/base.html:48
|
#: canaille/templates/base.html:50
|
||||||
msgid "Users"
|
msgid "Users"
|
||||||
msgstr "Utilisateurs"
|
msgstr "Utilisateurs"
|
||||||
|
|
||||||
#: canaille/templates/base.html:58
|
#: canaille/templates/base.html:65
|
||||||
msgid "Clients"
|
msgid "Clients"
|
||||||
msgstr "Clients"
|
msgstr "Clients"
|
||||||
|
|
||||||
#: canaille/templates/base.html:62
|
#: canaille/templates/base.html:69
|
||||||
msgid "Tokens"
|
msgid "Tokens"
|
||||||
msgstr "Jetons"
|
msgstr "Jetons"
|
||||||
|
|
||||||
#: canaille/templates/base.html:66
|
#: canaille/templates/base.html:73
|
||||||
msgid "Codes"
|
msgid "Codes"
|
||||||
msgstr "Codes"
|
msgstr "Codes"
|
||||||
|
|
||||||
#: canaille/templates/base.html:70
|
#: canaille/templates/base.html:77
|
||||||
msgid "Consents"
|
msgid "Consents"
|
||||||
msgstr "Autorisations"
|
msgstr "Autorisations"
|
||||||
|
|
||||||
#: canaille/templates/base.html:77
|
#: canaille/templates/base.html:84
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "Déconnexion"
|
msgstr "Déconnexion"
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:22
|
#: canaille/templates/consent_list.html:21
|
||||||
msgid "Consult and revoke the authorization you gave to websites."
|
msgid "Consult and revoke the authorization you gave to websites."
|
||||||
msgstr "Consultez et révoquez les autorisation que vous avez données."
|
msgstr "Consultez et révoquez les autorisation que vous avez données."
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:42
|
#: canaille/templates/consent_list.html:39
|
||||||
msgid "From:"
|
msgid "From:"
|
||||||
msgstr "À partir de :"
|
msgstr "À partir de :"
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:44
|
#: canaille/templates/consent_list.html:41
|
||||||
msgid "Revoked:"
|
msgid "Revoked:"
|
||||||
msgstr "Révoqué le :"
|
msgstr "Révoqué le :"
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:47
|
#: canaille/templates/consent_list.html:44
|
||||||
msgid "Has access to:"
|
msgid "Has access to:"
|
||||||
msgstr "A accès à :"
|
msgstr "A accès à :"
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:57
|
#: canaille/templates/consent_list.html:54
|
||||||
msgid "Remove access"
|
msgid "Remove access"
|
||||||
msgstr "Supprimer l'accès"
|
msgstr "Supprimer l'accès"
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:67
|
#: canaille/templates/consent_list.html:64
|
||||||
msgid "Nothing here"
|
msgid "Nothing here"
|
||||||
msgstr "Rien ici"
|
msgstr "Rien ici"
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:68
|
#: canaille/templates/consent_list.html:65
|
||||||
msgid "You did not authorize applications yet."
|
msgid "You did not authorize applications yet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vous n'avez pas encore autorisé d'application à accéder à votre profil."
|
"Vous n'avez pas encore autorisé d'application à accéder à votre profil."
|
||||||
|
@ -433,11 +465,11 @@ msgstr "Page non trouvée"
|
||||||
msgid "Technical problem"
|
msgid "Technical problem"
|
||||||
msgstr "Problème technique"
|
msgstr "Problème technique"
|
||||||
|
|
||||||
#: canaille/templates/firstlogin.html:12
|
#: canaille/templates/firstlogin.html:11
|
||||||
msgid "First login"
|
msgid "First login"
|
||||||
msgstr "Première connexion"
|
msgstr "Première connexion"
|
||||||
|
|
||||||
#: canaille/templates/firstlogin.html:19
|
#: canaille/templates/firstlogin.html:16
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" It seems this is the first time you are logging here. In order to "
|
" It seems this is the first time you are logging here. In order to "
|
||||||
|
@ -459,21 +491,21 @@ msgstr ""
|
||||||
" Veuillez cliquer sur le bouton bleu ci-dessous pour envoyer le "
|
" Veuillez cliquer sur le bouton bleu ci-dessous pour envoyer le "
|
||||||
"courriel."
|
"courriel."
|
||||||
|
|
||||||
#: canaille/templates/firstlogin.html:35
|
#: canaille/templates/firstlogin.html:32
|
||||||
msgid "Send the initialization email"
|
msgid "Send the initialization email"
|
||||||
msgstr "Envoyer le courriel d'initialisation"
|
msgstr "Envoyer le courriel d'initialisation"
|
||||||
|
|
||||||
#: canaille/templates/firstlogin.html:36
|
#: canaille/templates/firstlogin.html:33
|
||||||
#: canaille/templates/forgotten-password.html:43
|
#: canaille/templates/forgotten-password.html:40
|
||||||
msgid "Login page"
|
msgid "Login page"
|
||||||
msgstr "Page de connexion"
|
msgstr "Page de connexion"
|
||||||
|
|
||||||
#: canaille/templates/forgotten-password.html:12
|
#: canaille/templates/forgotten-password.html:11
|
||||||
#: canaille/templates/login.html:38 canaille/templates/password.html:35
|
#: canaille/templates/login.html:35 canaille/templates/password.html:32
|
||||||
msgid "Forgotten password"
|
msgid "Forgotten password"
|
||||||
msgstr "Mot de passe oublié"
|
msgstr "Mot de passe oublié"
|
||||||
|
|
||||||
#: canaille/templates/forgotten-password.html:19
|
#: canaille/templates/forgotten-password.html:16
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" After this form is sent, if the email address or the login you "
|
" After this form is sent, if the email address or the login you "
|
||||||
|
@ -490,51 +522,119 @@ msgstr ""
|
||||||
" vous permettra de ré-initialiser votre mot de passe.\n"
|
" vous permettra de ré-initialiser votre mot de passe.\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: canaille/templates/forgotten-password.html:38
|
#: canaille/templates/forgotten-password.html:35
|
||||||
#: canaille/templates/profile.html:120 canaille/templates/profile.html:143
|
#: canaille/templates/profile.html:117 canaille/templates/profile.html:140
|
||||||
msgid "Send again"
|
msgid "Send again"
|
||||||
msgstr "Envoyer à nouveau"
|
msgstr "Envoyer à nouveau"
|
||||||
|
|
||||||
#: canaille/templates/forgotten-password.html:40
|
#: canaille/templates/forgotten-password.html:37
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr "Envoyer"
|
msgstr "Envoyer"
|
||||||
|
|
||||||
#: canaille/templates/login.html:17
|
#: canaille/templates/group.html:13
|
||||||
|
msgid "Group deletion"
|
||||||
|
msgstr "Suppression d'un groupe"
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:17
|
||||||
|
msgid ""
|
||||||
|
"Are you sure you want to delete this group? This action is unrevokable and "
|
||||||
|
"all the data about this group will be removed."
|
||||||
|
msgstr ""
|
||||||
|
"Êtes-vous sûrs de vouloir supprimer ce groupe ? Cette action est "
|
||||||
|
"irrévocable, et toutes les données de cet utilisateur seront supprimées."
|
||||||
|
|
||||||
|
#: canaille/templates/admin/client_edit.html:18
|
||||||
|
#: canaille/templates/group.html:21 canaille/templates/profile.html:25
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr "Annuler"
|
||||||
|
|
||||||
|
#: canaille/templates/admin/client_edit.html:19
|
||||||
|
#: canaille/templates/group.html:22 canaille/templates/profile.html:26
|
||||||
|
msgid "Delete"
|
||||||
|
msgstr "Supprimer"
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:29
|
||||||
|
msgid "Members"
|
||||||
|
msgstr "Membres"
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:45
|
||||||
|
msgid "Group creation"
|
||||||
|
msgstr "Nouveau groupe"
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:47
|
||||||
|
msgid "Group edition"
|
||||||
|
msgstr "Édition d'un groupe"
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:53
|
||||||
|
msgid "Create a new group"
|
||||||
|
msgstr "Création d'un nouveau groupe"
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:55
|
||||||
|
msgid "Edit informations about a group"
|
||||||
|
msgstr "Éditez les informations d'un groupe"
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:70
|
||||||
|
msgid ""
|
||||||
|
"Because group cannot be empty, you will be added to the group. You can "
|
||||||
|
"remove you later by editing your profile when you will have added other "
|
||||||
|
"members to the group."
|
||||||
|
msgstr ""
|
||||||
|
"Vous serez ajouté au groupe car le groupe ne peut pas être vide. Vous "
|
||||||
|
"pourrez vous retirer du groupe depuis l'édition de votre profil dès que vous "
|
||||||
|
"aurez ajouter d'autres membres dans le groupe."
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:75
|
||||||
|
msgid "Create group"
|
||||||
|
msgstr "Créer le groupe"
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:77 canaille/templates/profile.html:154
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr "Valider"
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:82
|
||||||
|
msgid "Delete group"
|
||||||
|
msgstr "Supprimer le groupe"
|
||||||
|
|
||||||
|
#: canaille/templates/groups.html:5
|
||||||
|
msgid "Add a group"
|
||||||
|
msgstr "Ajouter un groupe"
|
||||||
|
|
||||||
|
#: canaille/templates/login.html:16
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Sign in at %(website)s"
|
msgid "Sign in at %(website)s"
|
||||||
msgstr "Connexion à %(website)s"
|
msgstr "Connexion à %(website)s"
|
||||||
|
|
||||||
#: canaille/templates/login.html:19
|
#: canaille/templates/login.html:18
|
||||||
msgid "Log-in and manage your authorizations."
|
msgid "Log-in and manage your authorizations."
|
||||||
msgstr "Connectez-vous et gérez vos autorisations."
|
msgstr "Connectez-vous et gérez vos autorisations."
|
||||||
|
|
||||||
#: canaille/templates/login.html:37
|
#: canaille/templates/login.html:34
|
||||||
msgid "Continue"
|
msgid "Continue"
|
||||||
msgstr "Continuer"
|
msgstr "Continuer"
|
||||||
|
|
||||||
#: canaille/templates/password.html:17
|
#: canaille/templates/password.html:16
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Sign in as %(username)s"
|
msgid "Sign in as %(username)s"
|
||||||
msgstr "Connexion en tant que %(username)s"
|
msgstr "Connexion en tant que %(username)s"
|
||||||
|
|
||||||
#: canaille/templates/password.html:19
|
#: canaille/templates/password.html:18
|
||||||
msgid "Please enter your password for this account."
|
msgid "Please enter your password for this account."
|
||||||
msgstr "Veuillez entre votre mot de passe pour ce compte."
|
msgstr "Veuillez entre votre mot de passe pour ce compte."
|
||||||
|
|
||||||
#: canaille/templates/password.html:34
|
#: canaille/templates/password.html:31
|
||||||
msgid "Sign in"
|
msgid "Sign in"
|
||||||
msgstr "Se connecter"
|
msgstr "Se connecter"
|
||||||
|
|
||||||
#: canaille/templates/password.html:36
|
#: canaille/templates/password.html:33
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "I am not %(username)s"
|
msgid "I am not %(username)s"
|
||||||
msgstr "Je ne suis pas %(username)s"
|
msgstr "Je ne suis pas %(username)s"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:14
|
#: canaille/templates/profile.html:13
|
||||||
msgid "Account deletion"
|
msgid "Account deletion"
|
||||||
msgstr "Suppression d'un compte"
|
msgstr "Suppression d'un compte"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:19
|
#: canaille/templates/profile.html:18
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to delete this user? This action is unrevokable and "
|
"Are you sure you want to delete this user? This action is unrevokable and "
|
||||||
"all the data about this user will be removed."
|
"all the data about this user will be removed."
|
||||||
|
@ -542,7 +642,7 @@ msgstr ""
|
||||||
"Êtes-vous sûrs de vouloir supprimer cet utilisateur ? Cette action est "
|
"Êtes-vous sûrs de vouloir supprimer cet utilisateur ? Cette action est "
|
||||||
"irrévocable, et toutes les données de cet utilisateur seront supprimées."
|
"irrévocable, et toutes les données de cet utilisateur seront supprimées."
|
||||||
|
|
||||||
#: canaille/templates/profile.html:21
|
#: canaille/templates/profile.html:20
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to delete your account? This action is unrevokable and "
|
"Are you sure you want to delete your account? This action is unrevokable and "
|
||||||
"all your data will be removed forever."
|
"all your data will be removed forever."
|
||||||
|
@ -550,57 +650,47 @@ msgstr ""
|
||||||
"Êtes-vous sûrs de vouloir supprimer votre compte ? Cette action est "
|
"Êtes-vous sûrs de vouloir supprimer votre compte ? Cette action est "
|
||||||
"irrévocable et toutes vos données seront supprimées pour toujours."
|
"irrévocable et toutes vos données seront supprimées pour toujours."
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:19
|
#: canaille/templates/profile.html:35
|
||||||
#: canaille/templates/profile.html:26
|
|
||||||
msgid "Cancel"
|
|
||||||
msgstr "Annuler"
|
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:20
|
|
||||||
#: canaille/templates/profile.html:27
|
|
||||||
msgid "Delete"
|
|
||||||
msgstr "Supprimer"
|
|
||||||
|
|
||||||
#: canaille/templates/profile.html:36
|
|
||||||
msgid "User creation"
|
msgid "User creation"
|
||||||
msgstr "Nouvel utilisateur"
|
msgstr "Nouvel utilisateur"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:40
|
#: canaille/templates/profile.html:39
|
||||||
msgid "User profile edition"
|
msgid "User profile edition"
|
||||||
msgstr "Édition d'un profil utilisateur"
|
msgstr "Édition d'un profil utilisateur"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:46
|
#: canaille/templates/profile.html:45
|
||||||
msgid "Create a new user account"
|
msgid "Create a new user account"
|
||||||
msgstr "Création d'un nouveau compte utilisateur"
|
msgstr "Création d'un nouveau compte utilisateur"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:48
|
#: canaille/templates/profile.html:47
|
||||||
msgid "Edit your personal informations"
|
msgid "Edit your personal informations"
|
||||||
msgstr "Éditez vos informations personnelles"
|
msgstr "Éditez vos informations personnelles"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:50
|
#: canaille/templates/profile.html:49
|
||||||
msgid "Edit informations about an user"
|
msgid "Edit informations about an user"
|
||||||
msgstr "Éditez les informations d'un utilisateur"
|
msgstr "Éditez les informations d'un utilisateur"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:67
|
#: canaille/templates/profile.html:64
|
||||||
msgid "Personal information"
|
msgid "Personal information"
|
||||||
msgstr "Informations personnelles"
|
msgstr "Informations personnelles"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:89
|
#: canaille/templates/profile.html:86
|
||||||
msgid "Account information"
|
msgid "Account information"
|
||||||
msgstr "Informations sur le compte"
|
msgstr "Informations sur le compte"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:105
|
#: canaille/templates/profile.html:102
|
||||||
msgid "User password is not mandatory"
|
msgid "User password is not mandatory"
|
||||||
msgstr "Le mot de passe utilisateur n'est pas requis à la création"
|
msgstr "Le mot de passe utilisateur n'est pas requis à la création"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:107
|
#: canaille/templates/profile.html:104
|
||||||
msgid "The user password can be set:"
|
msgid "The user password can be set:"
|
||||||
msgstr "Il pourra être renseigné :"
|
msgstr "Il pourra être renseigné :"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:109
|
#: canaille/templates/profile.html:106
|
||||||
msgid "by filling this form;"
|
msgid "by filling this form;"
|
||||||
msgstr "en remplissant ce formulaire ;"
|
msgstr "en remplissant ce formulaire ;"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:110
|
#: canaille/templates/profile.html:107
|
||||||
msgid ""
|
msgid ""
|
||||||
"by sending the user a password initialization mail, after the account "
|
"by sending the user a password initialization mail, after the account "
|
||||||
"creation;"
|
"creation;"
|
||||||
|
@ -608,7 +698,7 @@ msgstr ""
|
||||||
"en envoyant un lien d'initialisation de mot de passe, par mail à "
|
"en envoyant un lien d'initialisation de mot de passe, par mail à "
|
||||||
"l'utilisateur, après la création de son compte;"
|
"l'utilisateur, après la création de son compte;"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:111 canaille/templates/profile.html:134
|
#: canaille/templates/profile.html:108 canaille/templates/profile.html:131
|
||||||
msgid ""
|
msgid ""
|
||||||
"or simply waiting for the user to sign-in a first time, and then receive a "
|
"or simply waiting for the user to sign-in a first time, and then receive a "
|
||||||
"password initialization mail."
|
"password initialization mail."
|
||||||
|
@ -616,40 +706,40 @@ msgstr ""
|
||||||
"ou simplement en attendant la première connexion de l'utilisateur, afin "
|
"ou simplement en attendant la première connexion de l'utilisateur, afin "
|
||||||
"qu'il reçoive un lien d'initialisation de mot de passe par email."
|
"qu'il reçoive un lien d'initialisation de mot de passe par email."
|
||||||
|
|
||||||
#: canaille/templates/profile.html:124
|
#: canaille/templates/profile.html:121
|
||||||
msgid "Send email"
|
msgid "Send email"
|
||||||
msgstr "Envoyer l'email"
|
msgstr "Envoyer l'email"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:128
|
#: canaille/templates/profile.html:125
|
||||||
msgid "This user does not have a password yet"
|
msgid "This user does not have a password yet"
|
||||||
msgstr "L'utilisateur n'a pas encore de mot de passe"
|
msgstr "L'utilisateur n'a pas encore de mot de passe"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:130
|
#: canaille/templates/profile.html:127
|
||||||
msgid "You can solve this by:"
|
msgid "You can solve this by:"
|
||||||
msgstr "Vous pouvez régler ceci en :"
|
msgstr "Vous pouvez régler ceci en :"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:132
|
#: canaille/templates/profile.html:129
|
||||||
msgid "setting a password using this form;"
|
msgid "setting a password using this form;"
|
||||||
msgstr "renseignant un mot de passe via ce formulaire ;"
|
msgstr "renseignant un mot de passe via ce formulaire ;"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:133
|
#: canaille/templates/profile.html:130
|
||||||
msgid ""
|
msgid ""
|
||||||
"sending the user a password initialization mail, by clicking this button;"
|
"sending the user a password initialization mail, by clicking this button;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"envoyant un lien d'initialisation de mot de passe, par mail à l'utilisateur, "
|
"envoyant un lien d'initialisation de mot de passe, par mail à l'utilisateur, "
|
||||||
"en cliquant sur ce bouton;"
|
"en cliquant sur ce bouton;"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:145
|
#: canaille/templates/profile.html:142
|
||||||
msgid "Send mail"
|
msgid "Send mail"
|
||||||
msgstr "Envoyer l'email"
|
msgstr "Envoyer l'email"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:149
|
#: canaille/templates/profile.html:146
|
||||||
#: canaille/templates/reset-password.html:12
|
#: canaille/templates/reset-password.html:11
|
||||||
#: canaille/templates/reset-password.html:19
|
#: canaille/templates/reset-password.html:16
|
||||||
msgid "Password reset"
|
msgid "Password reset"
|
||||||
msgstr "Réinitialisation du mot de passe"
|
msgstr "Réinitialisation du mot de passe"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:151
|
#: canaille/templates/profile.html:148
|
||||||
msgid ""
|
msgid ""
|
||||||
"If the user has forgotten his password, you can send him a password reset "
|
"If the user has forgotten his password, you can send him a password reset "
|
||||||
"email by clicking this button."
|
"email by clicking this button."
|
||||||
|
@ -657,27 +747,23 @@ msgstr ""
|
||||||
"Si l'utilisateur a oublié son mot de passe, vous pouvez lui envoyer un email "
|
"Si l'utilisateur a oublié son mot de passe, vous pouvez lui envoyer un email "
|
||||||
"contenant un lien de réinitilisation en cliquant sur ce bouton."
|
"contenant un lien de réinitilisation en cliquant sur ce bouton."
|
||||||
|
|
||||||
#: canaille/templates/profile.html:157
|
#: canaille/templates/profile.html:158
|
||||||
msgid "Submit"
|
|
||||||
msgstr "Valider"
|
|
||||||
|
|
||||||
#: canaille/templates/profile.html:161
|
|
||||||
msgid "Impersonate"
|
msgid "Impersonate"
|
||||||
msgstr "Prendre l'identité"
|
msgstr "Prendre l'identité"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:167
|
#: canaille/templates/profile.html:164
|
||||||
msgid "Delete the user"
|
msgid "Delete the user"
|
||||||
msgstr "Supprimer l'utilisateur"
|
msgstr "Supprimer l'utilisateur"
|
||||||
|
|
||||||
#: canaille/templates/profile.html:169
|
#: canaille/templates/profile.html:166
|
||||||
msgid "Delete my account"
|
msgid "Delete my account"
|
||||||
msgstr "Supprimer mon compte"
|
msgstr "Supprimer mon compte"
|
||||||
|
|
||||||
#: canaille/templates/users.html:17
|
#: canaille/templates/users.html:16
|
||||||
msgid "Add a user"
|
msgid "Add a user"
|
||||||
msgstr "Nouvel utilisateur"
|
msgstr "Nouvel utilisateur"
|
||||||
|
|
||||||
#: canaille/templates/users.html:23
|
#: canaille/templates/users.html:22
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "Courriel"
|
msgstr "Courriel"
|
||||||
|
|
||||||
|
@ -697,28 +783,28 @@ msgid "Subject"
|
||||||
msgstr "Utilisateur"
|
msgstr "Utilisateur"
|
||||||
|
|
||||||
#: canaille/templates/admin/authorization_list.html:21
|
#: canaille/templates/admin/authorization_list.html:21
|
||||||
#: canaille/templates/admin/client_list.html:27
|
#: canaille/templates/admin/client_list.html:24
|
||||||
#: canaille/templates/admin/token_list.html:21
|
#: canaille/templates/admin/token_list.html:21
|
||||||
msgid "Created"
|
msgid "Created"
|
||||||
msgstr "Créé"
|
msgstr "Créé"
|
||||||
|
|
||||||
#: canaille/templates/admin/authorization_view.html:8
|
#: canaille/templates/admin/authorization_view.html:7
|
||||||
msgid "View a authorization"
|
msgid "View a authorization"
|
||||||
msgstr "Voir une autorisation"
|
msgstr "Voir une autorisation"
|
||||||
|
|
||||||
#: canaille/templates/admin/client_add.html:8
|
#: canaille/templates/admin/client_add.html:7
|
||||||
msgid "Add a client"
|
msgid "Add a client"
|
||||||
msgstr "Ajouter un client"
|
msgstr "Ajouter un client"
|
||||||
|
|
||||||
#: canaille/templates/admin/client_add.html:14
|
#: canaille/templates/admin/client_add.html:11
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirmer"
|
msgstr "Confirmer"
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:13
|
#: canaille/templates/admin/client_edit.html:12
|
||||||
msgid "Client deletion"
|
msgid "Client deletion"
|
||||||
msgstr "Suppression d'un client"
|
msgstr "Suppression d'un client"
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:16
|
#: canaille/templates/admin/client_edit.html:15
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to delete this client? This action is unrevokable and "
|
"Are you sure you want to delete this client? This action is unrevokable and "
|
||||||
"all the data about this client will be removed."
|
"all the data about this client will be removed."
|
||||||
|
@ -726,39 +812,39 @@ msgstr ""
|
||||||
"Êtes-vous sûrs de vouloir supprimer ce client ? Cette action est irrévocable "
|
"Êtes-vous sûrs de vouloir supprimer ce client ? Cette action est irrévocable "
|
||||||
"et toutes les données à propos de ce client seront supprimées."
|
"et toutes les données à propos de ce client seront supprimées."
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:26
|
#: canaille/templates/admin/client_edit.html:25
|
||||||
msgid "Edit a client"
|
msgid "Edit a client"
|
||||||
msgstr "Éditer un client"
|
msgstr "Éditer un client"
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:35
|
#: canaille/templates/admin/client_edit.html:32
|
||||||
msgid "ID"
|
msgid "ID"
|
||||||
msgstr "ID"
|
msgstr "ID"
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:39
|
#: canaille/templates/admin/client_edit.html:36
|
||||||
msgid "Secret"
|
msgid "Secret"
|
||||||
msgstr "Secret"
|
msgstr "Secret"
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:43
|
#: canaille/templates/admin/client_edit.html:40
|
||||||
msgid "Issued at"
|
msgid "Issued at"
|
||||||
msgstr "Créé le"
|
msgstr "Créé le"
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:60
|
#: canaille/templates/admin/client_edit.html:57
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Éditer"
|
msgstr "Éditer"
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:63
|
#: canaille/templates/admin/client_edit.html:60
|
||||||
msgid "Delete the client"
|
msgid "Delete the client"
|
||||||
msgstr "Supprimer le client"
|
msgstr "Supprimer le client"
|
||||||
|
|
||||||
#: canaille/templates/admin/client_list.html:20
|
#: canaille/templates/admin/client_list.html:17
|
||||||
msgid "Add client"
|
msgid "Add client"
|
||||||
msgstr "Ajouter un client"
|
msgstr "Ajouter un client"
|
||||||
|
|
||||||
#: canaille/templates/admin/client_list.html:26
|
#: canaille/templates/admin/client_list.html:23
|
||||||
msgid "URL"
|
msgid "URL"
|
||||||
msgstr "URL"
|
msgstr "URL"
|
||||||
|
|
||||||
#: canaille/templates/admin/token_view.html:8
|
#: canaille/templates/admin/token_view.html:7
|
||||||
msgid "View a token"
|
msgid "View a token"
|
||||||
msgstr "Voir un jeton"
|
msgstr "Voir un jeton"
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PROJECT VERSION\n"
|
"Project-Id-Version: PROJECT VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2021-06-03 15:21+0200\n"
|
"POT-Creation-Date: 2021-07-29 16:09+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -17,7 +17,7 @@ msgstr ""
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.9.1\n"
|
"Generated-By: Babel 2.9.1\n"
|
||||||
|
|
||||||
#: canaille/account.py:62 canaille/account.py:87 canaille/oauth.py:58
|
#: canaille/account.py:62 canaille/account.py:87 canaille/oauth.py:59
|
||||||
msgid "Login failed, please check your information"
|
msgid "Login failed, please check your information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -144,9 +144,9 @@ msgstr ""
|
||||||
msgid "jdoe"
|
msgid "jdoe"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/admin/clients.py:23 canaille/forms.py:82
|
#: canaille/admin/clients.py:23 canaille/forms.py:82 canaille/forms.py:152
|
||||||
#: canaille/templates/admin/client_list.html:25
|
#: canaille/templates/admin/client_list.html:22
|
||||||
#: canaille/templates/users.html:22
|
#: canaille/templates/users.html:21
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ msgstr ""
|
||||||
msgid "Email address"
|
msgid "Email address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/forms.py:109 canaille/templates/users.html:24
|
#: canaille/forms.py:109 canaille/templates/users.html:23
|
||||||
msgid "Phone number"
|
msgid "Phone number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -190,10 +190,37 @@ msgstr ""
|
||||||
msgid "1234"
|
msgid "1234"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/forms.py:143
|
#: canaille/forms.py:143 canaille/templates/base.html:55
|
||||||
|
#: canaille/templates/groups.html:9
|
||||||
msgid "Groups"
|
msgid "Groups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/forms.py:155
|
||||||
|
msgid "group"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/forms.py:162
|
||||||
|
msgid "The group '{group}' already exists"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/groups.py:39
|
||||||
|
msgid "Group creation failed."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/groups.py:46
|
||||||
|
#, python-format
|
||||||
|
msgid "The group %(group)s has been sucessfully created"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/groups.py:76
|
||||||
|
msgid "Group edition failed."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/groups.py:85
|
||||||
|
#, python-format
|
||||||
|
msgid "The group %(group)s has been sucessfully deleted"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/admin/mail.py:27 canaille/mails.py:27
|
#: canaille/admin/mail.py:27 canaille/mails.py:27
|
||||||
msgid "Password reset on {website_name}"
|
msgid "Password reset on {website_name}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -218,7 +245,11 @@ msgstr ""
|
||||||
msgid "Your phone number."
|
msgid "Your phone number."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/oauth.py:97
|
#: canaille/oauth.py:30
|
||||||
|
msgid "Groups you are belonging to"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/oauth.py:98
|
||||||
msgid "You have been successfully logged out."
|
msgid "You have been successfully logged out."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -298,24 +329,24 @@ msgstr ""
|
||||||
msgid "The client has been deleted."
|
msgid "The client has been deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/about.html:14 canaille/templates/base.html:90
|
#: canaille/templates/about.html:12 canaille/templates/base.html:98
|
||||||
msgid "About canaille"
|
msgid "About canaille"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/about.html:16
|
#: canaille/templates/about.html:14
|
||||||
msgid "Free and open-source identity provider."
|
msgid "Free and open-source identity provider."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/about.html:19
|
#: canaille/templates/about.html:17
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Version %(version)s"
|
msgid "Version %(version)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/about.html:20
|
#: canaille/templates/about.html:18
|
||||||
msgid "Source code"
|
msgid "Source code"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/about.html:21
|
#: canaille/templates/about.html:19
|
||||||
msgid "Documentation"
|
msgid "Documentation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -341,67 +372,67 @@ msgstr ""
|
||||||
msgid "Accept"
|
msgid "Accept"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/base.html:8
|
#: canaille/templates/base.html:10
|
||||||
msgid "authorization interface"
|
msgid "authorization interface"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/base.html:37 canaille/templates/profile.html:38
|
#: canaille/templates/base.html:39 canaille/templates/profile.html:37
|
||||||
msgid "My profile"
|
msgid "My profile"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/base.html:42 canaille/templates/consent_list.html:19
|
#: canaille/templates/base.html:44 canaille/templates/consent_list.html:18
|
||||||
msgid "My consents"
|
msgid "My consents"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/base.html:48
|
#: canaille/templates/base.html:50
|
||||||
msgid "Users"
|
msgid "Users"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/base.html:58
|
#: canaille/templates/base.html:65
|
||||||
msgid "Clients"
|
msgid "Clients"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/base.html:62
|
#: canaille/templates/base.html:69
|
||||||
msgid "Tokens"
|
msgid "Tokens"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/base.html:66
|
#: canaille/templates/base.html:73
|
||||||
msgid "Codes"
|
msgid "Codes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/base.html:70
|
#: canaille/templates/base.html:77
|
||||||
msgid "Consents"
|
msgid "Consents"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/base.html:77
|
#: canaille/templates/base.html:84
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:22
|
#: canaille/templates/consent_list.html:21
|
||||||
msgid "Consult and revoke the authorization you gave to websites."
|
msgid "Consult and revoke the authorization you gave to websites."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:42
|
#: canaille/templates/consent_list.html:39
|
||||||
msgid "From:"
|
msgid "From:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:44
|
#: canaille/templates/consent_list.html:41
|
||||||
msgid "Revoked:"
|
msgid "Revoked:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:47
|
#: canaille/templates/consent_list.html:44
|
||||||
msgid "Has access to:"
|
msgid "Has access to:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:57
|
#: canaille/templates/consent_list.html:54
|
||||||
msgid "Remove access"
|
msgid "Remove access"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:67
|
#: canaille/templates/consent_list.html:64
|
||||||
msgid "Nothing here"
|
msgid "Nothing here"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/consent_list.html:68
|
#: canaille/templates/consent_list.html:65
|
||||||
msgid "You did not authorize applications yet."
|
msgid "You did not authorize applications yet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -421,11 +452,11 @@ msgstr ""
|
||||||
msgid "Technical problem"
|
msgid "Technical problem"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/firstlogin.html:12
|
#: canaille/templates/firstlogin.html:11
|
||||||
msgid "First login"
|
msgid "First login"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/firstlogin.html:19
|
#: canaille/templates/firstlogin.html:16
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" It seems this is the first time you are logging here. In order to"
|
" It seems this is the first time you are logging here. In order to"
|
||||||
|
@ -438,21 +469,21 @@ msgid ""
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/firstlogin.html:35
|
#: canaille/templates/firstlogin.html:32
|
||||||
msgid "Send the initialization email"
|
msgid "Send the initialization email"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/firstlogin.html:36
|
#: canaille/templates/firstlogin.html:33
|
||||||
#: canaille/templates/forgotten-password.html:43
|
#: canaille/templates/forgotten-password.html:40
|
||||||
msgid "Login page"
|
msgid "Login page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/forgotten-password.html:12
|
#: canaille/templates/forgotten-password.html:11
|
||||||
#: canaille/templates/login.html:38 canaille/templates/password.html:35
|
#: canaille/templates/login.html:35 canaille/templates/password.html:32
|
||||||
msgid "Forgotten password"
|
msgid "Forgotten password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/forgotten-password.html:19
|
#: canaille/templates/forgotten-password.html:16
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" After this form is sent, if the email address or the login you "
|
" After this form is sent, if the email address or the login you "
|
||||||
|
@ -463,181 +494,230 @@ msgid ""
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/forgotten-password.html:38
|
#: canaille/templates/forgotten-password.html:35
|
||||||
#: canaille/templates/profile.html:120 canaille/templates/profile.html:143
|
#: canaille/templates/profile.html:117 canaille/templates/profile.html:140
|
||||||
msgid "Send again"
|
msgid "Send again"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/forgotten-password.html:40
|
#: canaille/templates/forgotten-password.html:37
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/login.html:17
|
#: canaille/templates/group.html:13
|
||||||
|
msgid "Group deletion"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:17
|
||||||
|
msgid ""
|
||||||
|
"Are you sure you want to delete this group? This action is unrevokable "
|
||||||
|
"and all the data about this group will be removed."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/admin/client_edit.html:18
|
||||||
|
#: canaille/templates/group.html:21 canaille/templates/profile.html:25
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/admin/client_edit.html:19
|
||||||
|
#: canaille/templates/group.html:22 canaille/templates/profile.html:26
|
||||||
|
msgid "Delete"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:29
|
||||||
|
msgid "Members"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:45
|
||||||
|
msgid "Group creation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:47
|
||||||
|
msgid "Group edition"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:53
|
||||||
|
msgid "Create a new group"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:55
|
||||||
|
msgid "Edit informations about a group"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:70
|
||||||
|
msgid ""
|
||||||
|
"Because group cannot be empty, you will be added to the group. You can "
|
||||||
|
"remove you later by editing your profile when you will have added other "
|
||||||
|
"members to the group."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:75
|
||||||
|
msgid "Create group"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:77 canaille/templates/profile.html:154
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/group.html:82
|
||||||
|
msgid "Delete group"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/groups.html:5
|
||||||
|
msgid "Add a group"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/login.html:16
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Sign in at %(website)s"
|
msgid "Sign in at %(website)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/login.html:19
|
#: canaille/templates/login.html:18
|
||||||
msgid "Log-in and manage your authorizations."
|
msgid "Log-in and manage your authorizations."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/login.html:37
|
#: canaille/templates/login.html:34
|
||||||
msgid "Continue"
|
msgid "Continue"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/password.html:17
|
#: canaille/templates/password.html:16
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Sign in as %(username)s"
|
msgid "Sign in as %(username)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/password.html:19
|
#: canaille/templates/password.html:18
|
||||||
msgid "Please enter your password for this account."
|
msgid "Please enter your password for this account."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/password.html:34
|
#: canaille/templates/password.html:31
|
||||||
msgid "Sign in"
|
msgid "Sign in"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/password.html:36
|
#: canaille/templates/password.html:33
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "I am not %(username)s"
|
msgid "I am not %(username)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:14
|
#: canaille/templates/profile.html:13
|
||||||
msgid "Account deletion"
|
msgid "Account deletion"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:19
|
#: canaille/templates/profile.html:18
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to delete this user? This action is unrevokable and"
|
"Are you sure you want to delete this user? This action is unrevokable and"
|
||||||
" all the data about this user will be removed."
|
" all the data about this user will be removed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:21
|
#: canaille/templates/profile.html:20
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to delete your account? This action is unrevokable "
|
"Are you sure you want to delete your account? This action is unrevokable "
|
||||||
"and all your data will be removed forever."
|
"and all your data will be removed forever."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:19
|
#: canaille/templates/profile.html:35
|
||||||
#: canaille/templates/profile.html:26
|
|
||||||
msgid "Cancel"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:20
|
|
||||||
#: canaille/templates/profile.html:27
|
|
||||||
msgid "Delete"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: canaille/templates/profile.html:36
|
|
||||||
msgid "User creation"
|
msgid "User creation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:40
|
#: canaille/templates/profile.html:39
|
||||||
msgid "User profile edition"
|
msgid "User profile edition"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:46
|
#: canaille/templates/profile.html:45
|
||||||
msgid "Create a new user account"
|
msgid "Create a new user account"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:48
|
#: canaille/templates/profile.html:47
|
||||||
msgid "Edit your personal informations"
|
msgid "Edit your personal informations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:50
|
#: canaille/templates/profile.html:49
|
||||||
msgid "Edit informations about an user"
|
msgid "Edit informations about an user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:67
|
#: canaille/templates/profile.html:64
|
||||||
msgid "Personal information"
|
msgid "Personal information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:89
|
#: canaille/templates/profile.html:86
|
||||||
msgid "Account information"
|
msgid "Account information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:105
|
#: canaille/templates/profile.html:102
|
||||||
msgid "User password is not mandatory"
|
msgid "User password is not mandatory"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:107
|
#: canaille/templates/profile.html:104
|
||||||
msgid "The user password can be set:"
|
msgid "The user password can be set:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:109
|
#: canaille/templates/profile.html:106
|
||||||
msgid "by filling this form;"
|
msgid "by filling this form;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:110
|
#: canaille/templates/profile.html:107
|
||||||
msgid ""
|
msgid ""
|
||||||
"by sending the user a password initialization mail, after the account "
|
"by sending the user a password initialization mail, after the account "
|
||||||
"creation;"
|
"creation;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:111 canaille/templates/profile.html:134
|
#: canaille/templates/profile.html:108 canaille/templates/profile.html:131
|
||||||
msgid ""
|
msgid ""
|
||||||
"or simply waiting for the user to sign-in a first time, and then receive "
|
"or simply waiting for the user to sign-in a first time, and then receive "
|
||||||
"a password initialization mail."
|
"a password initialization mail."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:124
|
#: canaille/templates/profile.html:121
|
||||||
msgid "Send email"
|
msgid "Send email"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:128
|
#: canaille/templates/profile.html:125
|
||||||
msgid "This user does not have a password yet"
|
msgid "This user does not have a password yet"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:130
|
#: canaille/templates/profile.html:127
|
||||||
msgid "You can solve this by:"
|
msgid "You can solve this by:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:132
|
#: canaille/templates/profile.html:129
|
||||||
msgid "setting a password using this form;"
|
msgid "setting a password using this form;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:133
|
#: canaille/templates/profile.html:130
|
||||||
msgid "sending the user a password initialization mail, by clicking this button;"
|
msgid "sending the user a password initialization mail, by clicking this button;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:145
|
#: canaille/templates/profile.html:142
|
||||||
msgid "Send mail"
|
msgid "Send mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:149
|
#: canaille/templates/profile.html:146
|
||||||
#: canaille/templates/reset-password.html:12
|
#: canaille/templates/reset-password.html:11
|
||||||
#: canaille/templates/reset-password.html:19
|
#: canaille/templates/reset-password.html:16
|
||||||
msgid "Password reset"
|
msgid "Password reset"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:151
|
#: canaille/templates/profile.html:148
|
||||||
msgid ""
|
msgid ""
|
||||||
"If the user has forgotten his password, you can send him a password reset"
|
"If the user has forgotten his password, you can send him a password reset"
|
||||||
" email by clicking this button."
|
" email by clicking this button."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:157
|
#: canaille/templates/profile.html:158
|
||||||
msgid "Submit"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: canaille/templates/profile.html:161
|
|
||||||
msgid "Impersonate"
|
msgid "Impersonate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:167
|
#: canaille/templates/profile.html:164
|
||||||
msgid "Delete the user"
|
msgid "Delete the user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/profile.html:169
|
#: canaille/templates/profile.html:166
|
||||||
msgid "Delete my account"
|
msgid "Delete my account"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/users.html:17
|
#: canaille/templates/users.html:16
|
||||||
msgid "Add a user"
|
msgid "Add a user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/users.html:23
|
#: canaille/templates/users.html:22
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -657,66 +737,66 @@ msgid "Subject"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/authorization_list.html:21
|
#: canaille/templates/admin/authorization_list.html:21
|
||||||
#: canaille/templates/admin/client_list.html:27
|
#: canaille/templates/admin/client_list.html:24
|
||||||
#: canaille/templates/admin/token_list.html:21
|
#: canaille/templates/admin/token_list.html:21
|
||||||
msgid "Created"
|
msgid "Created"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/authorization_view.html:8
|
#: canaille/templates/admin/authorization_view.html:7
|
||||||
msgid "View a authorization"
|
msgid "View a authorization"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_add.html:8
|
#: canaille/templates/admin/client_add.html:7
|
||||||
msgid "Add a client"
|
msgid "Add a client"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_add.html:14
|
#: canaille/templates/admin/client_add.html:11
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:13
|
#: canaille/templates/admin/client_edit.html:12
|
||||||
msgid "Client deletion"
|
msgid "Client deletion"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:16
|
#: canaille/templates/admin/client_edit.html:15
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to delete this client? This action is unrevokable "
|
"Are you sure you want to delete this client? This action is unrevokable "
|
||||||
"and all the data about this client will be removed."
|
"and all the data about this client will be removed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:26
|
#: canaille/templates/admin/client_edit.html:25
|
||||||
msgid "Edit a client"
|
msgid "Edit a client"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:35
|
#: canaille/templates/admin/client_edit.html:32
|
||||||
msgid "ID"
|
msgid "ID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:39
|
#: canaille/templates/admin/client_edit.html:36
|
||||||
msgid "Secret"
|
msgid "Secret"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:43
|
#: canaille/templates/admin/client_edit.html:40
|
||||||
msgid "Issued at"
|
msgid "Issued at"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:60
|
#: canaille/templates/admin/client_edit.html:57
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_edit.html:63
|
#: canaille/templates/admin/client_edit.html:60
|
||||||
msgid "Delete the client"
|
msgid "Delete the client"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_list.html:20
|
#: canaille/templates/admin/client_list.html:17
|
||||||
msgid "Add client"
|
msgid "Add client"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/client_list.html:26
|
#: canaille/templates/admin/client_list.html:23
|
||||||
msgid "URL"
|
msgid "URL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/admin/token_view.html:8
|
#: canaille/templates/admin/token_view.html:7
|
||||||
msgid "View a token"
|
msgid "View a token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ def create_app():
|
||||||
server_metadata_url=get_well_known_url(
|
server_metadata_url=get_well_known_url(
|
||||||
app.config["OAUTH_AUTH_SERVER"], external=True
|
app.config["OAUTH_AUTH_SERVER"], external=True
|
||||||
),
|
),
|
||||||
client_kwargs={"scope": "openid profile email"},
|
client_kwargs={"scope": "openid profile email groups"},
|
||||||
)
|
)
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
|
|
|
@ -53,7 +53,10 @@
|
||||||
<h2 class="ui header">{{ name }}</h2>
|
<h2 class="ui header">{{ name }}</h2>
|
||||||
<div>
|
<div>
|
||||||
{% if user %}
|
{% if user %}
|
||||||
Welcome {{ user.name }}
|
<p>Welcome {{ user.name }}</p>
|
||||||
|
{% if user.groups %}
|
||||||
|
<p>You're a member of the following groups: {{ user.groups }}</p>
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
Welcome, please <a href="{{ url_for('login') }}">log-in</a>.
|
Welcome, please <a href="{{ url_for('login') }}">log-in</a>.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
"http://localhost:5000/oauth/register",
|
"http://localhost:5000/oauth/register",
|
||||||
"scopes_supported":
|
"scopes_supported":
|
||||||
["openid", "profile", "email", "address",
|
["openid", "profile", "email", "address",
|
||||||
"phone"],
|
"phone", "groups"],
|
||||||
"response_types_supported":
|
"response_types_supported":
|
||||||
["code", "token", "id_token", "code token",
|
["code", "token", "id_token", "code token",
|
||||||
"code id_token", "token id_token"],
|
"code id_token", "token id_token"],
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
"http://localhost:5000/oauth/register",
|
"http://localhost:5000/oauth/register",
|
||||||
"scopes_supported":
|
"scopes_supported":
|
||||||
["openid", "profile", "email", "address",
|
["openid", "profile", "email", "address",
|
||||||
"phone"],
|
"phone", "groups"],
|
||||||
"response_types_supported":
|
"response_types_supported":
|
||||||
["code", "token", "id_token", "code token",
|
["code", "token", "id_token", "code token",
|
||||||
"code id_token", "token id_token"],
|
"code id_token", "token id_token"],
|
||||||
|
|
|
@ -94,6 +94,7 @@ oauthGrantType: refresh_token
|
||||||
oauthScope: openid
|
oauthScope: openid
|
||||||
oauthScope: profile
|
oauthScope: profile
|
||||||
oauthScope: email
|
oauthScope: email
|
||||||
|
oauthScope: groups
|
||||||
oauthResponseType: code
|
oauthResponseType: code
|
||||||
oauthResponseType: id_token
|
oauthResponseType: id_token
|
||||||
oauthTokenEndpointAuthMethod: client_secret_basic
|
oauthTokenEndpointAuthMethod: client_secret_basic
|
||||||
|
@ -111,6 +112,7 @@ oauthGrantType: refresh_token
|
||||||
oauthScope: openid
|
oauthScope: openid
|
||||||
oauthScope: profile
|
oauthScope: profile
|
||||||
oauthScope: email
|
oauthScope: email
|
||||||
|
oauthScope: groups
|
||||||
oauthResponseType: code
|
oauthResponseType: code
|
||||||
oauthResponseType: id_token
|
oauthResponseType: id_token
|
||||||
oauthTokenEndpointAuthMethod: client_secret_basic
|
oauthTokenEndpointAuthMethod: client_secret_basic
|
||||||
|
|
|
@ -215,7 +215,7 @@ def client(app, slapd_connection):
|
||||||
"refresh_token",
|
"refresh_token",
|
||||||
],
|
],
|
||||||
oauthResponseType=["code", "token", "id_token"],
|
oauthResponseType=["code", "token", "id_token"],
|
||||||
oauthScope=["openid", "profile"],
|
oauthScope=["openid", "profile", "groups"],
|
||||||
oauthTermsOfServiceURI="https://mydomain.tld/tos",
|
oauthTermsOfServiceURI="https://mydomain.tld/tos",
|
||||||
oauthPolicyURI="https://mydomain.tld/policy",
|
oauthPolicyURI="https://mydomain.tld/policy",
|
||||||
oauthJWKURI="https://mydomain.tld/jwk",
|
oauthJWKURI="https://mydomain.tld/jwk",
|
||||||
|
@ -361,7 +361,9 @@ def foo_group(app, user, slapd_connection):
|
||||||
g.save(slapd_connection)
|
g.save(slapd_connection)
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
user.load_groups(conn=slapd_connection)
|
user.load_groups(conn=slapd_connection)
|
||||||
return g
|
yield g
|
||||||
|
user._groups = []
|
||||||
|
g.delete(conn=slapd_connection)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -375,9 +377,6 @@ def bar_group(app, admin, slapd_connection):
|
||||||
g.save(slapd_connection)
|
g.save(slapd_connection)
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
admin.load_groups(conn=slapd_connection)
|
admin.load_groups(conn=slapd_connection)
|
||||||
return g
|
yield g
|
||||||
|
admin._groups = []
|
||||||
|
g.delete(conn=slapd_connection)
|
||||||
@pytest.fixture
|
|
||||||
def groups(foo_group, bar_group, slapd_connection):
|
|
||||||
return (foo_group, bar_group)
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ def test_authorization_code_flow(testclient, slapd_connection, logged_user, clie
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
status=200,
|
status=200,
|
||||||
)
|
)
|
||||||
assert {"name": "John Doe", "family_name": "Doe", "sub": "user"} == res.json
|
assert {"name": "John Doe", "family_name": "Doe", "sub": "user", "groups": []} == res.json
|
||||||
|
|
||||||
|
|
||||||
def test_logout_login(testclient, slapd_connection, logged_user, client):
|
def test_logout_login(testclient, slapd_connection, logged_user, client):
|
||||||
|
@ -105,7 +105,7 @@ def test_logout_login(testclient, slapd_connection, logged_user, client):
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
status=200,
|
status=200,
|
||||||
)
|
)
|
||||||
assert {"name": "John Doe", "family_name": "Doe", "sub": "user"} == res.json
|
assert {"name": "John Doe", "family_name": "Doe", "sub": "user", "groups": []} == res.json
|
||||||
|
|
||||||
|
|
||||||
def test_refresh_token(testclient, slapd_connection, logged_user, client):
|
def test_refresh_token(testclient, slapd_connection, logged_user, client):
|
||||||
|
@ -164,7 +164,7 @@ def test_refresh_token(testclient, slapd_connection, logged_user, client):
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
status=200,
|
status=200,
|
||||||
)
|
)
|
||||||
assert {"name": "John Doe", "family_name": "Doe", "sub": "user"} == res.json
|
assert {"name": "John Doe", "family_name": "Doe", "sub": "user", "groups": []} == res.json
|
||||||
|
|
||||||
|
|
||||||
def test_code_challenge(testclient, slapd_connection, logged_user, client):
|
def test_code_challenge(testclient, slapd_connection, logged_user, client):
|
||||||
|
@ -218,7 +218,7 @@ def test_code_challenge(testclient, slapd_connection, logged_user, client):
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
status=200,
|
status=200,
|
||||||
)
|
)
|
||||||
assert {"name": "John Doe", "family_name": "Doe", "sub": "user"} == res.json
|
assert {"name": "John Doe", "family_name": "Doe", "sub": "user", "groups": []} == res.json
|
||||||
|
|
||||||
client.oauthTokenEndpointAuthMethod = "client_secret_basic"
|
client.oauthTokenEndpointAuthMethod = "client_secret_basic"
|
||||||
client.save(slapd_connection)
|
client.save(slapd_connection)
|
||||||
|
|
|
@ -9,7 +9,7 @@ def test_no_group(app, slapd_connection):
|
||||||
def test_set_groups(app, slapd_connection, user, foo_group, bar_group):
|
def test_set_groups(app, slapd_connection, user, foo_group, bar_group):
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
Group.attr_type_by_name(conn=slapd_connection)
|
Group.attr_type_by_name(conn=slapd_connection)
|
||||||
a = User.attr_type_by_name(conn=slapd_connection)
|
User.attr_type_by_name(conn=slapd_connection)
|
||||||
|
|
||||||
user = User.get(dn=user.dn, conn=slapd_connection)
|
user = User.get(dn=user.dn, conn=slapd_connection)
|
||||||
assert set(Group.available_groups(conn=slapd_connection)) == {
|
assert set(Group.available_groups(conn=slapd_connection)) == {
|
||||||
|
@ -21,14 +21,80 @@ def test_set_groups(app, slapd_connection, user, foo_group, bar_group):
|
||||||
assert user.groups[0].dn == foo_group.dn
|
assert user.groups[0].dn == foo_group.dn
|
||||||
|
|
||||||
user.set_groups([foo_group, bar_group], conn=slapd_connection)
|
user.set_groups([foo_group, bar_group], conn=slapd_connection)
|
||||||
|
|
||||||
bar_dns = {g.dn for g in bar_group.get_members(conn=slapd_connection)}
|
bar_dns = {g.dn for g in bar_group.get_members(conn=slapd_connection)}
|
||||||
assert user.dn in bar_dns
|
assert user.dn in bar_dns
|
||||||
|
|
||||||
assert user.groups[1].dn == bar_group.dn
|
assert user.groups[1].dn == bar_group.dn
|
||||||
|
|
||||||
user.set_groups([foo_group], conn=slapd_connection)
|
user.set_groups([foo_group], conn=slapd_connection)
|
||||||
|
|
||||||
foo_dns = {g.dn for g in foo_group.get_members(conn=slapd_connection)}
|
foo_dns = {g.dn for g in foo_group.get_members(conn=slapd_connection)}
|
||||||
bar_dns = {g.dn for g in bar_group.get_members(conn=slapd_connection)}
|
bar_dns = {g.dn for g in bar_group.get_members(conn=slapd_connection)}
|
||||||
|
|
||||||
assert user.dn in foo_dns
|
assert user.dn in foo_dns
|
||||||
assert user.dn not in bar_dns
|
assert user.dn not in bar_dns
|
||||||
|
|
||||||
|
|
||||||
|
def test_moderator_can_create_edit_and_delete_group(
|
||||||
|
testclient, slapd_connection, logged_moderator, foo_group
|
||||||
|
):
|
||||||
|
# The group does not exist
|
||||||
|
res = testclient.get("/groups", status=200)
|
||||||
|
with testclient.app.app_context():
|
||||||
|
assert Group.get("bar", conn=slapd_connection) is None
|
||||||
|
assert Group.get("foo", conn=slapd_connection) == foo_group
|
||||||
|
assert "bar" not in res.text
|
||||||
|
assert "foo" in res.text
|
||||||
|
|
||||||
|
# Fill the form for a new group
|
||||||
|
res = testclient.get("/groups/add", status=200)
|
||||||
|
res.form["name"] = "bar"
|
||||||
|
|
||||||
|
# Group has been created
|
||||||
|
res = res.form.submit(status=302).follow(status=200)
|
||||||
|
|
||||||
|
with testclient.app.app_context():
|
||||||
|
bar_group = Group.get("bar", conn=slapd_connection)
|
||||||
|
assert bar_group.name == "bar"
|
||||||
|
assert [
|
||||||
|
member.dn for member in bar_group.get_members(conn=slapd_connection)
|
||||||
|
] == [
|
||||||
|
logged_moderator.dn
|
||||||
|
] # Group cannot be empty so creator is added in it
|
||||||
|
assert "bar" in res.text
|
||||||
|
|
||||||
|
# Group name can not be edited
|
||||||
|
res = testclient.get("/groups/bar", status=200)
|
||||||
|
res.form["name"] = "bar2"
|
||||||
|
|
||||||
|
res = res.form.submit(name="action", value="edit", status=200)
|
||||||
|
|
||||||
|
with testclient.app.app_context():
|
||||||
|
bar_group = Group.get("bar", conn=slapd_connection)
|
||||||
|
assert bar_group.name == "bar"
|
||||||
|
assert Group.get("bar2", conn=slapd_connection) is None
|
||||||
|
members = bar_group.get_members(conn=slapd_connection)
|
||||||
|
for member in members:
|
||||||
|
assert member.name in res.text
|
||||||
|
|
||||||
|
# Group is deleted
|
||||||
|
res = res.form.submit(name="action", value="delete", status=302).follow(status=200)
|
||||||
|
with testclient.app.app_context():
|
||||||
|
assert Group.get("bar", conn=slapd_connection) is None
|
||||||
|
assert "The group bar has been sucessfully deleted" in res.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_cannot_create_already_existing_group(
|
||||||
|
testclient, slapd_connection, logged_moderator, foo_group
|
||||||
|
):
|
||||||
|
res = testclient.post("/groups/add", {"name": "foo"}, status=200)
|
||||||
|
|
||||||
|
assert "Group creation failed." in res
|
||||||
|
assert "The group 'foo' already exists" in res
|
||||||
|
|
||||||
|
|
||||||
|
def test_simple_user_cannot_view_or_edit_groups(
|
||||||
|
testclient, slapd_connection, logged_user, foo_group
|
||||||
|
):
|
||||||
|
testclient.get("/groups", status=403)
|
||||||
|
testclient.get("/groups/add", status=403)
|
||||||
|
testclient.get("/groups/foo", status=403)
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from authlib.jose import jwt
|
from authlib.jose import jwt
|
||||||
from urllib.parse import urlsplit, parse_qs
|
from urllib.parse import urlsplit, parse_qs
|
||||||
from canaille.models import AuthorizationCode, Token
|
from canaille.models import AuthorizationCode, Token, User
|
||||||
|
|
||||||
|
|
||||||
def test_oauth_hybrid(testclient, slapd_connection, user, client):
|
def test_oauth_hybrid(testclient, slapd_connection, user, client):
|
||||||
|
User.attr_type_by_name(slapd_connection)
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/authorize",
|
"/oauth/authorize",
|
||||||
params=dict(
|
params=dict(
|
||||||
|
@ -41,7 +42,7 @@ def test_oauth_hybrid(testclient, slapd_connection, user, client):
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
status=200,
|
status=200,
|
||||||
)
|
)
|
||||||
assert {"name": "John Doe", "family_name": "Doe", "sub": "user"} == res.json
|
assert {"name": "John Doe", "family_name": "Doe", "sub": "user", "groups": []} == res.json
|
||||||
|
|
||||||
|
|
||||||
def test_oidc_hybrid(testclient, slapd_connection, logged_user, client, keypair):
|
def test_oidc_hybrid(testclient, slapd_connection, logged_user, client, keypair):
|
||||||
|
@ -80,4 +81,4 @@ def test_oidc_hybrid(testclient, slapd_connection, logged_user, client, keypair)
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
status=200,
|
status=200,
|
||||||
)
|
)
|
||||||
assert {"name": "John Doe", "family_name": "Doe", "sub": "user"} == res.json
|
assert {"name": "John Doe", "family_name": "Doe", "sub": "user", "groups": []} == res.json
|
||||||
|
|
|
@ -40,7 +40,7 @@ def test_oauth_implicit(testclient, slapd_connection, user, client):
|
||||||
"/oauth/userinfo", headers={"Authorization": f"Bearer {access_token}"}
|
"/oauth/userinfo", headers={"Authorization": f"Bearer {access_token}"}
|
||||||
)
|
)
|
||||||
assert "application/json" == res.content_type
|
assert "application/json" == res.content_type
|
||||||
assert {"name": "John Doe", "sub": "user", "family_name": "Doe"} == res.json
|
assert {"name": "John Doe", "sub": "user", "family_name": "Doe", "groups": []} == res.json
|
||||||
|
|
||||||
client.oauthGrantType = ["code"]
|
client.oauthGrantType = ["code"]
|
||||||
client.oauthTokenEndpointAuthMethod = "client_secret_basic"
|
client.oauthTokenEndpointAuthMethod = "client_secret_basic"
|
||||||
|
@ -92,7 +92,60 @@ def test_oidc_implicit(testclient, keypair, slapd_connection, user, client):
|
||||||
status=200,
|
status=200,
|
||||||
)
|
)
|
||||||
assert "application/json" == res.content_type
|
assert "application/json" == res.content_type
|
||||||
assert {"name": "John Doe", "sub": "user", "family_name": "Doe"} == res.json
|
assert {"name": "John Doe", "sub": "user", "family_name": "Doe", "groups": []} == res.json
|
||||||
|
|
||||||
|
client.oauthGrantType = ["code"]
|
||||||
|
client.oauthTokenEndpointAuthMethod = "client_secret_basic"
|
||||||
|
client.save(slapd_connection)
|
||||||
|
|
||||||
|
|
||||||
|
def test_oidc_implicit_with_group(testclient, keypair, slapd_connection, user, client, foo_group):
|
||||||
|
client.oauthGrantType = ["token id_token"]
|
||||||
|
client.oauthTokenEndpointAuthMethod = "none"
|
||||||
|
|
||||||
|
client.save(slapd_connection)
|
||||||
|
|
||||||
|
res = testclient.get(
|
||||||
|
"/oauth/authorize",
|
||||||
|
params=dict(
|
||||||
|
response_type="id_token token",
|
||||||
|
client_id=client.oauthClientID,
|
||||||
|
scope="openid profile groups",
|
||||||
|
nonce="somenonce",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assert "text/html" == res.content_type
|
||||||
|
|
||||||
|
res.form["login"] = "user"
|
||||||
|
res.form["password"] = "correct horse battery staple"
|
||||||
|
res = res.form.submit(status=302)
|
||||||
|
|
||||||
|
res = res.follow(status=200)
|
||||||
|
assert "text/html" == res.content_type, res.json
|
||||||
|
|
||||||
|
res = res.form.submit(name="answer", value="accept", status=302)
|
||||||
|
|
||||||
|
assert res.location.startswith(client.oauthRedirectURIs[0])
|
||||||
|
params = parse_qs(urlsplit(res.location).fragment)
|
||||||
|
|
||||||
|
access_token = params["access_token"][0]
|
||||||
|
token = Token.get(access_token, conn=slapd_connection)
|
||||||
|
assert token is not None
|
||||||
|
|
||||||
|
id_token = params["id_token"][0]
|
||||||
|
claims = jwt.decode(id_token, keypair[1])
|
||||||
|
assert user.uid[0] == claims["sub"]
|
||||||
|
assert user.cn[0] == claims["name"]
|
||||||
|
assert [client.oauthClientID] == claims["aud"]
|
||||||
|
assert ["foo"] == claims["groups"]
|
||||||
|
|
||||||
|
res = testclient.get(
|
||||||
|
"/oauth/userinfo",
|
||||||
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
|
status=200,
|
||||||
|
)
|
||||||
|
assert "application/json" == res.content_type
|
||||||
|
assert {"name": "John Doe", "sub": "user", "family_name": "Doe", "groups": ["foo"]} == res.json
|
||||||
|
|
||||||
client.oauthGrantType = ["code"]
|
client.oauthGrantType = ["code"]
|
||||||
client.oauthTokenEndpointAuthMethod = "client_secret_basic"
|
client.oauthTokenEndpointAuthMethod = "client_secret_basic"
|
||||||
|
|
|
@ -15,7 +15,7 @@ def test_password_flow(testclient, slapd_connection, user, client):
|
||||||
status=200,
|
status=200,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert res.json["scope"] == "openid profile"
|
assert res.json["scope"] == "openid profile groups"
|
||||||
assert res.json["token_type"] == "Bearer"
|
assert res.json["token_type"] == "Bearer"
|
||||||
access_token = res.json["access_token"]
|
access_token = res.json["access_token"]
|
||||||
|
|
||||||
|
@ -27,4 +27,4 @@ def test_password_flow(testclient, slapd_connection, user, client):
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
status=200,
|
status=200,
|
||||||
)
|
)
|
||||||
assert {"name": "John Doe", "sub": "user", "family_name": "Doe"} == res.json
|
assert {"name": "John Doe", "sub": "user", "family_name": "Doe", "groups": []} == res.json
|
||||||
|
|
Loading…
Reference in a new issue