mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2024-12-04 19:15:30 +00:00
Rework user image handling
Moved all the logic out of the template into a separate endpoint. This makes it easy to extend to also support images from different sources like LDAP/SAML/OIDC. Session-based caching is hard to do, so to allow time-based caching in the browser, the url needs to be unique for every user by using a query parameter. Replaced the default/fallback user image with a new one. It is based on the old one, but does not need css to be visible. And removed said css. Gravatar has now its own setting named `gravatar_enabled`, which is disabled by default.
This commit is contained in:
parent
b795f1eadf
commit
607caa1a2d
@ -100,8 +100,6 @@ def create_app(config=None):
|
||||
app.jinja_env.filters['display_record_name'] = utils.display_record_name
|
||||
app.jinja_env.filters['display_master_name'] = utils.display_master_name
|
||||
app.jinja_env.filters['display_second_to_time'] = utils.display_time
|
||||
app.jinja_env.filters[
|
||||
'email_to_gravatar_url'] = utils.email_to_gravatar_url
|
||||
app.jinja_env.filters[
|
||||
'display_setting_state'] = utils.display_setting_state
|
||||
app.jinja_env.filters['pretty_domain_name'] = utils.pretty_domain_name
|
||||
|
@ -2,14 +2,12 @@ import logging
|
||||
import re
|
||||
import json
|
||||
import requests
|
||||
import hashlib
|
||||
import ipaddress
|
||||
import idna
|
||||
|
||||
from collections.abc import Iterable
|
||||
from distutils.version import StrictVersion
|
||||
from urllib.parse import urlparse
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
def auth_from_url(url):
|
||||
@ -186,17 +184,6 @@ def pdns_api_extended_uri(version):
|
||||
return ""
|
||||
|
||||
|
||||
def email_to_gravatar_url(email="", size=100):
|
||||
"""
|
||||
AD doesn't necessarily have email
|
||||
"""
|
||||
if email is None:
|
||||
email = ""
|
||||
|
||||
hash_string = hashlib.md5(email.encode('utf-8')).hexdigest()
|
||||
return "https://s.gravatar.com/avatar/{0}?s={1}".format(hash_string, size)
|
||||
|
||||
|
||||
def display_setting_state(value):
|
||||
if value == 1:
|
||||
return "ON"
|
||||
|
@ -193,7 +193,8 @@ class Setting(db.Model):
|
||||
'otp_force': False,
|
||||
'max_history_records': 1000,
|
||||
'deny_domain_override': False,
|
||||
'account_name_extra_chars': False
|
||||
'account_name_extra_chars': False,
|
||||
'gravatar_enabled': False,
|
||||
}
|
||||
|
||||
def __init__(self, id=None, name=None, value=None):
|
||||
|
@ -1259,20 +1259,41 @@ def history_table(): # ajax call data
|
||||
@login_required
|
||||
@operator_role_required
|
||||
def setting_basic():
|
||||
if request.method == 'GET':
|
||||
settings = [
|
||||
'maintenance', 'fullscreen_layout', 'record_helper',
|
||||
'login_ldap_first', 'default_record_table_size',
|
||||
'default_domain_table_size', 'auto_ptr', 'record_quick_edit',
|
||||
'pretty_ipv6_ptr', 'dnssec_admins_only',
|
||||
'allow_user_create_domain', 'allow_user_remove_domain', 'allow_user_view_history', 'bg_domain_updates', 'site_name',
|
||||
'session_timeout', 'warn_session_timeout', 'ttl_options',
|
||||
'pdns_api_timeout', 'verify_ssl_connections', 'verify_user_email',
|
||||
'delete_sso_accounts', 'otp_field_enabled', 'custom_css', 'enable_api_rr_history', 'max_history_records', 'otp_force',
|
||||
'deny_domain_override', 'enforce_api_ttl', 'account_name_extra_chars'
|
||||
]
|
||||
settings = [
|
||||
'account_name_extra_chars',
|
||||
'allow_user_create_domain',
|
||||
'allow_user_remove_domain',
|
||||
'allow_user_view_history',
|
||||
'auto_ptr',
|
||||
'bg_domain_updates',
|
||||
'custom_css',
|
||||
'default_domain_table_size',
|
||||
'default_record_table_size',
|
||||
'delete_sso_accounts',
|
||||
'deny_domain_override',
|
||||
'dnssec_admins_only',
|
||||
'enable_api_rr_history',
|
||||
'enforce_api_ttl',
|
||||
'fullscreen_layout',
|
||||
'gravatar_enabled',
|
||||
'login_ldap_first',
|
||||
'maintenance',
|
||||
'max_history_records',
|
||||
'otp_field_enabled',
|
||||
'otp_force',
|
||||
'pdns_api_timeout',
|
||||
'pretty_ipv6_ptr',
|
||||
'record_helper',
|
||||
'record_quick_edit',
|
||||
'session_timeout',
|
||||
'site_name',
|
||||
'ttl_options',
|
||||
'verify_ssl_connections',
|
||||
'verify_user_email',
|
||||
'warn_session_timeout',
|
||||
]
|
||||
|
||||
return render_template('admin_setting_basic.html', settings=settings)
|
||||
return render_template('admin_setting_basic.html', settings=settings)
|
||||
|
||||
|
||||
@admin_bp.route('/setting/basic/<path:setting>/edit', methods=['POST'])
|
||||
|
@ -1,5 +1,8 @@
|
||||
import datetime
|
||||
from flask import Blueprint, request, render_template, make_response, jsonify, redirect, url_for, g, session, current_app
|
||||
import hashlib
|
||||
|
||||
from flask import Blueprint, request, render_template, make_response, jsonify, redirect, url_for, g, session, \
|
||||
current_app, after_this_request, abort
|
||||
from flask_login import current_user, login_required, login_manager
|
||||
|
||||
from ..models.user import User, Anonymous
|
||||
@ -96,4 +99,34 @@ def qrcode():
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||||
'Pragma': 'no-cache',
|
||||
'Expires': '0'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@user_bp.route('/image', methods=['GET'])
|
||||
@login_required
|
||||
def image():
|
||||
"""Returns the user profile image or avatar."""
|
||||
|
||||
@after_this_request
|
||||
def add_cache_headers(response_):
|
||||
"""When the response is ok, add cache headers."""
|
||||
if 200 <= response_.status_code <= 399:
|
||||
response_.cache_control.private = True
|
||||
response_.cache_control.max_age = int(datetime.timedelta(days=1).total_seconds())
|
||||
return response_
|
||||
|
||||
# To prevent "cache poisoning", the username query parameter is required
|
||||
if request.args.get('username', None) != current_user.username:
|
||||
abort(400)
|
||||
|
||||
setting = Setting()
|
||||
|
||||
email = current_user.email
|
||||
if email and setting.get('gravatar_enabled'):
|
||||
hash_ = hashlib.md5(email.encode('utf-8')).hexdigest()
|
||||
url = f'https://s.gravatar.com/avatar/{hash_}?s=100'
|
||||
current_app.logger.debug('Redirect user image request to gravatar')
|
||||
return redirect(url, 307)
|
||||
|
||||
# Fallback to the local default image
|
||||
return current_app.send_static_file('img/user_image.png')
|
||||
|
@ -42,15 +42,6 @@ table td {
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.navbar-nav>.user-menu>.dropdown-menu>li.user-header>img.img-circle.offline {
|
||||
filter: brightness(0);
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
.navbar-nav>.user-menu .user-image.offline {
|
||||
filter: brightness(0);
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
BIN
powerdnsadmin/static/img/user_image.png
Normal file
BIN
powerdnsadmin/static/img/user_image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
@ -23,11 +23,7 @@
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body class="hold-transition skin-blue sidebar-mini {% if not SETTING.get('fullscreen_layout') %}layout-boxed{% endif %}">
|
||||
{% if OFFLINE_MODE %}
|
||||
{% set gravatar_url = url_for('static', filename='img/gravatar.png') %}
|
||||
{% elif current_user.email is defined %}
|
||||
{% set gravatar_url = current_user.email|email_to_gravatar_url(size=80) %}
|
||||
{% endif %}
|
||||
{% set user_image_url = url_for('user.image', username=current_user.username) %}
|
||||
<div class="wrapper">
|
||||
{% block pageheader %}
|
||||
<header class="main-header">
|
||||
@ -51,14 +47,14 @@
|
||||
<!-- User Account: style can be found in dropdown.less -->
|
||||
<li class="dropdown user user-menu">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<img src="{{ gravatar_url }}" class="user-image {{ 'offline' if OFFLINE_MODE }}" alt="User Image"/>
|
||||
<img src="{{ user_image_url }}" class="user-image" alt="User Image"/>
|
||||
<span class="hidden-xs">
|
||||
{{ current_user.firstname }}
|
||||
</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="user-header">
|
||||
<img src="{{ gravatar_url }}" class="img-circle {{ 'offline' if OFFLINE_MODE }}" alt="User Image"/>
|
||||
<img src="{{ user_image_url }}" class="img-circle" alt="User Image"/>
|
||||
<p>
|
||||
{{ current_user.firstname }} {{ current_user.lastname }}
|
||||
<small>{{ current_user.role.name }}</small>
|
||||
@ -89,7 +85,7 @@
|
||||
{% if current_user.id is defined %}
|
||||
<div class="user-panel">
|
||||
<div class="pull-left image">
|
||||
<img src="{{ gravatar_url }}" class="img-circle" alt="User Image"/>
|
||||
<img src="{{ user_image_url }}" class="img-circle" alt="User Image"/>
|
||||
</div>
|
||||
<div class="pull-left info">
|
||||
<p>{{ current_user.firstname }} {{ current_user.lastname }}</p>
|
||||
|
Loading…
Reference in New Issue
Block a user