mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2024-11-14 01:20:27 +00:00
Merge pull request #610 from ngoduykhanh/warn_session_timeout
Warn session timeout
This commit is contained in:
commit
88991cdde9
@ -3,10 +3,11 @@
|
|||||||
"admin-lte": "2.4.9",
|
"admin-lte": "2.4.9",
|
||||||
"bootstrap": "^3.4.1",
|
"bootstrap": "^3.4.1",
|
||||||
"bootstrap-validator": "^0.11.9",
|
"bootstrap-validator": "^0.11.9",
|
||||||
|
"datatables.net-plugins": "^1.10.19",
|
||||||
"icheck": "^1.0.2",
|
"icheck": "^1.0.2",
|
||||||
"jquery-slimscroll": "^1.3.8",
|
"jquery-slimscroll": "^1.3.8",
|
||||||
"jquery-ui-dist": "^1.12.1",
|
"jquery-ui-dist": "^1.12.1",
|
||||||
"multiselect": "^0.9.12",
|
"jtimeout": "^3.1.0",
|
||||||
"datatables.net-plugins": "^1.10.19"
|
"multiselect": "^0.9.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from flask_assets import Bundle, Environment, Filter
|
from flask_assets import Bundle, Environment, Filter
|
||||||
|
|
||||||
|
|
||||||
class ConcatFilter(Filter):
|
class ConcatFilter(Filter):
|
||||||
"""
|
"""
|
||||||
Filter that merges files, placing a semicolon between them.
|
Filter that merges files, placing a semicolon between them.
|
||||||
@ -10,28 +11,23 @@ class ConcatFilter(Filter):
|
|||||||
def concat(self, out, hunks, **kw):
|
def concat(self, out, hunks, **kw):
|
||||||
out.write(';'.join([h.data() for h, info in hunks]))
|
out.write(';'.join([h.data() for h, info in hunks]))
|
||||||
|
|
||||||
css_login = Bundle(
|
|
||||||
'node_modules/bootstrap/dist/css/bootstrap.css',
|
css_login = Bundle('node_modules/bootstrap/dist/css/bootstrap.css',
|
||||||
'node_modules/font-awesome/css/font-awesome.css',
|
'node_modules/font-awesome/css/font-awesome.css',
|
||||||
'node_modules/ionicons/dist/css/ionicons.css',
|
'node_modules/ionicons/dist/css/ionicons.css',
|
||||||
'node_modules/icheck/skins/square/blue.css',
|
'node_modules/icheck/skins/square/blue.css',
|
||||||
'node_modules/admin-lte/dist/css/AdminLTE.css',
|
'node_modules/admin-lte/dist/css/AdminLTE.css',
|
||||||
filters=('cssmin','cssrewrite'),
|
filters=('cssmin', 'cssrewrite'),
|
||||||
output='generated/login.css'
|
output='generated/login.css')
|
||||||
)
|
|
||||||
|
|
||||||
js_login = Bundle(
|
js_login = Bundle('node_modules/jquery/dist/jquery.js',
|
||||||
'node_modules/jquery/dist/jquery.js',
|
|
||||||
'node_modules/bootstrap/dist/js/bootstrap.js',
|
'node_modules/bootstrap/dist/js/bootstrap.js',
|
||||||
'node_modules/icheck/icheck.js',
|
'node_modules/icheck/icheck.js',
|
||||||
filters=(ConcatFilter, 'jsmin'),
|
filters=(ConcatFilter, 'jsmin'),
|
||||||
output='generated/login.js'
|
output='generated/login.js')
|
||||||
)
|
|
||||||
|
|
||||||
js_validation = Bundle(
|
js_validation = Bundle('node_modules/bootstrap-validator/dist/validator.js',
|
||||||
'node_modules/bootstrap-validator/dist/validator.js',
|
output='generated/validation.js')
|
||||||
output='generated/validation.js'
|
|
||||||
)
|
|
||||||
|
|
||||||
css_main = Bundle(
|
css_main = Bundle(
|
||||||
'node_modules/bootstrap/dist/css/bootstrap.css',
|
'node_modules/bootstrap/dist/css/bootstrap.css',
|
||||||
@ -43,12 +39,10 @@ css_main = Bundle(
|
|||||||
'node_modules/admin-lte/dist/css/AdminLTE.css',
|
'node_modules/admin-lte/dist/css/AdminLTE.css',
|
||||||
'node_modules/admin-lte/dist/css/skins/_all-skins.css',
|
'node_modules/admin-lte/dist/css/skins/_all-skins.css',
|
||||||
'custom/css/custom.css',
|
'custom/css/custom.css',
|
||||||
filters=('cssmin','cssrewrite'),
|
filters=('cssmin', 'cssrewrite'),
|
||||||
output='generated/main.css'
|
output='generated/main.css')
|
||||||
)
|
|
||||||
|
|
||||||
js_main = Bundle(
|
js_main = Bundle('node_modules/jquery/dist/jquery.js',
|
||||||
'node_modules/jquery/dist/jquery.js',
|
|
||||||
'node_modules/jquery-ui-dist/jquery-ui.js',
|
'node_modules/jquery-ui-dist/jquery-ui.js',
|
||||||
'node_modules/bootstrap/dist/js/bootstrap.js',
|
'node_modules/bootstrap/dist/js/bootstrap.js',
|
||||||
'node_modules/datatables.net/js/jquery.dataTables.js',
|
'node_modules/datatables.net/js/jquery.dataTables.js',
|
||||||
@ -61,10 +55,10 @@ js_main = Bundle(
|
|||||||
'node_modules/admin-lte/dist/js/adminlte.js',
|
'node_modules/admin-lte/dist/js/adminlte.js',
|
||||||
'node_modules/multiselect/js/jquery.multi-select.js',
|
'node_modules/multiselect/js/jquery.multi-select.js',
|
||||||
'node_modules/datatables.net-plugins/sorting/natural.js',
|
'node_modules/datatables.net-plugins/sorting/natural.js',
|
||||||
|
'node_modules/jtimeout/src/jTimeout.js',
|
||||||
'custom/js/custom.js',
|
'custom/js/custom.js',
|
||||||
filters=(ConcatFilter, 'jsmin'),
|
filters=(ConcatFilter, 'jsmin'),
|
||||||
output='generated/main.js'
|
output='generated/main.js')
|
||||||
)
|
|
||||||
|
|
||||||
assets = Environment()
|
assets = Environment()
|
||||||
assets.register('js_login', js_login)
|
assets.register('js_login', js_login)
|
||||||
|
@ -26,6 +26,7 @@ class Setting(db.Model):
|
|||||||
'bg_domain_updates': False,
|
'bg_domain_updates': False,
|
||||||
'site_name': 'PowerDNS-Admin',
|
'site_name': 'PowerDNS-Admin',
|
||||||
'session_timeout': 10,
|
'session_timeout': 10,
|
||||||
|
'warn_session_timeout': True,
|
||||||
'pdns_api_url': '',
|
'pdns_api_url': '',
|
||||||
'pdns_api_key': '',
|
'pdns_api_key': '',
|
||||||
'pdns_api_timeout': 30,
|
'pdns_api_timeout': 30,
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import json
|
import json
|
||||||
|
import datetime
|
||||||
import traceback
|
import traceback
|
||||||
from ast import literal_eval
|
from ast import literal_eval
|
||||||
from flask import Blueprint, render_template, make_response, url_for, current_app, request, redirect, jsonify, abort, flash
|
from flask import Blueprint, render_template, make_response, url_for, current_app, request, redirect, jsonify, abort, flash, session
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
|
|
||||||
from ..decorators import operator_role_required, admin_role_required
|
from ..decorators import operator_role_required, admin_role_required
|
||||||
@ -23,6 +24,16 @@ admin_bp = Blueprint('admin',
|
|||||||
url_prefix='/admin')
|
url_prefix='/admin')
|
||||||
|
|
||||||
|
|
||||||
|
@admin_bp.before_request
|
||||||
|
def before_request():
|
||||||
|
# Manage session timeout
|
||||||
|
session.permanent = True
|
||||||
|
current_app.permanent_session_lifetime = datetime.timedelta(
|
||||||
|
minutes=int(Setting().get('session_timeout')))
|
||||||
|
session.modified = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@admin_bp.route('/pdns', methods=['GET'])
|
@admin_bp.route('/pdns', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@operator_role_required
|
@operator_role_required
|
||||||
@ -489,7 +500,8 @@ def setting_basic():
|
|||||||
'default_domain_table_size', 'auto_ptr', 'record_quick_edit',
|
'default_domain_table_size', 'auto_ptr', 'record_quick_edit',
|
||||||
'pretty_ipv6_ptr', 'dnssec_admins_only',
|
'pretty_ipv6_ptr', 'dnssec_admins_only',
|
||||||
'allow_user_create_domain', 'bg_domain_updates', 'site_name',
|
'allow_user_create_domain', 'bg_domain_updates', 'site_name',
|
||||||
'session_timeout', 'ttl_options', 'pdns_api_timeout'
|
'session_timeout', 'warn_session_timeout', 'ttl_options',
|
||||||
|
'pdns_api_timeout'
|
||||||
]
|
]
|
||||||
|
|
||||||
return render_template('admin_setting_basic.html', settings=settings)
|
return render_template('admin_setting_basic.html', settings=settings)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
from flask import Blueprint, g, request, abort, current_app
|
from flask import Blueprint, g, request, abort, current_app, make_response, jsonify
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
from ..models.base import db
|
from ..models.base import db
|
||||||
@ -88,7 +88,16 @@ def handle_request_is_not_json(err):
|
|||||||
@api_bp.before_request
|
@api_bp.before_request
|
||||||
@is_json
|
@is_json
|
||||||
def before_request():
|
def before_request():
|
||||||
pass
|
# Check site is in maintenance mode
|
||||||
|
maintenance = Setting().get('maintenance')
|
||||||
|
if maintenance and current_user.is_authenticated and current_user.role.name not in [
|
||||||
|
'Administrator', 'Operator'
|
||||||
|
]:
|
||||||
|
return make_response(
|
||||||
|
jsonify({
|
||||||
|
"status": False,
|
||||||
|
"msg": "Site is in maintenance mode"
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
@api_bp.route('/pdnsadmin/zones', methods=['POST'])
|
@api_bp.route('/pdnsadmin/zones', methods=['POST'])
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
from flask import Blueprint, render_template, url_for, current_app, request, jsonify, redirect
|
import datetime
|
||||||
from flask_login import login_required, current_user
|
from flask import Blueprint, render_template, url_for, current_app, request, jsonify, redirect, g, session
|
||||||
|
from flask_login import login_required, current_user, login_manager
|
||||||
from sqlalchemy import not_
|
from sqlalchemy import not_
|
||||||
|
|
||||||
from ..lib.utils import customBoxes
|
from ..lib.utils import customBoxes
|
||||||
from ..models.user import User
|
from ..models.user import User, Anonymous
|
||||||
from ..models.account import Account
|
from ..models.account import Account
|
||||||
from ..models.account_user import AccountUser
|
from ..models.account_user import AccountUser
|
||||||
from ..models.domain import Domain
|
from ..models.domain import Domain
|
||||||
@ -19,6 +20,26 @@ dashboard_bp = Blueprint('dashboard',
|
|||||||
url_prefix='/dashboard')
|
url_prefix='/dashboard')
|
||||||
|
|
||||||
|
|
||||||
|
@dashboard_bp.before_request
|
||||||
|
def before_request():
|
||||||
|
# Check if user is anonymous
|
||||||
|
g.user = current_user
|
||||||
|
login_manager.anonymous_user = Anonymous
|
||||||
|
|
||||||
|
# Check site is in maintenance mode
|
||||||
|
maintenance = Setting().get('maintenance')
|
||||||
|
if maintenance and current_user.is_authenticated and current_user.role.name not in [
|
||||||
|
'Administrator', 'Operator'
|
||||||
|
]:
|
||||||
|
return render_template('maintenance.html')
|
||||||
|
|
||||||
|
# Manage session timeout
|
||||||
|
session.permanent = True
|
||||||
|
current_app.permanent_session_lifetime = datetime.timedelta(
|
||||||
|
minutes=int(Setting().get('session_timeout')))
|
||||||
|
session.modified = True
|
||||||
|
|
||||||
|
|
||||||
@dashboard_bp.route('/domains-custom/<path:boxId>', methods=['GET'])
|
@dashboard_bp.route('/domains-custom/<path:boxId>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def domains_custom(boxId):
|
def domains_custom(boxId):
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
|
import datetime
|
||||||
import traceback
|
import traceback
|
||||||
import dns.name
|
import dns.name
|
||||||
import dns.reversename
|
import dns.reversename
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion
|
||||||
from flask import Blueprint, render_template, make_response, url_for, current_app, request, redirect, abort, jsonify
|
from flask import Blueprint, render_template, make_response, url_for, current_app, request, redirect, abort, jsonify, g, session
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user, login_manager
|
||||||
|
|
||||||
from ..lib.utils import pretty_json
|
from ..lib.utils import pretty_json
|
||||||
from ..decorators import can_create_domain, operator_role_required, can_access_domain, can_configure_dnssec
|
from ..decorators import can_create_domain, operator_role_required, can_access_domain, can_configure_dnssec
|
||||||
from ..models.user import User
|
from ..models.user import User, Anonymous
|
||||||
from ..models.account import Account
|
from ..models.account import Account
|
||||||
from ..models.setting import Setting
|
from ..models.setting import Setting
|
||||||
from ..models.history import History
|
from ..models.history import History
|
||||||
@ -26,6 +27,26 @@ domain_bp = Blueprint('domain',
|
|||||||
url_prefix='/domain')
|
url_prefix='/domain')
|
||||||
|
|
||||||
|
|
||||||
|
@domain_bp.before_request
|
||||||
|
def before_request():
|
||||||
|
# Check if user is anonymous
|
||||||
|
g.user = current_user
|
||||||
|
login_manager.anonymous_user = Anonymous
|
||||||
|
|
||||||
|
# Check site is in maintenance mode
|
||||||
|
maintenance = Setting().get('maintenance')
|
||||||
|
if maintenance and current_user.is_authenticated and current_user.role.name not in [
|
||||||
|
'Administrator', 'Operator'
|
||||||
|
]:
|
||||||
|
return render_template('maintenance.html')
|
||||||
|
|
||||||
|
# Manage session timeout
|
||||||
|
session.permanent = True
|
||||||
|
current_app.permanent_session_lifetime = datetime.timedelta(
|
||||||
|
minutes=int(Setting().get('session_timeout')))
|
||||||
|
session.modified = True
|
||||||
|
|
||||||
|
|
||||||
@domain_bp.route('/<path:domain_name>', methods=['GET'])
|
@domain_bp.route('/<path:domain_name>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@can_access_domain
|
@can_access_domain
|
||||||
|
@ -82,6 +82,12 @@ def index():
|
|||||||
return redirect(url_for('dashboard.dashboard'))
|
return redirect(url_for('dashboard.dashboard'))
|
||||||
|
|
||||||
|
|
||||||
|
@index_bp.route('/ping', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def ping():
|
||||||
|
return make_response('ok')
|
||||||
|
|
||||||
|
|
||||||
@index_bp.route('/google/login')
|
@index_bp.route('/google/login')
|
||||||
def google_login():
|
def google_login():
|
||||||
if not Setting().get('google_oauth_enabled') or google is None:
|
if not Setting().get('google_oauth_enabled') or google is None:
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
|
import datetime
|
||||||
import qrcode as qrc
|
import qrcode as qrc
|
||||||
import qrcode.image.svg as qrc_svg
|
import qrcode.image.svg as qrc_svg
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from flask import Blueprint, request, render_template, make_response, jsonify, redirect, url_for, session
|
from flask import Blueprint, request, render_template, make_response, jsonify, redirect, url_for, g, session, current_app
|
||||||
from flask_login import current_user, login_required
|
from flask_login import current_user, login_required, login_manager
|
||||||
|
|
||||||
from ..models.user import User
|
from ..models.user import User, Anonymous
|
||||||
|
from ..models.setting import Setting
|
||||||
|
|
||||||
user_bp = Blueprint('user',
|
user_bp = Blueprint('user',
|
||||||
__name__,
|
__name__,
|
||||||
@ -12,6 +14,26 @@ user_bp = Blueprint('user',
|
|||||||
url_prefix='/user')
|
url_prefix='/user')
|
||||||
|
|
||||||
|
|
||||||
|
@user_bp.before_request
|
||||||
|
def before_request():
|
||||||
|
# Check if user is anonymous
|
||||||
|
g.user = current_user
|
||||||
|
login_manager.anonymous_user = Anonymous
|
||||||
|
|
||||||
|
# Check site is in maintenance mode
|
||||||
|
maintenance = Setting().get('maintenance')
|
||||||
|
if maintenance and current_user.is_authenticated and current_user.role.name not in [
|
||||||
|
'Administrator', 'Operator'
|
||||||
|
]:
|
||||||
|
return render_template('maintenance.html')
|
||||||
|
|
||||||
|
# Manage session timeout
|
||||||
|
session.permanent = True
|
||||||
|
current_app.permanent_session_lifetime = datetime.timedelta(
|
||||||
|
minutes=int(Setting().get('session_timeout')))
|
||||||
|
session.modified = True
|
||||||
|
|
||||||
|
|
||||||
@user_bp.route('/profile', methods=['GET', 'POST'])
|
@user_bp.route('/profile', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def profile():
|
def profile():
|
||||||
|
@ -268,3 +268,20 @@ json_library = {
|
|||||||
.replace(jsonLine, json_library.replacer);
|
.replace(jsonLine, json_library.replacer);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// set count down in second on an element
|
||||||
|
function timer(elToUpdate, maxTime) {
|
||||||
|
elToUpdate.text(maxTime + "s");
|
||||||
|
|
||||||
|
var interval = setInterval(function () {
|
||||||
|
if (maxTime > 0) {
|
||||||
|
maxTime--;
|
||||||
|
elToUpdate.text(maxTime + "s");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
clearInterval(interval);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return interval;
|
||||||
|
}
|
@ -174,6 +174,99 @@
|
|||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
{% assets "js_main" -%}
|
{% assets "js_main" -%}
|
||||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||||
|
{% if SETTING.get('warn_session_timeout') %}
|
||||||
|
<script>
|
||||||
|
// close the session warning popup when receive
|
||||||
|
// a boradcast message
|
||||||
|
var bc = new BroadcastChannel('powerdnsadmin');
|
||||||
|
bc.addEventListener('message', function (e) {
|
||||||
|
if (e.data == 'close_session_timeout_modal'){
|
||||||
|
$("#modal_session_warning").modal('hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stay Signed In button click event
|
||||||
|
$(document.body).on("click", ".button_stay_signed_in", function (e) {
|
||||||
|
$.get({
|
||||||
|
url: $.jTimeout().options.extendUrl,
|
||||||
|
cache: false,
|
||||||
|
success: function(){
|
||||||
|
$.jTimeout().resetExpiration();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$.jTimeout().options.onClickExtend();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sign Out button click event
|
||||||
|
$(document.body).on("click", ".button_sign_out", function (e) {
|
||||||
|
window.location.replace("{{ url_for('index.logout') }}");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Things happen when session warning popup shown
|
||||||
|
$(document).on('show.bs.modal','#modal_session_warning', function () {
|
||||||
|
var secondsLeft = jTimeout.getSecondsTillExpiration();
|
||||||
|
var t = timer($('#modal-time'), secondsLeft);
|
||||||
|
|
||||||
|
$(this).on('hidden.bs.modal', function () {
|
||||||
|
clearInterval(t);
|
||||||
|
$('#modal-time').text("");
|
||||||
|
$(this).off('hidden.bs.modal');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// jTimeout definition
|
||||||
|
$(function(){
|
||||||
|
$.jTimeout({
|
||||||
|
flashTitle: true,
|
||||||
|
flashTitleSpeed: 500,
|
||||||
|
flashingTitleText: '**WARNING**',
|
||||||
|
originalTitle: document.title,
|
||||||
|
timeoutAfter: {{ SETTING.get('session_timeout')|int * 60 }},
|
||||||
|
secondsPrior: 60,
|
||||||
|
heartbeat: 1,
|
||||||
|
extendOnMouseMove: true,
|
||||||
|
mouseDebounce: 30,
|
||||||
|
extendUrl: '{{ url_for("index.ping") }}',
|
||||||
|
logoutUrl: '{{ url_for("index.logout") }}',
|
||||||
|
loginUrl: '{{ url_for("index.login") }}',
|
||||||
|
|
||||||
|
onClickExtend: function(){
|
||||||
|
// broadcast a message to tell other tabes
|
||||||
|
// close the session warning popup
|
||||||
|
var bc = new BroadcastChannel('powerdnsadmin');
|
||||||
|
bc.postMessage('close_session_timeout_modal');
|
||||||
|
},
|
||||||
|
|
||||||
|
onMouseMove: function(){
|
||||||
|
// if the mouse is moving while popup is present, we
|
||||||
|
// don't extend the session.
|
||||||
|
if (!$('#modal_session_warning').hasClass('in')) {
|
||||||
|
$.get({
|
||||||
|
url: $.jTimeout().options.extendUrl,
|
||||||
|
cache: false,
|
||||||
|
success: function () {
|
||||||
|
$.jTimeout().resetExpiration();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onTimeout: function(jTimeout){
|
||||||
|
window.location.replace("{{ url_for('index.logout') }}");
|
||||||
|
},
|
||||||
|
|
||||||
|
onPriorCallback: function(jTimeout){
|
||||||
|
$("#modal_session_warning").modal('show');;
|
||||||
|
},
|
||||||
|
|
||||||
|
onSessionExtended:function(jTimeout){
|
||||||
|
$("#modal_session_warning").modal('hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
{%- endassets %}
|
{%- endassets %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block extrascripts %}
|
{% block extrascripts %}
|
||||||
@ -225,6 +318,30 @@
|
|||||||
<!-- /.modal-dialog -->
|
<!-- /.modal-dialog -->
|
||||||
</div>
|
</div>
|
||||||
<!-- /.modal -->
|
<!-- /.modal -->
|
||||||
|
<!-- /.session-warning-modal -->
|
||||||
|
<div class="modal fade modal-warning" data-backdrop="static" id="modal_session_warning">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title">Session timeout warning</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>Your session is about to expire. You will be automatically signed out in</p>
|
||||||
|
<h3><span id="modal-time"></span></h3>
|
||||||
|
<p>To coninue your ssession, select <strong>Stay Signed In</strong></p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-flat btn-danger pull-left button_stay_signed_in"
|
||||||
|
data-dismiss="modal">Stay Signed In</button>
|
||||||
|
<button type="button" class="btn btn-flat btn-default pull-right button_sign_out"
|
||||||
|
data-dismiss="modal">Sign Out</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.session-warning-modal-content -->
|
||||||
|
</div>
|
||||||
|
<!-- /.session-warning-modal-dialog -->
|
||||||
|
</div>
|
||||||
|
<!-- /.session-warning-modal -->
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block modals %}
|
{% block modals %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -51,6 +51,9 @@ class TestUnitApiZoneAdminApiKey(object):
|
|||||||
self.mock_hist_patcher = patch(
|
self.mock_hist_patcher = patch(
|
||||||
'powerdnsadmin.routes.api.History',
|
'powerdnsadmin.routes.api.History',
|
||||||
spec=powerdnsadmin.models.history.History)
|
spec=powerdnsadmin.models.history.History)
|
||||||
|
self.mock_setting_patcher = patch(
|
||||||
|
'powerdnsadmin.routes.api.Setting',
|
||||||
|
spec=powerdnsadmin.models.setting.Setting)
|
||||||
|
|
||||||
data = admin_apikey_data()
|
data = admin_apikey_data()
|
||||||
api_key = ApiKey(desc=data['description'],
|
api_key = ApiKey(desc=data['description'],
|
||||||
@ -71,6 +74,7 @@ class TestUnitApiZoneAdminApiKey(object):
|
|||||||
)
|
)
|
||||||
self.mock_apikey = self.mock_apikey_patcher.start()
|
self.mock_apikey = self.mock_apikey_patcher.start()
|
||||||
self.mock_hist = self.mock_hist_patcher.start()
|
self.mock_hist = self.mock_hist_patcher.start()
|
||||||
|
self.mock_setting = self.mock_setting_patcher.start()
|
||||||
|
|
||||||
self.mock_google_setting.return_value.get.side_effect = load_data
|
self.mock_google_setting.return_value.get.side_effect = load_data
|
||||||
self.mock_github_setting.return_value.get.side_effect = load_data
|
self.mock_github_setting.return_value.get.side_effect = load_data
|
||||||
|
@ -701,6 +701,13 @@ jsonparse@^1.2.0:
|
|||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
|
resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
|
||||||
|
|
||||||
|
jtimeout@^3.1.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/jtimeout/-/jtimeout-3.1.0.tgz#4cd65b28eff8b9f8c61d08889a9ac3abdf5d9893"
|
||||||
|
integrity sha512-xA2TlImMGj4c0yAiM9BUq+8aAFVYVYUX2tkcC8u8das9qoZSs13SxhVcfWqI4cHOsv3huj2D0VRNHeVCLO3mVQ==
|
||||||
|
dependencies:
|
||||||
|
jquery ">=1.7.1 <4.0.0"
|
||||||
|
|
||||||
jvectormap@^1.2.2:
|
jvectormap@^1.2.2:
|
||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/jvectormap/-/jvectormap-1.2.2.tgz#2e4408b24a60473ff106c1e7243e375ae5ca85da"
|
resolved "https://registry.yarnpkg.com/jvectormap/-/jvectormap-1.2.2.tgz#2e4408b24a60473ff106c1e7243e375ae5ca85da"
|
||||||
|
Loading…
Reference in New Issue
Block a user