Add CRUD views for UserAccess

This commit is contained in:
Ivan Habunek 2019-07-04 13:16:00 +02:00 committed by Drew DeVault
parent eef166ade5
commit 9b26e7cbf3
3 changed files with 156 additions and 10 deletions

View File

@ -6,8 +6,8 @@ from todosrht.access import get_tracker
from todosrht.search import apply_search
from todosrht.tickets import get_last_seen_times, get_comment_counts
from todosrht.tickets import submit_ticket
from todosrht.types import TicketSubscription
from todosrht.types import Event
from todosrht.types import TicketSubscription, User
from todosrht.types import Event, UserAccess
from todosrht.types import Tracker, Ticket, TicketAccess
from todosrht.types import Label, TicketLabel
from todosrht.urls import tracker_url, ticket_url
@ -208,6 +208,13 @@ def settings_details_POST(owner, name):
db.session.commit()
return redirect(tracker_url(tracker))
def render_tracker_access(tracker, **kwargs):
return render_template("tracker-access.html",
view="access", tracker=tracker, access_type_list=TicketAccess,
access_help_map=access_help_map, **kwargs)
@tracker.route("/<owner>/<name>/settings/access")
@loginrequired
def settings_access_GET(owner, name):
@ -216,10 +223,7 @@ def settings_access_GET(owner, name):
abort(404)
if current_user.id != tracker.owner_id:
abort(403)
return render_template("tracker-access.html",
view="access", tracker=tracker,
access_type_list=TicketAccess,
access_help_map=access_help_map)
return render_tracker_access(tracker)
@tracker.route("/<owner>/<name>/settings/access", methods=["POST"])
@loginrequired
@ -236,9 +240,7 @@ def settings_access_POST(owner, name):
perm_submit = parse_html_perms('submit', valid)
if not valid.ok:
return render_template("tracker-access.html",
tracker=tracker, access_type_list=TicketAccess,
access_help_map=access_help_map, **valid.kwargs), 400
return render_tracker_access(tracker, **valid.kwargs), 400
tracker.default_anonymous_perms = perm_anon
tracker.default_user_perms = perm_user
@ -251,6 +253,61 @@ def settings_access_POST(owner, name):
db.session.commit()
return redirect(tracker_url(tracker))
@tracker.route("/<owner>/<name>/settings/user-access/create", methods=["POST"])
@loginrequired
def settings_user_access_create_POST(owner, name):
tracker, access = get_tracker(owner, name)
if not tracker:
abort(404)
if current_user.id != tracker.owner_id:
abort(403)
valid = Validation(request)
username = valid.require("username")
permissions = parse_html_perms("user_access", valid)
if not valid.ok:
return render_tracker_access(tracker, **valid.kwargs), 400
username = username.lstrip("~")
user = User.query.filter_by(username=username).one_or_none()
valid.expect(user, "User not found.", field="username")
if not valid.ok:
return render_tracker_access(tracker, **valid.kwargs), 400
existing = UserAccess.query.filter_by(user=user, tracker=tracker).count()
valid.expect(user != tracker.owner,
"Cannot override tracker owner's permissions.", field="username")
valid.expect(existing == 0,
"This user already has custom permissions assigned.", field="username")
if not valid.ok:
return render_tracker_access(tracker, **valid.kwargs), 400
ua = UserAccess(tracker=tracker, user=user, permissions=permissions)
db.session.add(ua)
db.session.commit()
return redirect(url_for("tracker.settings_access_GET",
owner=tracker.owner.canonical_name,
name=name))
@tracker.route("/<owner>/<name>/settings/user-access/<user_id>/delete",
methods=["POST"])
@loginrequired
def settings_user_access_delete_POST(owner, name, user_id):
tracker, access = get_tracker(owner, name)
if not tracker:
abort(404)
if current_user.id != tracker.owner_id:
abort(403)
UserAccess.query.filter_by(user_id=user_id, tracker_id=tracker.id).delete()
db.session.commit()
return redirect(url_for("tracker.settings_access_GET",
owner=tracker.owner.canonical_name,
name=name))
@tracker.route("/<owner>/<name>/settings/delete")
@loginrequired
def settings_delete_GET(owner, name):

View File

@ -87,6 +87,94 @@
</button>
</span>
</form>
<div class="clearfix"></div>
<h4>User permissions</h4>
<p>Here you may override permissions for specific users.</p>
{% if tracker.user_accesses %}
<table class="table">
<tbody>
{% for user_access in tracker.user_accesses %}
<tr>
<td>{{ user_access.user }}</td>
<td>
{% if user_access.permissions.name in ["all", "none"] %}
{{ user_access.permissions.name }}
{% else %}
{% for type in access_type_list
if type and type in user_access.permissions %}
{{ type.name }}{% if not loop.last %},{% endif %}
{% endfor %}
{% endif %}
</td>
<td>{{ user_access.created|date }}</td>
<td>
<form
action="{{ url_for(".settings_user_access_delete_POST",
owner=tracker.owner.canonical_name,
name=tracker.name,
user_id=user_access.user_id) }}"
method="POST"
style="margin: 0"
>
{{ csrf_token() }}
<button type="submit" class="btn btn-link btn-block">
(remove)
</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
<form
method="POST"
class="form-horizontal"
action="{{ url_for(".settings_user_access_create_POST",
owner=tracker.owner.canonical_name,
name=tracker.name) }}"
>
{{ csrf_token() }}
<div class="event-list">
<div class="event">
<h4>Add user permissions</h4>
<div class="form-group" style="margin-top: 1rem">
<label for="username">User</label>
<input
type="text"
class="form-control {{valid.cls("username")}}"
id="username"
name="username"
placeholder="~{{ current_user.username }}"
value="{{username or ""}}"
/>
{{ valid.summary("username") }}
</div>
<p>Permissions</p>
<div class="form-group">
{% for a in access_type_list %}
{{ perm_checkbox(a, TicketAccess.all, "user_access") }}
{% endfor %}
{{ valid.summary("user_access") }}
</div>
</div>
</div>
<span class="pull-right">
<button type="submit" class="btn btn-primary">
Add {{icon("caret-right")}}
</button>
</span>
</form>
</div>
</div>
{% endblock %}

View File

@ -13,7 +13,8 @@ class UserAccess(Base):
tracker_id = sa.Column(sa.Integer,
sa.ForeignKey("tracker.id", ondelete="CASCADE"), nullable=False)
tracker = sa.orm.relationship("Tracker")
tracker = sa.orm.relationship("Tracker",
backref=sa.orm.backref("user_accesses"))
user_id = sa.Column(sa.Integer,
sa.ForeignKey("user.id", ondelete="CASCADE"), nullable=False)