mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Added support for schema level restriction. Fixes #5583
Allow user to edit the connection properties when the database server is already connected.
This commit is contained in:
parent
4c05287677
commit
c873218c32
@ -97,6 +97,19 @@ Follow these steps to add additional parameter value definitions; to discard a
|
|||||||
parameter, click the trash icon to the left of the row and confirm deletion in
|
parameter, click the trash icon to the left of the row and confirm deletion in
|
||||||
the *Delete Row* popup.
|
the *Delete Row* popup.
|
||||||
|
|
||||||
|
Click the *Advanced* tab to continue.
|
||||||
|
|
||||||
|
.. image:: images/database_advanced.png
|
||||||
|
:alt: Database dialog advanced tab
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
Use the *Advanced* tab to set advanced parameters for the database.
|
||||||
|
|
||||||
|
* Use *Schema restriction* field to provide a SQL restriction that will be used
|
||||||
|
against the pg_namespace table to limit the schemas that you see.
|
||||||
|
For example, you might enter: *public* so that only *public* are shown in
|
||||||
|
the pgAdmin browser.Separate entries with a comma or tab as you type.
|
||||||
|
|
||||||
Click the *SQL* tab to continue.
|
Click the *SQL* tab to continue.
|
||||||
|
|
||||||
Your entries in the *Database* dialog generate a SQL command (see an example
|
Your entries in the *Database* dialog generate a SQL command (see an example
|
||||||
|
BIN
docs/en_US/images/database_advanced.png
Normal file
BIN
docs/en_US/images/database_advanced.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
@ -9,6 +9,7 @@ This release contains a number of bug fixes and new features since the release o
|
|||||||
New features
|
New features
|
||||||
************
|
************
|
||||||
|
|
||||||
|
| `Issue #5583 <https://redmine.postgresql.org/issues/5583>`_ - Added support for schema level restriction.
|
||||||
|
|
||||||
Housekeeping
|
Housekeeping
|
||||||
************
|
************
|
||||||
|
32
web/migrations/versions/84700139beb0_.py
Normal file
32
web/migrations/versions/84700139beb0_.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: 84700139beb0
|
||||||
|
Revises: d39482714a2e
|
||||||
|
Create Date: 2020-06-24 15:53:56.489518
|
||||||
|
|
||||||
|
"""
|
||||||
|
from pgadmin.model import db
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '84700139beb0'
|
||||||
|
down_revision = 'd39482714a2e'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
db.engine.execute("""
|
||||||
|
CREATE TABLE "database" (
|
||||||
|
"id" INTEGER NOT NULL,
|
||||||
|
"schema_res" TEXT,
|
||||||
|
"server" INTEGER NOT NULL,
|
||||||
|
PRIMARY KEY("id","server"),
|
||||||
|
FOREIGN KEY("server") REFERENCES "server"("id")
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
pass
|
@ -536,7 +536,7 @@ class ServerNode(PGChildNodeView):
|
|||||||
|
|
||||||
if connected:
|
if connected:
|
||||||
for arg in (
|
for arg in (
|
||||||
'host', 'hostaddr', 'port', 'db', 'username', 'sslmode',
|
'hostaddr', 'db', 'sslmode',
|
||||||
'role', 'service'
|
'role', 'service'
|
||||||
):
|
):
|
||||||
if arg in data:
|
if arg in data:
|
||||||
@ -1016,6 +1016,7 @@ class ServerNode(PGChildNodeView):
|
|||||||
|
|
||||||
# Connect the Server
|
# Connect the Server
|
||||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||||
|
manager.update(server)
|
||||||
conn = manager.connection()
|
conn = manager.connection()
|
||||||
|
|
||||||
# Get enc key
|
# Get enc key
|
||||||
|
@ -32,7 +32,7 @@ from pgadmin.utils.driver import get_driver
|
|||||||
from pgadmin.tools.sqleditor.utils.query_history import QueryHistory
|
from pgadmin.tools.sqleditor.utils.query_history import QueryHistory
|
||||||
|
|
||||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||||
from pgadmin.model import Server
|
from pgadmin.model import db, Server, Database
|
||||||
|
|
||||||
|
|
||||||
class DatabaseModule(CollectionNodeModule):
|
class DatabaseModule(CollectionNodeModule):
|
||||||
@ -423,6 +423,11 @@ class DatabaseView(PGChildNodeView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
status, res1 = self.conn.execute_dict(SQL)
|
status, res1 = self.conn.execute_dict(SQL)
|
||||||
|
database = Database.query.filter_by(id=did, server=sid).first()
|
||||||
|
|
||||||
|
if database:
|
||||||
|
result['schema_res'] = database.schema_res.split(
|
||||||
|
',') if database.schema_res else []
|
||||||
|
|
||||||
if not status:
|
if not status:
|
||||||
return internal_server_error(errormsg=res1)
|
return internal_server_error(errormsg=res1)
|
||||||
@ -611,6 +616,11 @@ class DatabaseView(PGChildNodeView):
|
|||||||
return internal_server_error(errormsg=res)
|
return internal_server_error(errormsg=res)
|
||||||
|
|
||||||
response = res['rows'][0]
|
response = res['rows'][0]
|
||||||
|
# Add database entry into database table with schema_restrictions.
|
||||||
|
database = Database(id=response['did'], server=sid,
|
||||||
|
schema_res=','.join(data['schema_res']))
|
||||||
|
db.session.add(database)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
return jsonify(
|
return jsonify(
|
||||||
node=self.blueprint.generate_browser_node(
|
node=self.blueprint.generate_browser_node(
|
||||||
@ -627,53 +637,27 @@ class DatabaseView(PGChildNodeView):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@check_precondition(action='update')
|
@staticmethod
|
||||||
def update(self, gid, sid, did):
|
def _update_db_schema_res(data, did, sid):
|
||||||
"""Update the database."""
|
database = Database.query.filter_by(id=did, server=sid).first()
|
||||||
|
if 'schema_res' in data:
|
||||||
|
if database:
|
||||||
|
data['schema_res'] = ','.join(data['schema_res'])
|
||||||
|
setattr(database, 'schema_res', data['schema_res'])
|
||||||
|
else:
|
||||||
|
database_obj = Database(id=did, server=sid,
|
||||||
|
schema_res=','.join(
|
||||||
|
data['schema_res']))
|
||||||
|
db.session.add(database_obj)
|
||||||
|
|
||||||
data = request.form if request.form else json.loads(
|
def _check_rename_db_or_change_table_space(self, data, conn, all_ids):
|
||||||
request.data, encoding='utf-8'
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generic connection for offline updates
|
|
||||||
conn = self.manager.connection(conn_id='db_offline_update')
|
|
||||||
status, errmsg = conn.connect()
|
|
||||||
if not status:
|
|
||||||
current_app.logger.error(
|
|
||||||
"Could not create database connection for offline updates\n"
|
|
||||||
"Err: {0}".format(errmsg)
|
|
||||||
)
|
|
||||||
return internal_server_error(errmsg)
|
|
||||||
|
|
||||||
if did is not None:
|
|
||||||
# Fetch the name of database for comparison
|
|
||||||
status, rset = self.conn.execute_dict(
|
|
||||||
render_template(
|
|
||||||
"/".join([self.template_path, 'nodes.sql']),
|
|
||||||
did=did, conn=self.conn, last_system_oid=0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if not status:
|
|
||||||
return internal_server_error(errormsg=rset)
|
|
||||||
|
|
||||||
if len(rset['rows']) == 0:
|
|
||||||
return gone(
|
|
||||||
_('Could not find the database on the server.')
|
|
||||||
)
|
|
||||||
|
|
||||||
data['old_name'] = (rset['rows'][0])['name']
|
|
||||||
if 'name' not in data:
|
|
||||||
data['name'] = data['old_name']
|
|
||||||
|
|
||||||
# Release any existing connection from connection manager
|
|
||||||
# to perform offline operation
|
|
||||||
self.manager.release(did=did)
|
|
||||||
|
|
||||||
for action in ["rename_database", "tablespace"]:
|
for action in ["rename_database", "tablespace"]:
|
||||||
SQL = self.get_offline_sql(gid, sid, data, did, action)
|
sql = self.get_offline_sql(all_ids['gid'], all_ids['sid'], data,
|
||||||
SQL = SQL.strip('\n').strip(' ')
|
all_ids['did'], action)
|
||||||
if SQL and SQL != "":
|
sql = sql.strip('\n').strip(' ')
|
||||||
status, msg = conn.execute_scalar(SQL)
|
if sql and sql != "":
|
||||||
|
status, msg = conn.execute_scalar(sql)
|
||||||
if not status:
|
if not status:
|
||||||
# In case of error from server while rename it,
|
# In case of error from server while rename it,
|
||||||
# reconnect to the database with old name again.
|
# reconnect to the database with old name again.
|
||||||
@ -684,13 +668,38 @@ class DatabaseView(PGChildNodeView):
|
|||||||
if not status:
|
if not status:
|
||||||
current_app.logger.error(
|
current_app.logger.error(
|
||||||
'Could not reconnected to database(#{0}).\n'
|
'Could not reconnected to database(#{0}).\n'
|
||||||
'Error: {1}'.format(did, errmsg)
|
'Error: {1}'.format(all_ids['did'], errmsg)
|
||||||
)
|
)
|
||||||
return internal_server_error(errormsg=msg)
|
return True, msg
|
||||||
|
|
||||||
QueryHistory.update_history_dbname(
|
QueryHistory.update_history_dbname(
|
||||||
current_user.id, sid, data['old_name'], data['name'])
|
current_user.id, all_ids['sid'], data['old_name'],
|
||||||
# Make connection for database again
|
data['name'])
|
||||||
|
return False, ''
|
||||||
|
|
||||||
|
def _fetch_db_details(self, data, did):
|
||||||
|
if did is not None:
|
||||||
|
# Fetch the name of database for comparison
|
||||||
|
status, rset = self.conn.execute_dict(
|
||||||
|
render_template(
|
||||||
|
"/".join([self.template_path, 'nodes.sql']),
|
||||||
|
did=did, conn=self.conn, last_system_oid=0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if not status:
|
||||||
|
return True, rset
|
||||||
|
|
||||||
|
if len(rset['rows']) == 0:
|
||||||
|
return gone(
|
||||||
|
_('Could not find the database on the server.')
|
||||||
|
)
|
||||||
|
|
||||||
|
data['old_name'] = (rset['rows'][0])['name']
|
||||||
|
if 'name' not in data:
|
||||||
|
data['name'] = data['old_name']
|
||||||
|
return False, ''
|
||||||
|
|
||||||
|
def _reconnect_connect_db(self, data, did):
|
||||||
if self._db['datallowconn']:
|
if self._db['datallowconn']:
|
||||||
self.conn = self.manager.connection(
|
self.conn = self.manager.connection(
|
||||||
database=data['name'], auto_reconnect=True
|
database=data['name'], auto_reconnect=True
|
||||||
@ -702,12 +711,70 @@ class DatabaseView(PGChildNodeView):
|
|||||||
'Could not connected to database(#{0}).\n'
|
'Could not connected to database(#{0}).\n'
|
||||||
'Error: {1}'.format(did, errmsg)
|
'Error: {1}'.format(did, errmsg)
|
||||||
)
|
)
|
||||||
return internal_server_error(errmsg)
|
return True, errmsg
|
||||||
|
return False, ''
|
||||||
|
|
||||||
SQL = self.get_online_sql(gid, sid, data, did)
|
def _commit_db_changes(self, res, can_drop):
|
||||||
SQL = SQL.strip('\n').strip(' ')
|
if self.manager.db == res['name']:
|
||||||
if SQL and SQL != "":
|
can_drop = False
|
||||||
status, msg = self.conn.execute_scalar(SQL)
|
|
||||||
|
try:
|
||||||
|
db.session.commit()
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.exception(e)
|
||||||
|
return True, e.message, False
|
||||||
|
return False, '', can_drop
|
||||||
|
|
||||||
|
def _get_data_from_request(self):
|
||||||
|
return request.form if request.form else json.loads(
|
||||||
|
request.data, encoding='utf-8'
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_precondition(action='update')
|
||||||
|
def update(self, gid, sid, did):
|
||||||
|
"""Update the database."""
|
||||||
|
|
||||||
|
data = self._get_data_from_request()
|
||||||
|
# Update schema restriction in db object.
|
||||||
|
DatabaseView._update_db_schema_res(data, did, sid)
|
||||||
|
|
||||||
|
# Generic connection for offline updates
|
||||||
|
conn = self.manager.connection(conn_id='db_offline_update')
|
||||||
|
status, errmsg = conn.connect()
|
||||||
|
if not status:
|
||||||
|
current_app.logger.error(
|
||||||
|
"Could not create database connection for offline updates\n"
|
||||||
|
"Err: {0}".format(errmsg)
|
||||||
|
)
|
||||||
|
return internal_server_error(errmsg)
|
||||||
|
|
||||||
|
fetching_error, err_msg = self._fetch_db_details(data, did)
|
||||||
|
if fetching_error:
|
||||||
|
return internal_server_error(errormsg=err_msg)
|
||||||
|
|
||||||
|
# Release any existing connection from connection manager
|
||||||
|
# to perform offline operation
|
||||||
|
self.manager.release(did=did)
|
||||||
|
all_ids = {
|
||||||
|
'gid': gid,
|
||||||
|
'sid': sid,
|
||||||
|
'did': did
|
||||||
|
}
|
||||||
|
is_error, errmsg = self._check_rename_db_or_change_table_space(data,
|
||||||
|
conn,
|
||||||
|
all_ids)
|
||||||
|
if is_error:
|
||||||
|
return internal_server_error(errmsg)
|
||||||
|
|
||||||
|
# Make connection for database again
|
||||||
|
connection_error, errmsg = self._reconnect_connect_db(data, did)
|
||||||
|
if connection_error:
|
||||||
|
return internal_server_error(errmsg)
|
||||||
|
|
||||||
|
sql = self.get_online_sql(gid, sid, data, did)
|
||||||
|
sql = sql.strip('\n').strip(' ')
|
||||||
|
if sql and sql != "":
|
||||||
|
status, msg = self.conn.execute_scalar(sql)
|
||||||
if not status:
|
if not status:
|
||||||
return internal_server_error(errormsg=msg)
|
return internal_server_error(errormsg=msg)
|
||||||
|
|
||||||
@ -733,9 +800,15 @@ class DatabaseView(PGChildNodeView):
|
|||||||
|
|
||||||
res = rset['rows'][0]
|
res = rset['rows'][0]
|
||||||
|
|
||||||
can_drop = can_dis_conn = True
|
can_drop = True
|
||||||
if self.manager.db == res['name']:
|
error, errmsg, is_can_drop = self._commit_db_changes(res, can_drop)
|
||||||
can_drop = can_dis_conn = False
|
if error:
|
||||||
|
return make_json_response(
|
||||||
|
success=0,
|
||||||
|
errormsg=errmsg
|
||||||
|
)
|
||||||
|
|
||||||
|
can_drop = can_dis_conn = is_can_drop
|
||||||
|
|
||||||
return jsonify(
|
return jsonify(
|
||||||
node=self.blueprint.generate_browser_node(
|
node=self.blueprint.generate_browser_node(
|
||||||
|
@ -24,6 +24,7 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
|
|||||||
make_response as ajax_response, gone, bad_request
|
make_response as ajax_response, gone, bad_request
|
||||||
from pgadmin.utils.driver import get_driver
|
from pgadmin.utils.driver import get_driver
|
||||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||||
|
from pgadmin.model import Database
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This module is responsible for generating two nodes
|
This module is responsible for generating two nodes
|
||||||
@ -384,10 +385,21 @@ class SchemaView(PGChildNodeView):
|
|||||||
Returns:
|
Returns:
|
||||||
JSON of available schema nodes
|
JSON of available schema nodes
|
||||||
"""
|
"""
|
||||||
|
database = Database.query.filter_by(id=did, server=sid).first()
|
||||||
|
param = None
|
||||||
|
if database:
|
||||||
|
schema_restrictions = database.schema_res
|
||||||
|
|
||||||
|
if schema_restrictions:
|
||||||
|
schema_res = ",".join(
|
||||||
|
["'%s'"] * len(schema_restrictions.split(',')))
|
||||||
|
param = schema_res % (tuple(schema_restrictions.split(',')))
|
||||||
|
|
||||||
SQL = render_template(
|
SQL = render_template(
|
||||||
"/".join([self.template_path, 'sql/properties.sql']),
|
"/".join([self.template_path, 'sql/properties.sql']),
|
||||||
_=gettext,
|
_=gettext,
|
||||||
show_sysobj=self.blueprint.show_system_objects
|
show_sysobj=self.blueprint.show_system_objects,
|
||||||
|
schema_restrictions=param
|
||||||
)
|
)
|
||||||
status, res = self.conn.execute_dict(SQL)
|
status, res = self.conn.execute_dict(SQL)
|
||||||
|
|
||||||
@ -413,11 +425,22 @@ class SchemaView(PGChildNodeView):
|
|||||||
JSON of available schema child nodes
|
JSON of available schema child nodes
|
||||||
"""
|
"""
|
||||||
res = []
|
res = []
|
||||||
|
database = Database.query.filter_by(id=did, server=sid).first()
|
||||||
|
param = None
|
||||||
|
if database:
|
||||||
|
schema_restrictions = database.schema_res
|
||||||
|
|
||||||
|
if schema_restrictions:
|
||||||
|
schema_res = ",".join(
|
||||||
|
["'%s'"] * len(schema_restrictions.split(',')))
|
||||||
|
param = schema_res % (tuple(schema_restrictions.split(',')))
|
||||||
|
|
||||||
SQL = render_template(
|
SQL = render_template(
|
||||||
"/".join([self.template_path, 'sql/nodes.sql']),
|
"/".join([self.template_path, 'sql/nodes.sql']),
|
||||||
show_sysobj=self.blueprint.show_system_objects,
|
show_sysobj=self.blueprint.show_system_objects,
|
||||||
_=gettext,
|
_=gettext,
|
||||||
scid=scid
|
scid=scid,
|
||||||
|
schema_restrictions=param
|
||||||
)
|
)
|
||||||
|
|
||||||
status, rset = self.conn.execute_2darray(SQL)
|
status, rset = self.conn.execute_2darray(SQL)
|
||||||
@ -428,10 +451,9 @@ class SchemaView(PGChildNodeView):
|
|||||||
|
|
||||||
if scid is not None:
|
if scid is not None:
|
||||||
if len(rset['rows']) == 0:
|
if len(rset['rows']) == 0:
|
||||||
return gone(gettext("""
|
return gone(gettext(
|
||||||
Could not find the schema in the database.
|
"""Could not find the schema in the database.
|
||||||
It may have been removed by another user.
|
It may have been removed by another user."""))
|
||||||
"""))
|
|
||||||
row = rset['rows'][0]
|
row = rset['rows'][0]
|
||||||
return make_json_response(
|
return make_json_response(
|
||||||
data=self.blueprint.generate_browser_node(
|
data=self.blueprint.generate_browser_node(
|
||||||
@ -896,10 +918,9 @@ It may have been removed by another user.
|
|||||||
return internal_server_error(errormsg=res)
|
return internal_server_error(errormsg=res)
|
||||||
|
|
||||||
if len(res['rows']) == 0:
|
if len(res['rows']) == 0:
|
||||||
return gone(gettext("""
|
return gone(gettext(
|
||||||
Could not find the schema in the database.
|
"""Could not find the schema in the database.
|
||||||
It may have been removed by another user.
|
It may have been removed by another user."""))
|
||||||
"""))
|
|
||||||
|
|
||||||
data = res['rows'][0]
|
data = res['rows'][0]
|
||||||
backend_support_keywords = kwargs.copy()
|
backend_support_keywords = kwargs.copy()
|
||||||
|
@ -17,4 +17,10 @@ WHERE
|
|||||||
NOT (
|
NOT (
|
||||||
{{ CATALOGS.LIST('nsp') }}
|
{{ CATALOGS.LIST('nsp') }}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
{% if schema_restrictions %}
|
||||||
|
AND
|
||||||
|
nsp.nspname in ({{schema_restrictions}})
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
ORDER BY nspname;
|
ORDER BY nspname;
|
||||||
|
@ -50,4 +50,8 @@ WHERE
|
|||||||
NOT (
|
NOT (
|
||||||
{{ CATALOGS.LIST('nsp') }}
|
{{ CATALOGS.LIST('nsp') }}
|
||||||
)
|
)
|
||||||
|
{% if schema_restrictions %}
|
||||||
|
AND
|
||||||
|
nsp.nspname in ({{schema_restrictions}})
|
||||||
|
{% endif %}
|
||||||
ORDER BY 1, nspname;
|
ORDER BY 1, nspname;
|
||||||
|
@ -46,6 +46,7 @@ define('pgadmin.node.database', [
|
|||||||
node_image: function() {
|
node_image: function() {
|
||||||
return 'pg-icon-database';
|
return 'pg-icon-database';
|
||||||
},
|
},
|
||||||
|
width: '700px',
|
||||||
Init: function() {
|
Init: function() {
|
||||||
/* Avoid mulitple registration of menus */
|
/* Avoid mulitple registration of menus */
|
||||||
if (this.initialized)
|
if (this.initialized)
|
||||||
@ -297,6 +298,7 @@ define('pgadmin.node.database', [
|
|||||||
defseqacl: [],
|
defseqacl: [],
|
||||||
is_template: false,
|
is_template: false,
|
||||||
deftypeacl: [],
|
deftypeacl: [],
|
||||||
|
schema_res:'',
|
||||||
},
|
},
|
||||||
|
|
||||||
// Default values!
|
// Default values!
|
||||||
@ -310,150 +312,189 @@ define('pgadmin.node.database', [
|
|||||||
pgBrowser.Node.Model.prototype.initialize.apply(this, arguments);
|
pgBrowser.Node.Model.prototype.initialize.apply(this, arguments);
|
||||||
},
|
},
|
||||||
|
|
||||||
schema: [{
|
schema: [
|
||||||
id: 'name', label: gettext('Database'), cell: 'string',
|
{
|
||||||
editable: false, type: 'text',
|
id: 'name', label: gettext('Database'), cell: 'string',
|
||||||
},{
|
editable: false, type: 'text',
|
||||||
id: 'did', label: gettext('OID'), cell: 'string', mode: ['properties'],
|
},{
|
||||||
editable: false, type: 'text',
|
id: 'did', label: gettext('OID'), cell: 'string', mode: ['properties'],
|
||||||
},{
|
editable: false, type: 'text',
|
||||||
id: 'datowner', label: gettext('Owner'),
|
},{
|
||||||
editable: false, type: 'text', node: 'role',
|
id: 'datowner', label: gettext('Owner'),
|
||||||
control: Backform.NodeListByNameControl, select2: { allowClear: false },
|
editable: false, type: 'text', node: 'role',
|
||||||
},{
|
control: Backform.NodeListByNameControl, select2: { allowClear: false },
|
||||||
id: 'acl', label: gettext('Privileges'), type: 'text',
|
},{
|
||||||
group: gettext('Security'), mode: ['properties'],
|
id: 'acl', label: gettext('Privileges'), type: 'text',
|
||||||
},{
|
group: gettext('Security'), mode: ['properties'],
|
||||||
id: 'tblacl', label: gettext('Default TABLE privileges'), type: 'text',
|
},{
|
||||||
group: gettext('Security'), mode: ['properties'],
|
id: 'tblacl', label: gettext('Default TABLE privileges'), type: 'text',
|
||||||
},{
|
group: gettext('Security'), mode: ['properties'],
|
||||||
id: 'seqacl', label: gettext('Default SEQUENCE privileges'), type: 'text',
|
},{
|
||||||
group: gettext('Security'), mode: ['properties'],
|
id: 'seqacl', label: gettext('Default SEQUENCE privileges'), type: 'text',
|
||||||
},{
|
group: gettext('Security'), mode: ['properties'],
|
||||||
id: 'funcacl', label: gettext('Default FUNCTION privileges'), type: 'text',
|
},{
|
||||||
group: gettext('Security'), mode: ['properties'],
|
id: 'funcacl', label: gettext('Default FUNCTION privileges'), type: 'text',
|
||||||
},{
|
group: gettext('Security'), mode: ['properties'],
|
||||||
id: 'typeacl', label: gettext('Default TYPE privileges'), type: 'text',
|
},{
|
||||||
group: gettext('Security'), mode: ['properties'], min_version: 90200,
|
id: 'typeacl', label: gettext('Default TYPE privileges'), type: 'text',
|
||||||
},{
|
group: gettext('Security'), mode: ['properties'], min_version: 90200,
|
||||||
id: 'is_sys_obj', label: gettext('System database?'),
|
},{
|
||||||
cell:'boolean', type: 'switch', mode: ['properties'],
|
id: 'is_sys_obj', label: gettext('System database?'),
|
||||||
},{
|
cell:'boolean', type: 'switch', mode: ['properties'],
|
||||||
id: 'comments', label: gettext('Comment'),
|
},{
|
||||||
editable: false, type: 'multiline',
|
id: 'comments', label: gettext('Comment'),
|
||||||
},{
|
editable: false, type: 'multiline',
|
||||||
id: 'encoding', label: gettext('Encoding'),
|
},{
|
||||||
editable: false, type: 'text', group: gettext('Definition'),
|
id: 'encoding', label: gettext('Encoding'),
|
||||||
readonly: function(m) { return !m.isNew(); }, url: 'get_encodings',
|
editable: false, type: 'text', group: gettext('Definition'),
|
||||||
control: 'node-ajax-options', cache_level: 'server',
|
readonly: function(m) { return !m.isNew(); }, url: 'get_encodings',
|
||||||
},{
|
control: 'node-ajax-options', cache_level: 'server',
|
||||||
id: 'template', label: gettext('Template'),
|
},{
|
||||||
editable: false, type: 'text', group: gettext('Definition'),
|
id: 'template', label: gettext('Template'),
|
||||||
readonly: function(m) { return !m.isNew(); },
|
editable: false, type: 'text', group: gettext('Definition'),
|
||||||
control: 'node-list-by-name', url: 'get_databases', cache_level: 'server',
|
readonly: function(m) { return !m.isNew(); },
|
||||||
select2: { allowClear: false }, mode: ['create'],
|
control: 'node-list-by-name', url: 'get_databases', cache_level: 'server',
|
||||||
transform: function(data, cell) {
|
select2: { allowClear: false }, mode: ['create'],
|
||||||
var res = [],
|
transform: function(data, cell) {
|
||||||
control = cell || this,
|
var res = [],
|
||||||
label = control.model.get('name');
|
control = cell || this,
|
||||||
|
label = control.model.get('name');
|
||||||
|
|
||||||
if (!control.model.isNew()) {
|
if (!control.model.isNew()) {
|
||||||
res.push({label: label, value: label});
|
res.push({label: label, value: label});
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (data && _.isArray(data)) {
|
|
||||||
_.each(data, function(d) {
|
|
||||||
res.push({label: d, value: d,
|
|
||||||
image: 'pg-icon-database'});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
return res;
|
if (data && _.isArray(data)) {
|
||||||
},
|
_.each(data, function(d) {
|
||||||
},{
|
res.push({label: d, value: d,
|
||||||
id: 'spcname', label: gettext('Tablespace'),
|
image: 'pg-icon-database'});
|
||||||
editable: false, type: 'text', group: gettext('Definition'),
|
});
|
||||||
control: 'node-list-by-name', node: 'tablespace',
|
}
|
||||||
select2: { allowClear: false },
|
}
|
||||||
filter: function(m) {
|
return res;
|
||||||
return (m.label != 'pg_global');
|
},
|
||||||
},
|
|
||||||
},{
|
|
||||||
id: 'datcollate', label: gettext('Collation'),
|
|
||||||
editable: false, type: 'text', group: gettext('Definition'),
|
|
||||||
readonly: function(m) { return !m.isNew(); }, url: 'get_ctypes',
|
|
||||||
control: 'node-ajax-options', cache_level: 'server',
|
|
||||||
},{
|
|
||||||
id: 'datctype', label: gettext('Character type'),
|
|
||||||
editable: false, type: 'text', group: gettext('Definition'),
|
|
||||||
readonly: function(m) { return !m.isNew(); }, url: 'get_ctypes',
|
|
||||||
control: 'node-ajax-options', cache_level: 'server',
|
|
||||||
},{
|
|
||||||
id: 'datconnlimit', label: gettext('Connection limit'),
|
|
||||||
editable: false, type: 'int', group: gettext('Definition'), min: -1,
|
|
||||||
},{
|
|
||||||
id: 'is_template', label: gettext('Template?'),
|
|
||||||
editable: false, type: 'switch', group: gettext('Definition'),
|
|
||||||
readonly: true, mode: ['properties', 'edit'],
|
|
||||||
},{
|
|
||||||
id: 'datallowconn', label: gettext('Allow connections?'),
|
|
||||||
editable: false, type: 'switch', group: gettext('Definition'),
|
|
||||||
mode: ['properties'],
|
|
||||||
},{
|
|
||||||
id: 'datacl', label: gettext('Privileges'), type: 'collection',
|
|
||||||
model: pgBrowser.Node.PrivilegeRoleModel.extend({
|
|
||||||
privileges: ['C', 'T', 'c'],
|
|
||||||
}), uniqueCol : ['grantee', 'grantor'], editable: false,
|
|
||||||
group: gettext('Security'), mode: ['edit', 'create'],
|
|
||||||
canAdd: true, canDelete: true, control: 'unique-col-collection',
|
|
||||||
},{
|
|
||||||
id: 'variables', label: '', type: 'collection',
|
|
||||||
model: pgBrowser.Node.VariableModel.extend({keys:['name', 'role']}), editable: false,
|
|
||||||
group: gettext('Parameters'), mode: ['edit', 'create'],
|
|
||||||
canAdd: true, canEdit: false, canDelete: true, hasRole: true,
|
|
||||||
control: Backform.VariableCollectionControl, node: 'role',
|
|
||||||
},{
|
|
||||||
id: 'seclabels', label: gettext('Security labels'),
|
|
||||||
model: pgBrowser.SecLabelModel,
|
|
||||||
editable: false, type: 'collection', canEdit: false,
|
|
||||||
group: gettext('Security'), canDelete: true,
|
|
||||||
mode: ['edit', 'create'], canAdd: true,
|
|
||||||
control: 'unique-col-collection', uniqueCol : ['provider'],
|
|
||||||
min_version: 90200,
|
|
||||||
},{
|
|
||||||
type: 'nested', control: 'tab', group: gettext('Default Privileges'),
|
|
||||||
mode: ['edit'],
|
|
||||||
schema:[{
|
|
||||||
id: 'deftblacl', model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
|
||||||
{privileges: ['a', 'r', 'w', 'd', 'D', 'x', 't']}), label: '',
|
|
||||||
editable: false, type: 'collection', group: gettext('Tables'),
|
|
||||||
mode: ['edit', 'create'], control: 'unique-col-collection',
|
|
||||||
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
|
|
||||||
},{
|
},{
|
||||||
id: 'defseqacl', model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
id: 'spcname', label: gettext('Tablespace'),
|
||||||
{privileges: ['r', 'w', 'U']}), label: '',
|
editable: false, type: 'text', group: gettext('Definition'),
|
||||||
editable: false, type: 'collection', group: gettext('Sequences'),
|
control: 'node-list-by-name', node: 'tablespace',
|
||||||
mode: ['edit', 'create'], control: 'unique-col-collection',
|
select2: { allowClear: false },
|
||||||
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
|
filter: function(m) {
|
||||||
|
return (m.label != 'pg_global');
|
||||||
|
},
|
||||||
},{
|
},{
|
||||||
id: 'deffuncacl', model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
id: 'datcollate', label: gettext('Collation'),
|
||||||
{privileges: ['X']}), label: '',
|
editable: false, type: 'text', group: gettext('Definition'),
|
||||||
editable: false, type: 'collection', group: gettext('Functions'),
|
readonly: function(m) { return !m.isNew(); }, url: 'get_ctypes',
|
||||||
mode: ['edit', 'create'], control: 'unique-col-collection',
|
control: 'node-ajax-options', cache_level: 'server',
|
||||||
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
|
|
||||||
},{
|
},{
|
||||||
id: 'deftypeacl', model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
id: 'datctype', label: gettext('Character type'),
|
||||||
{privileges: ['U']}), label: '',
|
editable: false, type: 'text', group: gettext('Definition'),
|
||||||
editable: false, type: 'collection', group: 'deftypesacl_group',
|
readonly: function(m) { return !m.isNew(); }, url: 'get_ctypes',
|
||||||
mode: ['edit', 'create'], control: 'unique-col-collection',
|
control: 'node-ajax-options', cache_level: 'server',
|
||||||
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
|
},{
|
||||||
|
id: 'datconnlimit', label: gettext('Connection limit'),
|
||||||
|
editable: false, type: 'int', group: gettext('Definition'), min: -1,
|
||||||
|
},{
|
||||||
|
id: 'is_template', label: gettext('Template?'),
|
||||||
|
editable: false, type: 'switch', group: gettext('Definition'),
|
||||||
|
readonly: true, mode: ['properties', 'edit'],
|
||||||
|
},{
|
||||||
|
id: 'datallowconn', label: gettext('Allow connections?'),
|
||||||
|
editable: false, type: 'switch', group: gettext('Definition'),
|
||||||
|
mode: ['properties'],
|
||||||
|
},{
|
||||||
|
id: 'datacl', label: gettext('Privileges'), type: 'collection',
|
||||||
|
model: pgBrowser.Node.PrivilegeRoleModel.extend({
|
||||||
|
privileges: ['C', 'T', 'c'],
|
||||||
|
}), uniqueCol : ['grantee', 'grantor'], editable: false,
|
||||||
|
group: gettext('Security'), mode: ['edit', 'create'],
|
||||||
|
canAdd: true, canDelete: true, control: 'unique-col-collection',
|
||||||
|
},{
|
||||||
|
id: 'variables', label: '', type: 'collection',
|
||||||
|
model: pgBrowser.Node.VariableModel.extend({keys:['name', 'role']}), editable: false,
|
||||||
|
group: gettext('Parameters'), mode: ['edit', 'create'],
|
||||||
|
canAdd: true, canEdit: false, canDelete: true, hasRole: true,
|
||||||
|
control: Backform.VariableCollectionControl, node: 'role',
|
||||||
|
},{
|
||||||
|
id: 'seclabels', label: gettext('Security labels'),
|
||||||
|
model: pgBrowser.SecLabelModel,
|
||||||
|
editable: false, type: 'collection', canEdit: false,
|
||||||
|
group: gettext('Security'), canDelete: true,
|
||||||
|
mode: ['edit', 'create'], canAdd: true,
|
||||||
|
control: 'unique-col-collection', uniqueCol : ['provider'],
|
||||||
min_version: 90200,
|
min_version: 90200,
|
||||||
},{
|
},{
|
||||||
id: 'deftypesacl_group', type: 'group', label: gettext('Types'),
|
type: 'nested', control: 'tab', group: gettext('Default Privileges'),
|
||||||
mode: ['edit', 'create'], min_version: 90200,
|
mode: ['edit'],
|
||||||
|
schema:[{
|
||||||
|
id: 'deftblacl', model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
||||||
|
{privileges: ['a', 'r', 'w', 'd', 'D', 'x', 't']}), label: '',
|
||||||
|
editable: false, type: 'collection', group: gettext('Tables'),
|
||||||
|
mode: ['edit', 'create'], control: 'unique-col-collection',
|
||||||
|
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
|
||||||
|
},{
|
||||||
|
id: 'defseqacl', model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
||||||
|
{privileges: ['r', 'w', 'U']}), label: '',
|
||||||
|
editable: false, type: 'collection', group: gettext('Sequences'),
|
||||||
|
mode: ['edit', 'create'], control: 'unique-col-collection',
|
||||||
|
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
|
||||||
|
},{
|
||||||
|
id: 'deffuncacl', model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
||||||
|
{privileges: ['X']}), label: '',
|
||||||
|
editable: false, type: 'collection', group: gettext('Functions'),
|
||||||
|
mode: ['edit', 'create'], control: 'unique-col-collection',
|
||||||
|
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
|
||||||
|
},{
|
||||||
|
id: 'deftypeacl', model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
||||||
|
{privileges: ['U']}), label: '',
|
||||||
|
editable: false, type: 'collection', group: 'deftypesacl_group',
|
||||||
|
mode: ['edit', 'create'], control: 'unique-col-collection',
|
||||||
|
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
|
||||||
|
min_version: 90200,
|
||||||
|
},{
|
||||||
|
id: 'deftypesacl_group', type: 'group', label: gettext('Types'),
|
||||||
|
mode: ['edit', 'create'], min_version: 90200,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},{
|
||||||
|
type: 'collection', group: gettext('Advanced'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'schema_res', label: gettext('Schema restriction'),
|
||||||
|
type: 'select2', group: gettext('Advanced'),
|
||||||
|
mode: ['properties', 'edit', 'create'],
|
||||||
|
select2: {
|
||||||
|
multiple: true, allowClear: false, tags: true,
|
||||||
|
tokenSeparators: [','], first_empty: false,
|
||||||
|
selectOnClose: true, emptyOptions: true,
|
||||||
|
},
|
||||||
|
control: Backform.Select2Control.extend({
|
||||||
|
onChange: function() {
|
||||||
|
Backform.Select2Control.prototype.onChange.apply(this, arguments);
|
||||||
|
if (!this.model || !(
|
||||||
|
this.model.changed &&
|
||||||
|
this.model.get('oid') !== undefined
|
||||||
|
)) {
|
||||||
|
this.model.inform_text = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.model.origSessAttrs.schema_res != this.model.changed.schema_res)
|
||||||
|
{
|
||||||
|
this.model.inform_text = gettext(
|
||||||
|
'Please refresh the Schemas node to make changes to the schema restriction take effect.'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.model.inform_text = undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'note', label: gettext('Note: Changes to the schema restriction will require the Schemas node in the browser to be refreshed before they will be shown.'),
|
||||||
|
group: gettext('Advanced'), type: 'help',
|
||||||
|
mode: ['edit', 'create'],
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
validate: function() {
|
validate: function() {
|
||||||
var name = this.get('name');
|
var name = this.get('name');
|
||||||
|
@ -41,7 +41,8 @@ class DatabasesUpdateTestCase(BaseTestGenerator):
|
|||||||
try:
|
try:
|
||||||
data = {
|
data = {
|
||||||
"comments": "This is db update comment",
|
"comments": "This is db update comment",
|
||||||
"id": self.db_id
|
"id": self.db_id,
|
||||||
|
"schema_res": ["public"]
|
||||||
}
|
}
|
||||||
response = self.tester.put(
|
response = self.tester.put(
|
||||||
self.url + str(utils.SERVER_GROUP) + '/' + str(
|
self.url + str(utils.SERVER_GROUP) + '/' + str(
|
||||||
|
@ -73,7 +73,8 @@ def get_db_data(db_owner):
|
|||||||
"name": "db_add_%s" % str(uuid.uuid4())[1: 8],
|
"name": "db_add_%s" % str(uuid.uuid4())[1: 8],
|
||||||
"privileges": [],
|
"privileges": [],
|
||||||
"securities": [],
|
"securities": [],
|
||||||
"variables": []
|
"variables": [],
|
||||||
|
"schema_res": ["public", "sample"]
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -39,7 +39,6 @@ define('pgadmin.node.server', [
|
|||||||
}],
|
}],
|
||||||
validate: function() {
|
validate: function() {
|
||||||
this.errorModel.clear();
|
this.errorModel.clear();
|
||||||
|
|
||||||
if (_.isUndefined(this.get('label')) ||
|
if (_.isUndefined(this.get('label')) ||
|
||||||
_.isNull(this.get('label')) ||
|
_.isNull(this.get('label')) ||
|
||||||
String(this.get('label')).replace(/^\s+|\s+$/g, '') == '') {
|
String(this.get('label')).replace(/^\s+|\s+$/g, '') == '') {
|
||||||
@ -66,7 +65,6 @@ define('pgadmin.node.server', [
|
|||||||
return d && d.connected;
|
return d && d.connected;
|
||||||
},
|
},
|
||||||
Init: function() {
|
Init: function() {
|
||||||
|
|
||||||
/* Avoid multiple registration of same menus */
|
/* Avoid multiple registration of same menus */
|
||||||
if (this.initialized)
|
if (this.initialized)
|
||||||
return;
|
return;
|
||||||
@ -785,16 +783,70 @@ define('pgadmin.node.server', [
|
|||||||
mode: ['properties', 'edit', 'create'],
|
mode: ['properties', 'edit', 'create'],
|
||||||
},{
|
},{
|
||||||
id: 'host', label: gettext('Host name/address'), type: 'text', group: gettext('Connection'),
|
id: 'host', label: gettext('Host name/address'), type: 'text', group: gettext('Connection'),
|
||||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected',
|
mode: ['properties', 'edit', 'create'],
|
||||||
|
control: Backform.InputControl.extend({
|
||||||
|
onChange: function() {
|
||||||
|
Backform.InputControl.prototype.onChange.apply(this, arguments);
|
||||||
|
if (!this.model || !this.model.changed) {
|
||||||
|
this.model.inform_text = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.model.origSessAttrs.host != this.model.changed.host && !this.model.isNew() && this.model.get('connected'))
|
||||||
|
{
|
||||||
|
this.model.inform_text = gettext(
|
||||||
|
'To apply changes to the connection configuration, please disconnect from the server and then reconnect.'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.model.inform_text = undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
},{
|
},{
|
||||||
id: 'port', label: gettext('Port'), type: 'int', group: gettext('Connection'),
|
id: 'port', label: gettext('Port'), type: 'int', group: gettext('Connection'),
|
||||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected', min: 1, max: 65535,
|
mode: ['properties', 'edit', 'create'], min: 1, max: 65535,
|
||||||
|
control: Backform.InputControl.extend({
|
||||||
|
onChange: function() {
|
||||||
|
Backform.InputControl.prototype.onChange.apply(this, arguments);
|
||||||
|
if (!this.model || !this.model.changed) {
|
||||||
|
this.model.inform_text = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.model.origSessAttrs.port != this.model.changed.port && !this.model.isNew() && this.model.get('connected'))
|
||||||
|
{
|
||||||
|
this.model.inform_text = gettext(
|
||||||
|
'To apply changes to the connection configuration, please disconnect from the server and then reconnect.'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.model.inform_text = undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
},{
|
},{
|
||||||
id: 'db', label: gettext('Maintenance database'), type: 'text', group: gettext('Connection'),
|
id: 'db', label: gettext('Maintenance database'), type: 'text', group: gettext('Connection'),
|
||||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected',
|
mode: ['properties', 'edit', 'create'], readonly: 'isConnected',
|
||||||
},{
|
},{
|
||||||
id: 'username', label: gettext('Username'), type: 'text', group: gettext('Connection'),
|
id: 'username', label: gettext('Username'), type: 'text', group: gettext('Connection'),
|
||||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected',
|
mode: ['properties', 'edit', 'create'],
|
||||||
|
control: Backform.InputControl.extend({
|
||||||
|
onChange: function() {
|
||||||
|
Backform.InputControl.prototype.onChange.apply(this, arguments);
|
||||||
|
if (!this.model || !this.model.changed) {
|
||||||
|
this.model.inform_text = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.model.origSessAttrs.username != this.model.changed.username && !this.model.isNew() && this.model.get('connected'))
|
||||||
|
{
|
||||||
|
this.model.inform_text = gettext(
|
||||||
|
'To apply changes to the connection configuration, please disconnect from the server and then reconnect.'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.model.inform_text = undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
},{
|
},{
|
||||||
id: 'password', label: gettext('Password'), type: 'password', maxlength: '2000',
|
id: 'password', label: gettext('Password'), type: 'password', maxlength: '2000',
|
||||||
group: gettext('Connection'), control: 'input', mode: ['create'], deps: ['connect_now'],
|
group: gettext('Connection'), control: 'input', mode: ['create'], deps: ['connect_now'],
|
||||||
|
@ -1339,6 +1339,21 @@ define('pgadmin.browser.node', [
|
|||||||
}
|
}
|
||||||
}.bind(panel),
|
}.bind(panel),
|
||||||
|
|
||||||
|
informBeforeAttributeChange = function(ok_callback) {
|
||||||
|
var j = this.$container.find('.obj_properties').first();
|
||||||
|
view = j && j.data('obj-view');
|
||||||
|
|
||||||
|
if (view && view.model && !_.isUndefined(view.model.inform_text) && !_.isNull(view.model.inform_text)) {
|
||||||
|
Alertify.alert(
|
||||||
|
gettext('Warning'),
|
||||||
|
gettext(view.model.inform_text)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
ok_callback();
|
||||||
|
return true;
|
||||||
|
}.bind(panel),
|
||||||
|
|
||||||
onSave = function(view, saveBtn) {
|
onSave = function(view, saveBtn) {
|
||||||
var m = view.model,
|
var m = view.model,
|
||||||
d = m.toJSON(true),
|
d = m.toJSON(true),
|
||||||
@ -1535,9 +1550,11 @@ define('pgadmin.browser.node', [
|
|||||||
warnBeforeAttributeChange.call(
|
warnBeforeAttributeChange.call(
|
||||||
panel,
|
panel,
|
||||||
function() {
|
function() {
|
||||||
setTimeout(function() {
|
informBeforeAttributeChange.call(panel, function(){
|
||||||
onSave.call(this, view, btn);
|
setTimeout(function() {
|
||||||
}, 0);
|
onSave.call(this, view, btn);
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -290,3 +290,18 @@ class QueryHistoryModel(db.Model):
|
|||||||
dbname = db.Column(db.String(), nullable=False, primary_key=True)
|
dbname = db.Column(db.String(), nullable=False, primary_key=True)
|
||||||
query_info = db.Column(db.String(), nullable=False)
|
query_info = db.Column(db.String(), nullable=False)
|
||||||
last_updated_flag = db.Column(db.String(), nullable=False)
|
last_updated_flag = db.Column(db.String(), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class Database(db.Model):
|
||||||
|
"""
|
||||||
|
Define a Database.
|
||||||
|
"""
|
||||||
|
__tablename__ = 'database'
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
schema_res = db.Column(db.String(256), nullable=True)
|
||||||
|
server = db.Column(
|
||||||
|
db.Integer,
|
||||||
|
db.ForeignKey('server.id'),
|
||||||
|
nullable=False,
|
||||||
|
primary_key=True
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user