mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
User management.
This commit is contained in:
committed by
Dave Page
parent
4398d1d869
commit
e3ab4501d5
@@ -150,7 +150,7 @@ MAX_SESSION_IDLE_TIME = 60
|
|||||||
|
|
||||||
# The schema version number for the configuration database
|
# The schema version number for the configuration database
|
||||||
# DO NOT CHANGE UNLESS YOU ARE A PGADMIN DEVELOPER!!
|
# DO NOT CHANGE UNLESS YOU ARE A PGADMIN DEVELOPER!!
|
||||||
SETTINGS_SCHEMA_VERSION = 10
|
SETTINGS_SCHEMA_VERSION = 11
|
||||||
|
|
||||||
# The default path to the SQLite database used to store user accounts and
|
# The default path to the SQLite database used to store user accounts and
|
||||||
# settings. This default places the file in the same directory as this
|
# settings. This default places the file in the same directory as this
|
||||||
|
|||||||
@@ -475,6 +475,7 @@ def index():
|
|||||||
return render_template(
|
return render_template(
|
||||||
MODULE_NAME + "/index.html",
|
MODULE_NAME + "/index.html",
|
||||||
username=current_user.email,
|
username=current_user.email,
|
||||||
|
is_admin=current_user.has_role("Administrator"),
|
||||||
_=gettext
|
_=gettext
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ try {
|
|||||||
<ul class="dropdown-menu navbar-inverse">
|
<ul class="dropdown-menu navbar-inverse">
|
||||||
<li><a href="{{ url_for('security.change_password') }}">{{ _('Change Password') }}</a></li>
|
<li><a href="{{ url_for('security.change_password') }}">{{ _('Change Password') }}</a></li>
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
|
{% if is_admin %}
|
||||||
|
<li><a onclick="pgAdmin.Browser.UserManagement.show_users()">{{ _('Users') }}</a></li>
|
||||||
|
<li class="divider"></li>
|
||||||
|
{% endif %}
|
||||||
<li><a href="{{ url_for('security.logout') }}">{{ _('Logout') }}</a></li>
|
<li><a href="{{ url_for('security.logout') }}">{{ _('Logout') }}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1103,7 +1103,7 @@ span.button-label {
|
|||||||
}
|
}
|
||||||
button.pg-alertify-button {
|
button.pg-alertify-button {
|
||||||
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
|
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
|
||||||
font-size: initial;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
.fa.pg-alertify-button:before {
|
.fa.pg-alertify-button:before {
|
||||||
font: normal normal normal 18px/1 FontAwesome;
|
font: normal normal normal 18px/1 FontAwesome;
|
||||||
@@ -1233,6 +1233,7 @@ form[name="change_password_form"] .help-block {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Override Backgrid's default z-index */
|
/* Override Backgrid's default z-index */
|
||||||
.dashboard-tab-container .backgrid-filter .search {
|
.dashboard-tab-container .backgrid-filter .search {
|
||||||
z-index: 10 !important;
|
z-index: 10 !important;
|
||||||
@@ -1264,3 +1265,64 @@ form[name="change_password_form"] .help-block {
|
|||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subnode-footer {
|
||||||
|
text-align: right;
|
||||||
|
border-color: #a9a9a9;
|
||||||
|
border-style: inset inset inset solid;
|
||||||
|
border-width: 2px 1px 0;
|
||||||
|
margin-top: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subnode-footer .ajs-button {
|
||||||
|
margin: 2px 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user_management {
|
||||||
|
margin: 0 10px !important;
|
||||||
|
width: calc(100% - 20px);
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user_management .search_users form {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user_management table {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
border: 0 none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user_management .backform-tab {
|
||||||
|
height: calc(100% - 75px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user_management .search_users {
|
||||||
|
float:right;
|
||||||
|
margin-right: 5px;
|
||||||
|
padding:0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user_management .search_users input{
|
||||||
|
height:15px;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user_management .user_container {
|
||||||
|
height: calc(100% - 35px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user_management input[placeholder] {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user_management-pg-alertify-button {
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alertify_tools_dialog_backgrid_properties {
|
||||||
|
top: 43px !important;
|
||||||
|
}
|
||||||
327
web/pgadmin/tools/user_management/__init__.py
Normal file
327
web/pgadmin/tools/user_management/__init__.py
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2016, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
"""Implements pgAdmin4 User Management Utility"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
|
from flask import render_template, request, \
|
||||||
|
url_for, Response, abort
|
||||||
|
from flask.ext.babel import gettext as _
|
||||||
|
from flask.ext.security import login_required, roles_required, current_user
|
||||||
|
|
||||||
|
from pgadmin.utils.ajax import make_response as ajax_response,\
|
||||||
|
make_json_response, bad_request, internal_server_error
|
||||||
|
from pgadmin.utils import PgAdminModule
|
||||||
|
from pgadmin.model import db, Role, User, UserPreference, Server,\
|
||||||
|
ServerGroup, Process, Setting
|
||||||
|
from flask.ext.security.utils import encrypt_password
|
||||||
|
|
||||||
|
# set template path for sql scripts
|
||||||
|
MODULE_NAME = 'user_management'
|
||||||
|
server_info = {}
|
||||||
|
|
||||||
|
|
||||||
|
class UserManagementModule(PgAdminModule):
|
||||||
|
"""
|
||||||
|
class UserManagementModule(Object):
|
||||||
|
|
||||||
|
It is a utility which inherits PgAdminModule
|
||||||
|
class and define methods to load its own
|
||||||
|
javascript file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
LABEL = _('Users')
|
||||||
|
|
||||||
|
def get_own_javascripts(self):
|
||||||
|
""""
|
||||||
|
Returns:
|
||||||
|
list: js files used by this module
|
||||||
|
"""
|
||||||
|
return [{
|
||||||
|
'name': 'pgadmin.tools.user_management',
|
||||||
|
'path': url_for('user_management.index') + 'user_management',
|
||||||
|
'when': None
|
||||||
|
}]
|
||||||
|
|
||||||
|
def show_system_objects(self):
|
||||||
|
"""
|
||||||
|
return system preference objects
|
||||||
|
"""
|
||||||
|
return self.pref_show_system_objects
|
||||||
|
|
||||||
|
|
||||||
|
# Create blueprint for BackupModule class
|
||||||
|
blueprint = UserManagementModule(
|
||||||
|
MODULE_NAME, __name__, static_url_path=''
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_user(data):
|
||||||
|
new_data = dict()
|
||||||
|
email_filter = '^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$'
|
||||||
|
if ('newPassword' in data and data['newPassword'] != "" and
|
||||||
|
'confirmPassword' in data and data['confirmPassword'] != ""):
|
||||||
|
|
||||||
|
if data['newPassword'] == data['confirmPassword']:
|
||||||
|
new_data['password'] = encrypt_password(data['newPassword'])
|
||||||
|
else:
|
||||||
|
raise Exception(_("Passwords do not match."))
|
||||||
|
|
||||||
|
if 'email' in data and data['email'] != "":
|
||||||
|
if re.match(email_filter, data['email']):
|
||||||
|
new_data['email'] = data['email']
|
||||||
|
else:
|
||||||
|
raise Exception(_("Invalid email address."))
|
||||||
|
|
||||||
|
if 'role' in data and data['role'] != "":
|
||||||
|
new_data['roles'] = int(data['role'])
|
||||||
|
|
||||||
|
if 'active' in data and data['active'] != "":
|
||||||
|
new_data['active'] = data['active']
|
||||||
|
|
||||||
|
return new_data
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route("/")
|
||||||
|
@login_required
|
||||||
|
def index():
|
||||||
|
return bad_request(errormsg=_("This URL can not be called directly."))
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route("/user_management.js")
|
||||||
|
@login_required
|
||||||
|
def script():
|
||||||
|
"""render own javascript"""
|
||||||
|
return Response(
|
||||||
|
response=render_template(
|
||||||
|
"user_management/js/user_management.js", _=_,
|
||||||
|
is_admin=current_user.has_role("Administrator"),
|
||||||
|
user_id=current_user.id
|
||||||
|
|
||||||
|
),
|
||||||
|
status=200,
|
||||||
|
mimetype="application/javascript"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/user/', methods=['GET'], defaults={'uid': None})
|
||||||
|
@blueprint.route('/user/<int:uid>', methods=['GET'])
|
||||||
|
@roles_required('Administrator')
|
||||||
|
def user(uid):
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uid: User id
|
||||||
|
|
||||||
|
Returns: List of pgAdmin4 users or single user if uid is provided.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if uid:
|
||||||
|
u = User.query.get(uid)
|
||||||
|
|
||||||
|
res = {'id': u.id,
|
||||||
|
'email': u.email,
|
||||||
|
'active': u.active,
|
||||||
|
'role': u.roles[0].id
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
users = User.query.all()
|
||||||
|
|
||||||
|
users_data = []
|
||||||
|
for u in users:
|
||||||
|
users_data.append({'id': u.id,
|
||||||
|
'email': u.email,
|
||||||
|
'active': u.active,
|
||||||
|
'role': u.roles[0].id
|
||||||
|
})
|
||||||
|
|
||||||
|
res = users_data
|
||||||
|
|
||||||
|
return ajax_response(
|
||||||
|
response=res,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/user/', methods=['POST'])
|
||||||
|
@roles_required('Administrator')
|
||||||
|
def create():
|
||||||
|
"""
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
data = request.form if request.form else json.loads(request.data.decode())
|
||||||
|
|
||||||
|
for f in ('email', 'role', 'active', 'newPassword', 'confirmPassword'):
|
||||||
|
if f in data and data[f] != '':
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
return bad_request(errormsg=_("Missing field: '{0}'".format(f)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
new_data = validate_user(data)
|
||||||
|
|
||||||
|
if 'roles' in new_data:
|
||||||
|
new_data['roles'] = [Role.query.get(new_data['roles'])]
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return bad_request(errormsg=_(str(e)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
usr = User(email=new_data['email'],
|
||||||
|
roles=new_data['roles'],
|
||||||
|
active=new_data['active'],
|
||||||
|
password=new_data['password'])
|
||||||
|
db.session.add(usr)
|
||||||
|
db.session.commit()
|
||||||
|
# Add default server group for new user.
|
||||||
|
server_group = ServerGroup(user_id=usr.id, name="Servers")
|
||||||
|
db.session.add(server_group)
|
||||||
|
db.session.commit()
|
||||||
|
except Exception as e:
|
||||||
|
return internal_server_error(errormsg=str(e))
|
||||||
|
|
||||||
|
res = {'id': usr.id,
|
||||||
|
'email': usr.email,
|
||||||
|
'active': usr.active,
|
||||||
|
'role': usr.roles[0].id
|
||||||
|
}
|
||||||
|
|
||||||
|
return ajax_response(
|
||||||
|
response=res,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/user/<int:uid>', methods=['DELETE'])
|
||||||
|
@roles_required('Administrator')
|
||||||
|
def delete(uid):
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uid:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
usr = User.query.get(uid)
|
||||||
|
|
||||||
|
if not usr:
|
||||||
|
abort(404)
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
Setting.query.filter_by(user_id=uid).delete()
|
||||||
|
|
||||||
|
UserPreference.query.filter_by(uid=uid).delete()
|
||||||
|
|
||||||
|
Server.query.filter_by(user_id=uid).delete()
|
||||||
|
|
||||||
|
ServerGroup.query.filter_by(user_id=uid).delete()
|
||||||
|
|
||||||
|
Process.query.filter_by(user_id=uid).delete()
|
||||||
|
|
||||||
|
# Finally delete user
|
||||||
|
db.session.delete(usr)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
return make_json_response(
|
||||||
|
success=1,
|
||||||
|
info=_("User Deleted."),
|
||||||
|
data={}
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return internal_server_error(errormsg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/user/<int:uid>', methods=['PUT'])
|
||||||
|
@roles_required('Administrator')
|
||||||
|
def update(uid):
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uid:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
usr = User.query.get(uid)
|
||||||
|
|
||||||
|
if not usr:
|
||||||
|
abort(404)
|
||||||
|
|
||||||
|
data = request.form if request.form else json.loads(request.data.decode())
|
||||||
|
|
||||||
|
try:
|
||||||
|
new_data = validate_user(data)
|
||||||
|
|
||||||
|
if 'roles' in new_data:
|
||||||
|
new_data['roles'] = [Role.query.get(new_data['roles'])]
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return bad_request(errormsg=_(str(e)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
for k, v in new_data.items():
|
||||||
|
setattr(usr, k, v)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
res = {'id': usr.id,
|
||||||
|
'email': usr.email,
|
||||||
|
'active': usr.active,
|
||||||
|
'role': usr.roles[0].id
|
||||||
|
}
|
||||||
|
|
||||||
|
return ajax_response(
|
||||||
|
response=res,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return internal_server_error(errormsg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/role/', methods=['GET'], defaults={'rid': None})
|
||||||
|
@blueprint.route('/role/<int:rid>', methods=['GET'])
|
||||||
|
@roles_required('Administrator')
|
||||||
|
def role(rid):
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
rid: Role id
|
||||||
|
|
||||||
|
Returns: List of pgAdmin4 users roles or single role if rid is provided.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if rid:
|
||||||
|
r = Role.query.get(rid)
|
||||||
|
|
||||||
|
res = {'id': r.id, 'name': r.name}
|
||||||
|
else:
|
||||||
|
roles = Role.query.all()
|
||||||
|
|
||||||
|
roles_data = []
|
||||||
|
for r in roles:
|
||||||
|
roles_data.append({'id': r.id,
|
||||||
|
'name': r.name})
|
||||||
|
|
||||||
|
res = roles_data
|
||||||
|
|
||||||
|
return ajax_response(
|
||||||
|
response=res,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
@@ -0,0 +1,651 @@
|
|||||||
|
define([
|
||||||
|
'jquery', 'underscore', 'underscore.string', 'alertify',
|
||||||
|
'pgadmin.browser', 'backbone', 'backgrid', 'backform', 'pgadmin.browser.node',
|
||||||
|
'backgrid.select.all', 'backgrid.filter'
|
||||||
|
],
|
||||||
|
|
||||||
|
// This defines Backup dialog
|
||||||
|
function($, _, S, alertify, pgBrowser, Backbone, Backgrid, Backform, pgNode) {
|
||||||
|
|
||||||
|
// if module is already initialized, refer to that.
|
||||||
|
if (pgBrowser.UserManagement) {
|
||||||
|
return pgBrowser.UserManagement;
|
||||||
|
}
|
||||||
|
|
||||||
|
var BASEURL = '{{ url_for('user_management.index')}}',
|
||||||
|
USERURL = BASEURL + 'user/',
|
||||||
|
ROLEURL = BASEURL + 'role/',
|
||||||
|
userFilter = function(collection) {
|
||||||
|
return (new Backgrid.Extension.ClientSideFilter({
|
||||||
|
collection: collection,
|
||||||
|
placeholder: _('Filter by email'),
|
||||||
|
|
||||||
|
// The model fields to search for matches
|
||||||
|
fields: ['email'],
|
||||||
|
|
||||||
|
// How long to wait after typing has stopped before searching can start
|
||||||
|
wait: 150
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
StringDepCell = Backgrid.StringCell.extend({
|
||||||
|
initialize: function() {
|
||||||
|
Backgrid.StringCell.prototype.initialize.apply(this, arguments);
|
||||||
|
Backgrid.Extension.DependentCell.prototype.initialize.apply(this, arguments);
|
||||||
|
},
|
||||||
|
dependentChanged: function () {
|
||||||
|
this.$el.empty();
|
||||||
|
|
||||||
|
var self = this,
|
||||||
|
model = this.model,
|
||||||
|
column = this.column,
|
||||||
|
editable = this.column.get("editable");
|
||||||
|
|
||||||
|
this.render();
|
||||||
|
|
||||||
|
is_editable = _.isFunction(editable) ? !!editable.apply(column, [model]) : !!editable;
|
||||||
|
setTimeout(function() {
|
||||||
|
self.$el.removeClass("editor");
|
||||||
|
if (is_editable){ self.$el.addClass("editable"); }
|
||||||
|
else { self.$el.removeClass("editable"); }
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
this.delegateEvents();
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
remove: Backgrid.Extension.DependentCell.prototype.remove
|
||||||
|
});
|
||||||
|
|
||||||
|
pgBrowser.UserManagement = {
|
||||||
|
init: function() {
|
||||||
|
if (this.initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.initialized = true;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
{% if is_admin %},
|
||||||
|
|
||||||
|
// Callback to draw User Management Dialog.
|
||||||
|
show_users: function(action, item, params) {
|
||||||
|
var Roles = [];
|
||||||
|
|
||||||
|
var UserModel = pgAdmin.Browser.Node.Model.extend({
|
||||||
|
idAttribute: 'id',
|
||||||
|
urlRoot: USERURL,
|
||||||
|
defaults: {
|
||||||
|
id: undefined,
|
||||||
|
email: undefined,
|
||||||
|
active: true,
|
||||||
|
role: undefined,
|
||||||
|
newPassword: undefined,
|
||||||
|
confirmPassword: undefined
|
||||||
|
},
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
id: 'email', label: '{{ _('Email') }}', type: 'text',
|
||||||
|
cell:StringDepCell, cellHeaderClasses:'width_percent_30',
|
||||||
|
deps: ['id'],
|
||||||
|
editable: function(m) {
|
||||||
|
if(m instanceof Backbone.Collection) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Disable email edit for existing user.
|
||||||
|
if (m.isNew()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
id: 'role', label: '{{ _('Role') }}',
|
||||||
|
type: 'text', control: "Select2", cellHeaderClasses:'width_percent_20',
|
||||||
|
cell: 'select2', select2: {allowClear: false, openOnEnter: false},
|
||||||
|
options: function (controlOrCell) {
|
||||||
|
var options = [];
|
||||||
|
|
||||||
|
if( controlOrCell instanceof Backform.Control){
|
||||||
|
// This is be backform select2 control
|
||||||
|
_.each(Roles, function(role) {
|
||||||
|
options.push({
|
||||||
|
label: role.name,
|
||||||
|
value: role.id.toString()}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// This must be backgrid select2 cell
|
||||||
|
_.each(Roles, function(role) {
|
||||||
|
options.push([role.name, role.id.toString()]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
},
|
||||||
|
editable: function(m) {
|
||||||
|
if(m instanceof Backbone.Collection) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (m.get("id") == {{user_id}}){
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
id: 'active', label: '{{ _('Active') }}',
|
||||||
|
type: 'switch', cell: 'switch', cellHeaderClasses:'width_percent_10',
|
||||||
|
options: { 'onText': 'Yes', 'offText': 'No'},
|
||||||
|
editable: function(m) {
|
||||||
|
if(m instanceof Backbone.Collection) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (m.get("id") == {{user_id}}){
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
id: 'newPassword', label: '{{ _('New password') }}',
|
||||||
|
type: 'password', disabled: false, control: 'input',
|
||||||
|
cell: 'password', cellHeaderClasses:'width_percent_20'
|
||||||
|
},{
|
||||||
|
id: 'confirmPassword', label: '{{ _('Confirm password') }}',
|
||||||
|
type: 'password', disabled: false, control: 'input',
|
||||||
|
cell: 'password', cellHeaderClasses:'width_percent_20'
|
||||||
|
}],
|
||||||
|
validate: function() {
|
||||||
|
var err = {},
|
||||||
|
errmsg = null,
|
||||||
|
changedAttrs = this.changed || {},
|
||||||
|
email_filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
|
||||||
|
|
||||||
|
if (('email' in changedAttrs || !this.isNew()) && (_.isUndefined(this.get('email')) ||
|
||||||
|
_.isNull(this.get('email')) ||
|
||||||
|
String(this.get('email')).replace(/^\s+|\s+$/g, '') == '')) {
|
||||||
|
errmsg = '{{ _('Email address cannot be empty.')}}';
|
||||||
|
this.errorModel.set('email', errmsg);
|
||||||
|
return errmsg;
|
||||||
|
} else if (!!this.get('email') && !email_filter.test(this.get('email'))) {
|
||||||
|
|
||||||
|
errmsg = S("{{ _("Invalid Email id: %%s")}}").sprintf(
|
||||||
|
this.get('email')
|
||||||
|
).value();
|
||||||
|
this.errorModel.set('email', errmsg);
|
||||||
|
return errmsg;
|
||||||
|
} else if (!!this.get('email') && this.collection.where({"email":this.get('email')}).length > 1) {
|
||||||
|
|
||||||
|
errmsg = S("{{ _("This email id %%s already exist.")}}").sprintf(
|
||||||
|
this.get('email')
|
||||||
|
).value();
|
||||||
|
|
||||||
|
this.errorModel.set('email', errmsg);
|
||||||
|
return errmsg;
|
||||||
|
} else {
|
||||||
|
this.errorModel.unset('email');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('role' in changedAttrs && (_.isUndefined(this.get('role')) ||
|
||||||
|
_.isNull(this.get('role')) ||
|
||||||
|
String(this.get('role')).replace(/^\s+|\s+$/g, '') == '')) {
|
||||||
|
|
||||||
|
errmsg = S("{{ _("Role cannot be empty for user %%s")}}").sprintf(
|
||||||
|
(this.get('email') || '')
|
||||||
|
).value();
|
||||||
|
|
||||||
|
this.errorModel.set('role', errmsg);
|
||||||
|
return errmsg;
|
||||||
|
} else {
|
||||||
|
this.errorModel.unset('role');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.isNew()){
|
||||||
|
// Password is compulsory for new user.
|
||||||
|
if ('newPassword' in changedAttrs && (_.isUndefined(this.get('newPassword')) ||
|
||||||
|
_.isNull(this.get('newPassword')) ||
|
||||||
|
this.get('newPassword') == '')) {
|
||||||
|
|
||||||
|
errmsg = S("{{ _("Password cannot be empty for user %%s")}}").sprintf(
|
||||||
|
(this.get('email') || '')
|
||||||
|
).value();
|
||||||
|
|
||||||
|
this.errorModel.set('newPassword', errmsg);
|
||||||
|
return errmsg;
|
||||||
|
} else if ('newPassword' in changedAttrs && !_.isUndefined(this.get('newPassword')) &&
|
||||||
|
!_.isNull(this.get('newPassword')) &&
|
||||||
|
this.get('newPassword').length < 6) {
|
||||||
|
|
||||||
|
errmsg = S("{{ _("Password must be at least 6 characters for user %%s")}}").sprintf(
|
||||||
|
(this.get('email') || '')
|
||||||
|
).value();
|
||||||
|
|
||||||
|
this.errorModel.set('newPassword', errmsg);
|
||||||
|
return errmsg;
|
||||||
|
} else {
|
||||||
|
this.errorModel.unset('newPassword');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('confirmPassword' in changedAttrs && (_.isUndefined(this.get('confirmPassword')) ||
|
||||||
|
_.isNull(this.get('confirmPassword')) ||
|
||||||
|
this.get('confirmPassword') == '')) {
|
||||||
|
|
||||||
|
errmsg = S("{{ _("Confirm Password cannot be empty for user %%s")}}").sprintf(
|
||||||
|
(this.get('email') || '')
|
||||||
|
).value();
|
||||||
|
|
||||||
|
this.errorModel.set('confirmPassword', errmsg);
|
||||||
|
return errmsg;
|
||||||
|
} else {
|
||||||
|
this.errorModel.unset('confirmPassword');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!!this.get('newPassword') && !!this.get('confirmPassword') &&
|
||||||
|
this.get('newPassword') != this.get('confirmPassword')) {
|
||||||
|
|
||||||
|
errmsg = S("{{ _("Passwords do not match for user %%s")}}").sprintf(
|
||||||
|
(this.get('email') || '')
|
||||||
|
).value();
|
||||||
|
|
||||||
|
this.errorModel.set('confirmPassword', errmsg);
|
||||||
|
return errmsg;
|
||||||
|
} else {
|
||||||
|
this.errorModel.unset('confirmPassword');
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if ((_.isUndefined(this.get('newPassword')) || _.isNull(this.get('newPassword')) ||
|
||||||
|
this.get('newPassword') == '') &&
|
||||||
|
((_.isUndefined(this.get('confirmPassword')) || _.isNull(this.get('confirmPassword')) ||
|
||||||
|
this.get('confirmPassword') == ''))) {
|
||||||
|
|
||||||
|
this.errorModel.unset('newPassword');
|
||||||
|
if(this.get('newPassword') == ''){
|
||||||
|
this.set({'newPassword': undefined})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.errorModel.unset('confirmPassword');
|
||||||
|
if(this.get('confirmPassword') == ''){
|
||||||
|
this.set({'confirmPassword': undefined})
|
||||||
|
}
|
||||||
|
} else if (!_.isUndefined(this.get('newPassword')) &&
|
||||||
|
!_.isNull(this.get('newPassword')) &&
|
||||||
|
!this.get('newPassword') == '' &&
|
||||||
|
this.get('newPassword').length < 6) {
|
||||||
|
|
||||||
|
errmsg = S("{{ _("Password must be at least 6 characters for user %%s")}}").sprintf(
|
||||||
|
(this.get('email') || '')
|
||||||
|
).value();
|
||||||
|
|
||||||
|
this.errorModel.set('newPassword', errmsg);
|
||||||
|
return errmsg;
|
||||||
|
} else if (_.isUndefined(this.get('confirmPassword')) ||
|
||||||
|
_.isNull(this.get('confirmPassword')) ||
|
||||||
|
this.get('confirmPassword') == '') {
|
||||||
|
|
||||||
|
errmsg = S("{{ _("Confirm password cannot be empty for user %%s")}}").sprintf(
|
||||||
|
(this.get('email') || '')
|
||||||
|
).value();
|
||||||
|
|
||||||
|
this.errorModel.set('confirmPassword', errmsg);
|
||||||
|
return errmsg;
|
||||||
|
} else if (!!this.get('newPassword') && !!this.get('confirmPassword') &&
|
||||||
|
this.get('newPassword') != this.get('confirmPassword')) {
|
||||||
|
|
||||||
|
errmsg = S("{{ _("Passwords do not match for user %%s")}}").sprintf(
|
||||||
|
(this.get('email') || '')
|
||||||
|
).value();
|
||||||
|
|
||||||
|
this.errorModel.set('confirmPassword', errmsg);
|
||||||
|
return errmsg;
|
||||||
|
} else {
|
||||||
|
this.errorModel.unset('newPassword');
|
||||||
|
this.errorModel.unset('confirmPassword');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
gridSchema = Backform.generateGridColumnsFromModel(
|
||||||
|
null, UserModel, 'edit'),
|
||||||
|
deleteUserCell = Backgrid.Extension.DeleteCell.extend({
|
||||||
|
deleteRow: function(e) {
|
||||||
|
self = this;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (self.model.get("id") == {{user_id}}) {
|
||||||
|
alertify.alert(
|
||||||
|
'{{_('Cannot delete user.') }}',
|
||||||
|
'{{_('Cannot delete currently logged in user.') }}',
|
||||||
|
function(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will check if row is deletable or not
|
||||||
|
var canDeleteRow = (!_.isUndefined(this.column.get('canDeleteRow')) &&
|
||||||
|
_.isFunction(this.column.get('canDeleteRow')) ) ?
|
||||||
|
Backgrid.callByNeed(this.column.get('canDeleteRow'),
|
||||||
|
this.column, this.model) : true;
|
||||||
|
if (canDeleteRow) {
|
||||||
|
if(self.model.isNew()){
|
||||||
|
self.model.destroy();
|
||||||
|
} else {
|
||||||
|
alertify.confirm(
|
||||||
|
'Delete user?',
|
||||||
|
'Are you sure you wish to delete this user?',
|
||||||
|
function(evt) {
|
||||||
|
self.model.destroy({
|
||||||
|
wait: true,
|
||||||
|
success: function(res) {
|
||||||
|
alertify.success('{{_('User deleted.') }}');
|
||||||
|
},
|
||||||
|
error: function(m, jqxhr) {
|
||||||
|
alertify.error('{{_('Error during deleting user.') }}');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function(evt) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alertify.alert("This user cannot be deleted.",
|
||||||
|
function(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
gridSchema.columns.unshift({
|
||||||
|
name: "pg-backform-delete", label: "",
|
||||||
|
cell: deleteUserCell,
|
||||||
|
editable: false, cell_priority: -1,
|
||||||
|
canDeleteRow: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Users Management dialog code here
|
||||||
|
if(!alertify.UserManagement) {
|
||||||
|
alertify.dialog('UserManagement' ,function factory() {
|
||||||
|
return {
|
||||||
|
main: function(title) {
|
||||||
|
this.set('title', title);
|
||||||
|
},
|
||||||
|
setup:function() {
|
||||||
|
return {
|
||||||
|
buttons: [{
|
||||||
|
text: '{{ _('Close') }}', key: 27, className: 'btn btn-danger fa fa-lg fa-times pg-alertify-button',
|
||||||
|
attrs:{name:'close'}
|
||||||
|
}],
|
||||||
|
// Set options for dialog
|
||||||
|
options: {
|
||||||
|
title: '{{ _('User Management') }}',
|
||||||
|
//disable both padding and overflow control.
|
||||||
|
padding : !1,
|
||||||
|
overflow: !1,
|
||||||
|
model: 0,
|
||||||
|
resizable: true,
|
||||||
|
maximizable: true,
|
||||||
|
pinnable: false,
|
||||||
|
closableByDimmer: false,
|
||||||
|
closable: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
|
// Triggered when the dialog is closed
|
||||||
|
onclose: function() {
|
||||||
|
if (this.view) {
|
||||||
|
// clear our backform model/view
|
||||||
|
this.view.remove({data: true, internal: true, silent: true});
|
||||||
|
this.$content.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
prepare: function() {
|
||||||
|
var self = this,
|
||||||
|
footerTpl = _.template([
|
||||||
|
'<div class="pg-prop-footer">',
|
||||||
|
'<div class="pg-prop-status-bar" style="visibility:hidden">',
|
||||||
|
'</div>',
|
||||||
|
'</div>'].join("\n")),
|
||||||
|
$footer = $(footerTpl()),
|
||||||
|
$statusBar = $footer.find('.pg-prop-status-bar'),
|
||||||
|
UserRow = Backgrid.Row.extend({
|
||||||
|
userInvalidColor: "lightYellow",
|
||||||
|
|
||||||
|
userValidColor: "#fff",
|
||||||
|
|
||||||
|
initialize: function() {
|
||||||
|
Backgrid.Row.prototype.initialize.apply(this, arguments);
|
||||||
|
this.listenTo(this.model, 'pgadmin:user:invalid', this.userInvalid);
|
||||||
|
this.listenTo(this.model, 'pgadmin:user:valid', this.userValid);
|
||||||
|
},
|
||||||
|
userInvalid: function() {
|
||||||
|
$(this.el).removeClass("new");
|
||||||
|
this.el.style.backgroundColor = this.userInvalidColor;
|
||||||
|
},
|
||||||
|
userValid: function() {
|
||||||
|
this.el.style.backgroundColor = this.userValidColor;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
UserCollection = Backbone.Collection.extend({
|
||||||
|
model: UserModel,
|
||||||
|
url: USERURL,
|
||||||
|
initialize: function() {
|
||||||
|
Backbone.Collection.prototype.initialize.apply(this, arguments);
|
||||||
|
var self = this;
|
||||||
|
self.changedUser = null;
|
||||||
|
self.invalidUsers = {};
|
||||||
|
|
||||||
|
self.on('add', self.onModelAdd);
|
||||||
|
self.on('remove', self.onModelRemove);
|
||||||
|
self.on('pgadmin-session:model:invalid', function(msg, m, c) {
|
||||||
|
self.invalidUsers[m.cid] = msg;
|
||||||
|
m.trigger('pgadmin:user:invalid', m);
|
||||||
|
$statusBar.html(msg).css("visibility", "visible");
|
||||||
|
});
|
||||||
|
self.on('pgadmin-session:model:valid', function(m, c) {
|
||||||
|
delete self.invalidUsers[m.cid];
|
||||||
|
m.trigger('pgadmin:user:valid', m);
|
||||||
|
this.updateErrorMsg();
|
||||||
|
this.saveUser(m);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onModelAdd: function(m) {
|
||||||
|
// Start tracking changes.
|
||||||
|
m.startNewSession();
|
||||||
|
},
|
||||||
|
onModelRemove: function(m) {
|
||||||
|
delete this.invalidUsers[m.cid];
|
||||||
|
this.updateErrorMsg();
|
||||||
|
},
|
||||||
|
updateErrorMsg: function() {
|
||||||
|
var self = this,
|
||||||
|
msg = null;
|
||||||
|
|
||||||
|
for (var key in self.invalidUsers) {
|
||||||
|
msg = self.invalidUsers [key];
|
||||||
|
if (msg) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(msg){
|
||||||
|
$statusBar.html(msg).css("visibility", "visible");
|
||||||
|
} else {
|
||||||
|
$statusBar.empty().css("visibility", "hidden");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
saveUser: function(m) {
|
||||||
|
d = m.toJSON(true);
|
||||||
|
|
||||||
|
if(m.isNew() && (!m.get('email') || !m.get('role') ||
|
||||||
|
!m.get('newPassword') || !m.get('confirmPassword') ||
|
||||||
|
m.get('newPassword') != m.get('confirmPassword'))
|
||||||
|
) {
|
||||||
|
// New user model is valid but partially filled so return without saving.
|
||||||
|
return false;
|
||||||
|
} else if (!m.isNew() && m.get('newPassword') != m.get('confirmPassword')) {
|
||||||
|
// For old user password change is in progress and user model is valid but admin has not added
|
||||||
|
// both the passwords so return without saving.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m.sessChanged() && d && !_.isEmpty(d)) {
|
||||||
|
m.stopSession();
|
||||||
|
m.save({}, {
|
||||||
|
attrs: d,
|
||||||
|
wait: true,
|
||||||
|
success: function(res) {
|
||||||
|
// User created/updated on server now start new session for this user.
|
||||||
|
m.set({'newPassword':undefined,
|
||||||
|
'confirmPassword':undefined});
|
||||||
|
|
||||||
|
m.startNewSession();
|
||||||
|
alertify.success(S("{{_("User '%%s' saved.")|safe }}").sprintf(
|
||||||
|
m.get('email')
|
||||||
|
).value());
|
||||||
|
},
|
||||||
|
error: function(res, jqxhr) {
|
||||||
|
m.startNewSession();
|
||||||
|
alertify.error(
|
||||||
|
S("{{_("Error during saving user: '%%s'")|safe }}").sprintf(
|
||||||
|
jqxhr.responseJSON.errormsg
|
||||||
|
).value()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
userCollection = this.userCollection = new UserCollection(),
|
||||||
|
header = [
|
||||||
|
'<div class="subnode-header">',
|
||||||
|
' <button class="btn-sm btn-default add" title="<%-add_title%>" <%=canAdd ? "" : "disabled=\'disabled\'"%> ><%=add_label ? add_label : "" %></button>',
|
||||||
|
' <div class="control-label search_users"></div>',
|
||||||
|
'</div>',].join("\n"),
|
||||||
|
headerTpl = _.template(header),
|
||||||
|
data = {
|
||||||
|
canAdd: true,
|
||||||
|
add_title: '{{ _("Add new user")}}',
|
||||||
|
add_label:'{{ _('ADD')}}'
|
||||||
|
},
|
||||||
|
$gridBody = $("<div></div>", {
|
||||||
|
class: "user_container"
|
||||||
|
});
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: ROLEURL,
|
||||||
|
method: 'GET',
|
||||||
|
async: false,
|
||||||
|
success: function(res) {
|
||||||
|
Roles = res
|
||||||
|
},
|
||||||
|
error: function(e) {
|
||||||
|
setTimeout(function() {
|
||||||
|
alertify.alert(
|
||||||
|
'{{ _('Cannot load user roles.') }}'
|
||||||
|
);
|
||||||
|
},100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var view = this.view = new Backgrid.Grid({
|
||||||
|
row: UserRow,
|
||||||
|
columns: gridSchema.columns,
|
||||||
|
collection: userCollection,
|
||||||
|
className: "backgrid table-bordered"
|
||||||
|
});
|
||||||
|
|
||||||
|
$gridBody.append(view.render().$el[0]);
|
||||||
|
|
||||||
|
this.$content = $("<div class='user_management object subnode'></div>").append(
|
||||||
|
headerTpl(data)).append($gridBody
|
||||||
|
).append($footer);
|
||||||
|
|
||||||
|
$(this.elements.body.childNodes[0]).addClass(
|
||||||
|
'alertify_tools_dialog_backgrid_properties');
|
||||||
|
|
||||||
|
this.elements.content.appendChild(this.$content[0]);
|
||||||
|
|
||||||
|
// Render Search Filter
|
||||||
|
$('.search_users').append(
|
||||||
|
userFilter(userCollection).render().el);
|
||||||
|
|
||||||
|
userCollection.fetch();
|
||||||
|
|
||||||
|
this.$content.find('button.add').first().click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var canAddRow = true;
|
||||||
|
|
||||||
|
if (canAddRow) {
|
||||||
|
// There should be only one empty row.
|
||||||
|
|
||||||
|
var isEmpty = false,
|
||||||
|
unsavedModel = null;
|
||||||
|
|
||||||
|
userCollection.each(function(model) {
|
||||||
|
if(!isEmpty) {
|
||||||
|
isEmpty = model.isNew();
|
||||||
|
unsavedModel = model;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(isEmpty) {
|
||||||
|
var idx = userCollection.indexOf(unsavedModel),
|
||||||
|
row = view.body.rows[idx].$el;
|
||||||
|
|
||||||
|
row.addClass("new");
|
||||||
|
$(row).pgMakeVisible('backform-tab');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(view.body.$el.find($("tr.new"))).removeClass("new")
|
||||||
|
var m = new (UserModel) (null, {
|
||||||
|
handler: userCollection,
|
||||||
|
top: userCollection,
|
||||||
|
collection: userCollection
|
||||||
|
});
|
||||||
|
userCollection.add(m);
|
||||||
|
|
||||||
|
var idx = userCollection.indexOf(m),
|
||||||
|
newRow = view.body.rows[idx].$el;
|
||||||
|
|
||||||
|
newRow.addClass("new");
|
||||||
|
$(newRow).pgMakeVisible('backform-tab');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
callback: function(e) {
|
||||||
|
if (e.button.element.name == "close") {
|
||||||
|
var self = this;
|
||||||
|
if (!_.all(this.userCollection.pluck('id')) || !_.isEmpty(this.userCollection.invalidUsers)) {
|
||||||
|
e.cancel = true;
|
||||||
|
alertify.confirm(
|
||||||
|
'{{ _('Discard unsaved changes?') }}',
|
||||||
|
'{{ _('Are you sure you want to close the dialog? Any unsaved changes will be lost.') }}',
|
||||||
|
function(e) {
|
||||||
|
self.close();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
function(e) {
|
||||||
|
// Do nothing.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
alertify.UserManagement(true).resizeTo('680px','400px');
|
||||||
|
}{% endif %}
|
||||||
|
|
||||||
|
};
|
||||||
|
return pgBrowser.UserManagement;
|
||||||
|
});
|
||||||
24
web/setup.py
24
web/setup.py
@@ -69,12 +69,17 @@ account:\n""")
|
|||||||
|
|
||||||
db.create_all()
|
db.create_all()
|
||||||
user_datastore.create_role(
|
user_datastore.create_role(
|
||||||
name='Administrators',
|
name='Administrator',
|
||||||
description='pgAdmin Administrators Role'
|
description='pgAdmin Administrator Role'
|
||||||
)
|
)
|
||||||
|
user_datastore.create_role(
|
||||||
|
name='User',
|
||||||
|
description='pgAdmin User Role'
|
||||||
|
)
|
||||||
|
|
||||||
user_datastore.create_user(email=email, password=password)
|
user_datastore.create_user(email=email, password=password)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
user_datastore.add_role_to_user(email, 'Administrators')
|
user_datastore.add_role_to_user(email, 'Administrator')
|
||||||
|
|
||||||
# Get the user's ID and create the default server group
|
# Get the user's ID and create the default server group
|
||||||
user = User.query.filter_by(email=email).first()
|
user = User.query.filter_by(email=email).first()
|
||||||
@@ -249,6 +254,19 @@ CREATE TABLE process(
|
|||||||
FOREIGN KEY(user_id) REFERENCES user (id)
|
FOREIGN KEY(user_id) REFERENCES user (id)
|
||||||
)""")
|
)""")
|
||||||
|
|
||||||
|
if int(version.value) < 11:
|
||||||
|
db.engine.execute("""
|
||||||
|
UPDATE role
|
||||||
|
SET name = 'Administrator',
|
||||||
|
description = 'pgAdmin Administrator Role'
|
||||||
|
WHERE name = 'Administrators'
|
||||||
|
""")
|
||||||
|
|
||||||
|
db.engine.execute("""
|
||||||
|
INSERT INTO role ( name, description )
|
||||||
|
VALUES ('User', 'pgAdmin User Role')
|
||||||
|
""")
|
||||||
|
|
||||||
# Finally, update the schema version
|
# Finally, update the schema version
|
||||||
version.value = config.SETTINGS_SCHEMA_VERSION
|
version.value = config.SETTINGS_SCHEMA_VERSION
|
||||||
db.session.merge(version)
|
db.session.merge(version)
|
||||||
|
|||||||
Reference in New Issue
Block a user