1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-09-20 03:11:04 +00:00

New feature: Now admins can edit users profiles

This commit is contained in:
Óscar García Amor 2017-07-11 16:43:55 +02:00
parent 3c2f1651a3
commit 97fb5232e5
7 changed files with 202 additions and 38 deletions

View File

@ -39,20 +39,33 @@ def check_admin():
def user_index(): def user_index():
return render_template('users.html', users = store.find(User), admin = UserManager.get(store, session.get('userid'))[1].admin) return render_template('users.html', users = store.find(User), admin = UserManager.get(store, session.get('userid'))[1].admin)
@app.route('/user/me') @app.route('/user/<uid>')
def user_profile(): def user_profile(uid):
if uid == 'me':
prefs = store.find(ClientPrefs, ClientPrefs.user_id == uuid.UUID(session.get('userid'))) prefs = store.find(ClientPrefs, ClientPrefs.user_id == uuid.UUID(session.get('userid')))
return render_template('profile.html', user = UserManager.get(store, session.get('userid'))[1], api_key = config.get('lastfm', 'api_key'), clients = prefs, admin = UserManager.get(store, session.get('userid'))[1].admin) return render_template('profile.html', user = UserManager.get(store, session.get('userid'))[1], api_key = config.get('lastfm', 'api_key'), clients = prefs, admin = UserManager.get(store, session.get('userid'))[1].admin)
else:
if not UserManager.get(store, session.get('userid'))[1].admin:
return redirect(url_for('index'))
prefs = store.find(ClientPrefs, ClientPrefs.user_id == uuid.UUID(uid))
return render_template('profile.html', user = UserManager.get(store, uuid.UUID(uid))[1], api_key = config.get('lastfm', 'api_key'), clients = prefs, admin = UserManager.get(store, session.get('userid'))[1].admin)
@app.route('/user/me', methods = [ 'POST' ]) @app.route('/user/<uid>', methods = [ 'POST' ])
def update_clients(): def update_clients(uid):
clients_opts = {} clients_opts = {}
for client in set(map(lambda k: k.rsplit('_', 1)[0], request.form.keys())): for client in set(map(lambda k: k.rsplit('_', 1)[0], request.form.keys())):
clients_opts[client] = { k.rsplit('_', 1)[1]: v for k, v in filter(lambda (k, v): k.startswith(client), request.form.iteritems()) } clients_opts[client] = { k.rsplit('_', 1)[1]: v for k, v in filter(lambda (k, v): k.startswith(client), request.form.iteritems()) }
app.logger.debug(clients_opts) app.logger.debug(clients_opts)
if uid == 'me':
userid = uuid.UUID(session.get('userid'))
else:
if not UserManager.get(store, session.get('userid'))[1].admin:
return redirect(url_for('index'))
userid = uuid.UUID(uid)
for client, opts in clients_opts.iteritems(): for client, opts in clients_opts.iteritems():
prefs = store.get(ClientPrefs, (uuid.UUID(session.get('userid')), client)) prefs = store.get(ClientPrefs, (userid, client))
if 'delete' in opts and opts['delete'] in [ 'on', 'true', 'checked', 'selected', '1' ]: if 'delete' in opts and opts['delete'] in [ 'on', 'true', 'checked', 'selected', '1' ]:
store.remove(prefs) store.remove(prefs)
continue continue
@ -62,22 +75,60 @@ def update_clients():
store.commit() store.commit()
flash('Clients preferences updated.') flash('Clients preferences updated.')
return user_profile() return user_profile(uid)
@app.route('/user/changemail', methods = [ 'GET', 'POST' ]) @app.route('/user/<uid>/changeusername', methods = [ 'GET', 'POST' ])
def change_mail(): def change_username(uid):
if not UserManager.get(store, session.get('userid'))[1].admin:
return redirect(url_for('index'))
user = UserManager.get(store, uuid.UUID(uid))[1]
if request.method == 'POST':
username = request.form.get('user')
if username in ('', None):
flash('The username is required')
return render_template('change_username.html', user = user, admin = UserManager.get(store, session.get('userid'))[1].admin)
if request.form.get('admin') is None:
admin = False
else:
admin = True
changed = False
if user.name != username or user.admin != admin:
user.name = username
user.admin = admin
store.commit()
flash("User '%s' updated." % username)
return redirect(url_for('user_profile', uid = uid))
else:
flash("No changes for '%s'." % username)
return redirect(url_for('user_profile', uid = uid))
return render_template('change_username.html', user = user, admin = UserManager.get(store, session.get('userid'))[1].admin)
@app.route('/user/<uid>/changemail', methods = [ 'GET', 'POST' ])
def change_mail(uid):
if uid == 'me':
user = UserManager.get(store, session.get('userid'))[1] user = UserManager.get(store, session.get('userid'))[1]
else:
if not UserManager.get(store, session.get('userid'))[1].admin:
return redirect(url_for('index'))
user = UserManager.get(store, uuid.UUID(uid))[1]
if request.method == 'POST': if request.method == 'POST':
mail = request.form.get('mail') mail = request.form.get('mail')
# No validation, lol. # No validation, lol.
user.mail = mail user.mail = mail
store.commit() store.commit()
return redirect(url_for('user_profile')) return redirect(url_for('user_profile', uid = uid))
return render_template('change_mail.html', user = user, admin = UserManager.get(store, session.get('userid'))[1].admin) return render_template('change_mail.html', user = user, admin = UserManager.get(store, session.get('userid'))[1].admin)
@app.route('/user/changepass', methods = [ 'GET', 'POST' ]) @app.route('/user/<uid>/changepass', methods = [ 'GET', 'POST' ])
def change_password(): def change_password(uid):
if uid == 'me':
user = UserManager.get(store, session.get('userid'))[1].name
else:
if not UserManager.get(store, session.get('userid'))[1].admin:
return redirect(url_for('index'))
user = UserManager.get(store, uuid.UUID(uid))[1].name
if request.method == 'POST': if request.method == 'POST':
current, new, confirm = map(request.form.get, [ 'current', 'new', 'confirm' ]) current, new, confirm = map(request.form.get, [ 'current', 'new', 'confirm' ])
error = False error = False
@ -92,14 +143,17 @@ def change_password():
error = True error = True
if not error: if not error:
if uid == 'me':
status = UserManager.change_password(store, session.get('userid'), current, new) status = UserManager.change_password(store, session.get('userid'), current, new)
else:
status = UserManager.change_password(store, uuid.UUID(uid), current, new)
if status != UserManager.SUCCESS: if status != UserManager.SUCCESS:
flash(UserManager.error_str(status)) flash(UserManager.error_str(status))
else: else:
flash('Password changed') flash('Password changed')
return redirect(url_for('user_profile')) return redirect(url_for('user_profile', uid = uid))
return render_template('change_pass.html', user = UserManager.get(store, session.get('userid'))[1].name, admin = UserManager.get(store, session.get('userid'))[1].admin) return render_template('change_pass.html', user = user, admin = UserManager.get(store, session.get('userid'))[1].admin)
@app.route('/user/add', methods = [ 'GET', 'POST' ]) @app.route('/user/add', methods = [ 'GET', 'POST' ])
def add_user(): def add_user():
@ -131,8 +185,7 @@ def add_user():
else: else:
flash(UserManager.error_str(status)) flash(UserManager.error_str(status))
return render_template('adduser.html') return render_template('adduser.html', admin = UserManager.get(store, session.get('userid'))[1].admin)
@app.route('/user/del/<uid>') @app.route('/user/del/<uid>')
def del_user(uid): def del_user(uid):
@ -187,27 +240,37 @@ def do_user_import():
return redirect(url_for('user_index')) return redirect(url_for('user_index'))
@app.route('/user/lastfm/link') @app.route('/user/<uid>/lastfm/link')
def lastfm_reg(): def lastfm_reg(uid):
token = request.args.get('token') token = request.args.get('token')
if token in ('', None): if token in ('', None):
flash('Missing LastFM auth token') flash('Missing LastFM auth token')
return redirect(url_for('user_profile')) return redirect(url_for('user_profile', uid = uid))
if uid == 'me':
lfm = LastFm(UserManager.get(store, session.get('userid'))[1], app.logger) lfm = LastFm(UserManager.get(store, session.get('userid'))[1], app.logger)
else:
if not UserManager.get(store, session.get('userid'))[1].admin:
return redirect(url_for('index'))
lfm = LastFm(UserManager.get(store, uuid.UUID(uid))[1], app.logger)
status, error = lfm.link_account(token) status, error = lfm.link_account(token)
store.commit() store.commit()
flash(error if not status else 'Successfully linked LastFM account') flash(error if not status else 'Successfully linked LastFM account')
return redirect(url_for('user_profile')) return redirect(url_for('user_profile', uid = uid))
@app.route('/user/lastfm/unlink') @app.route('/user/<uid>/lastfm/unlink')
def lastfm_unreg(): def lastfm_unreg(uid):
if uid == 'me':
lfm = LastFm(UserManager.get(store, session.get('userid'))[1], app.logger) lfm = LastFm(UserManager.get(store, session.get('userid'))[1], app.logger)
else:
if not UserManager.get(store, session.get('userid'))[1].admin:
return redirect(url_for('index'))
lfm = LastFm(UserManager.get(store, uuid.UUID(uid))[1], app.logger)
lfm.unlink_account() lfm.unlink_account()
store.commit() store.commit()
flash('Unliked LastFM account') flash('Unliked LastFM account')
return redirect(url_for('user_profile')) return redirect(url_for('user_profile', uid = uid))
@app.route('/user/login', methods = [ 'GET', 'POST']) @app.route('/user/login', methods = [ 'GET', 'POST'])
def login(): def login():

View File

@ -18,8 +18,20 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
-#} -#}
{% extends "layout.html" %} {% extends "layout.html" %}
{% block navbar_users %}
{% if session.username != user.name %}
<li class="active"><a href="{{ url_for('user_index') }}">Users <span
class="sr-only">(current)</span></a></li>
{% else %}
{{ super() }}
{% endif %}
{% endblock %}
{% block navbar_profile %} {% block navbar_profile %}
<li class="active"><a href="{{ url_for('user_profile') }}">{{ session.username }} <span class="sr-only">(current)</span></a></li> {% if session.username == user.name %}
<li class="active"><a href="{{ url_for('user_profile', uid = 'me') }}">{{ session.username }} <span class="sr-only">(current)</span></a></li>
{% else %}
{{ super() }}
{% endif %}
{% endblock %} {% endblock %}
{% block body %} {% block body %}
<div class="page-header first-header"> <div class="page-header first-header">

View File

@ -18,8 +18,20 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
-#} -#}
{% extends "layout.html" %} {% extends "layout.html" %}
{% block navbar_users %}
{% if session.username != user %}
<li class="active"><a href="{{ url_for('user_index') }}">Users <span
class="sr-only">(current)</span></a></li>
{% else %}
{{ super() }}
{% endif %}
{% endblock %}
{% block navbar_profile %} {% block navbar_profile %}
<li class="active"><a href="{{ url_for('user_profile') }}">{{ session.username }} <span class="sr-only">(current)</span></a></li> {% if session.username == user %}
<li class="active"><a href="{{ url_for('user_profile', uid = 'me') }}">{{ session.username }} <span class="sr-only">(current)</span></a></li>
{% else %}
{{ super() }}
{% endif %}
{% endblock %} {% endblock %}
{% block body %} {% block body %}
<div class="page-header first-header"> <div class="page-header first-header">

View File

@ -0,0 +1,44 @@
{#-
This file is part of Supysonic.
Supysonic is a Python implementation of the Subsonic server API.
Copyright (C) 2013 Alban 'spl0k' Féron
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-#}
{% extends "layout.html" %}
{% block navbar_users %}
<li class="active"><a href="{{ url_for('user_index') }}">Users <span
class="sr-only">(current)</span></a></li>
{% endblock %}
{% block body %}
<div class="page-header first-header">
<h2>{{ user.name }}</h2>
</div>
<form method="post">
<div class="form-group">
<label class="sr-only" for="user">Username</label>
<div class="input-group">
<div class="input-group-addon"><span class="glyphicon glyphicon-user"></span></div>
<input type="text" class="form-control" id="user" name="user" value="{{ user.name }}" placeholder="Username" />
<span class="input-group-addon">
<label for="admin">Admin</label>
<input type="checkbox" id="admin" name="admin" {{ 'checked="checked"' if user.admin }} />
</span>
</div>
</div>
<input type="submit" class="btn btn-default" />
</form>
{% endblock %}

View File

@ -75,7 +75,7 @@
{% endblock %} {% endblock %}
{% endif %} {% endif %}
{% block navbar_profile %} {% block navbar_profile %}
<li><a href="{{ url_for('user_profile') }}">{{ session.username }}</a></li> <li><a href="{{ url_for('user_profile', uid = 'me')}}">{{ session.username }}</a></li>
{% endblock %} {% endblock %}
</ul> </ul>
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">

View File

@ -18,13 +18,26 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
-#} -#}
{% extends "layout.html" %} {% extends "layout.html" %}
{% block navbar_users %}
{% if session.username != user.name %}
<li class="active"><a href="{{ url_for('user_index') }}">Users <span
class="sr-only">(current)</span></a></li>
{% else %}
{{ super() }}
{% endif %}
{% endblock %}
{% block navbar_profile %} {% block navbar_profile %}
<li class="active"><a href="{{ url_for('user_profile') }}">{{ session.username }} <span class="sr-only">(current)</span></a></li> {% if session.username == user.name %}
<li class="active"><a href="{{ url_for('user_profile', uid = 'me') }}">{{ session.username }} <span class="sr-only">(current)</span></a></li>
{% else %}
{{ super() }}
{% endif %}
{% endblock %} {% endblock %}
{% block body %} {% block body %}
<div class="page-header first-header"> <div class="page-header first-header">
<h2>{{ user.name }}{% if user.admin %} <small><span class="glyphicon <h2>{{ user.name }}{% if user.admin %} <small><span class="glyphicon
glyphicon-certificate" data-toggle="tooltip" data-placement="right" title="You're an admin!"></span></small>{% endif %}</h2> glyphicon-certificate" data-toggle="tooltip" data-placement="right"
title="{% if session.username == user.name %}You're an admin!{% else %}The user is an admin!{% endif %}"></span></small>{% endif %}</h2>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
@ -35,7 +48,11 @@
<div class="input-group-addon">User eMail</div> <div class="input-group-addon">User eMail</div>
<input type="text" class="form-control" id="email" placeholder="{{ user.mail }}" readonly> <input type="text" class="form-control" id="email" placeholder="{{ user.mail }}" readonly>
<div class="input-group-btn"> <div class="input-group-btn">
<a href="{{ url_for('change_mail') }}" class="btn btn-default">Change eMail</a> {% if session.username == user.name %}
<a href="{{ url_for('change_mail', uid = 'me') }}" class="btn btn-default">Change eMail</a>
{% else %}
<a href="{{ url_for('change_mail', uid = user.id) }}" class="btn btn-default">Change eMail</a>
{% endif %}
</div> </div>
</div> </div>
</div> </div>
@ -51,12 +68,20 @@
{% if user.lastfm_session %} {% if user.lastfm_session %}
<input type="text" class="form-control" id="lastfm" placeholder="{% if user.lastfm_status %}Linked{% else %}Invalid session{% endif %}" readonly> <input type="text" class="form-control" id="lastfm" placeholder="{% if user.lastfm_status %}Linked{% else %}Invalid session{% endif %}" readonly>
<div class="input-group-btn"> <div class="input-group-btn">
<a href="{{ url_for('lastfm_unreg') }}" class="btn btn-default">Unlink</a> {% if session.username == user.name %}
<a href="{{ url_for('lastfm_unreg', uid = 'me') }}" class="btn btn-default">Unlink</a>
{% else %}
<a href="{{ url_for('lastfm_unreg', uid = user.id) }}" class="btn btn-default">Unlink</a>
{% endif %}
</div> </div>
{% else %} {% else %}
<input type="text" class="form-control" id="lastfm" placeholder="Unlinked" readonly> <input type="text" class="form-control" id="lastfm" placeholder="Unlinked" readonly>
<div class="input-group-btn"> <div class="input-group-btn">
<a href="http://www.last.fm/api/auth/?api_key={{ api_key }}&cb={{ request.url_root[:-(request.script_root|length+1)] + url_for('lastfm_reg') }}" class="btn btn-default">Link</a> {% if session.username == user.name %}
<a href="http://www.last.fm/api/auth/?api_key={{ api_key }}&cb={{ request.url_root[:-(request.script_root|length+1)] + url_for('lastfm_reg', uid = 'me') }}" class="btn btn-default">Link</a>
{% else %}
<a href="http://www.last.fm/api/auth/?api_key={{ api_key }}&cb={{ request.url_root[:-(request.script_root|length+1)] + url_for('lastfm_reg', uid = user.id) }}" class="btn btn-default">Link</a>
{% endif %}
</div> </div>
{% endif %} {% endif %}
{% else %} {% else %}
@ -67,7 +92,12 @@
</form> </form>
</div> </div>
</div> </div>
<a href="{{ url_for('change_password') }}" class="btn btn-default">Change password</a></li> {% if session.username == user.name %}
<a href="{{ url_for('change_password', uid = 'me') }}" class="btn btn-default">Change password</a></li>
{% else %}
<a href="{{ url_for('change_username', uid = user.id) }}" class="btn btn-default">Change username or admin status</a></li>
<a href="{{ url_for('change_password', uid = user.id) }}" class="btn btn-default">Change password</a></li>
{% endif %}
{% if clients.count() %} {% if clients.count() %}
<div class="page-header"> <div class="page-header">
<h2>Clients</h2> <h2>Clients</h2>

View File

@ -32,7 +32,10 @@
</thead> </thead>
<tbody> <tbody>
{% for user in users %} {% for user in users %}
<tr><td>{{ user.name }}</td><td>{{ user.mail }}</td><td>{{ user.admin }}</td><td>{{ user.last_play_date }}</td><td> <tr>
<td>{% if session.username == user.name %}{{ user.name }}{% else %}
<a href="{{ url_for('user_profile', uid = user.id) }}">{{ user.name }}</a>{% endif %}</td>
<td>{{ user.mail }}</td><td>{{ user.admin }}</td><td>{{ user.last_play_date }}</td><td>
<a href="{{ url_for('del_user', uid = user.id) }}" aria-label="Delete user"> <a href="{{ url_for('del_user', uid = user.id) }}" aria-label="Delete user">
<span class="glyphicon glyphicon-remove-circle" aria-hidden="true" data-toggle="tooltip" data-placement="top" title="Delete user"></span></a></td></tr> <span class="glyphicon glyphicon-remove-circle" aria-hidden="true" data-toggle="tooltip" data-placement="top" title="Delete user"></span></a></td></tr>
{% endfor %} {% endfor %}