mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-01-23 15:03:26 -06:00
Added shared server support for admin users. Fixes #4979
This commit is contained in:
parent
3e35dc95e5
commit
b562ab7681
@ -11,6 +11,7 @@ New features
|
||||
|
||||
| `Issue #2042 <https://redmine.postgresql.org/issues/2042>`_ - Added SQL Formatter support in Query Tool.
|
||||
| `Issue #4059 <https://redmine.postgresql.org/issues/4059>`_ - Added a new button to the query tool toolbar to open a new query tool window.
|
||||
| `Issue #4979 <https://redmine.postgresql.org/issues/4979>`_ - Added shared server support for admin users.
|
||||
| `Issue #5772 <https://redmine.postgresql.org/issues/5772>`_ - Warn the user when connecting to a server that is older than pgAdmin supports.
|
||||
|
||||
Housekeeping
|
||||
|
72
web/migrations/versions/a091c9611d20_.py
Normal file
72
web/migrations/versions/a091c9611d20_.py
Normal file
@ -0,0 +1,72 @@
|
||||
|
||||
"""empty message
|
||||
|
||||
Revision ID: a091c9611d20
|
||||
Revises: 84700139beb0
|
||||
Create Date: 2020-07-14 17:20:22.705737
|
||||
|
||||
"""
|
||||
from pgadmin.model import db
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'a091c9611d20'
|
||||
down_revision = '84700139beb0'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
db.engine.execute(
|
||||
'ALTER TABLE server ADD COLUMN shared BOOLEAN'
|
||||
)
|
||||
|
||||
db.engine.execute("""
|
||||
CREATE TABLE sharedserver (
|
||||
id INTEGER NOT NULL,
|
||||
user_id INTEGER NOT NULL,
|
||||
server_owner VARCHAR(64),
|
||||
servergroup_id INTEGER NOT NULL,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
host VARCHAR(128),
|
||||
port INTEGER NOT NULL CHECK(port >= 1 AND port <= 65534),
|
||||
maintenance_db VARCHAR(64),
|
||||
username VARCHAR(64),
|
||||
password VARCHAR(64),
|
||||
role VARCHAR(64),
|
||||
ssl_mode VARCHAR(16) NOT NULL CHECK(ssl_mode IN
|
||||
( 'allow' , 'prefer' , 'require' , 'disable' ,
|
||||
'verify-ca' , 'verify-full' )
|
||||
),
|
||||
comment VARCHAR(1024),
|
||||
discovery_id VARCHAR(128),
|
||||
hostaddr TEXT(1024),
|
||||
db_res TEXT,
|
||||
passfile TEXT,
|
||||
sslcert TEXT,
|
||||
sslkey TEXT,
|
||||
sslrootcert TEXT,
|
||||
sslcrl TEXT,
|
||||
sslcompression INTEGER DEFAULT 0,
|
||||
bgcolor TEXT(10),
|
||||
fgcolor TEXT(10),
|
||||
service TEXT,
|
||||
use_ssh_tunnel INTEGER DEFAULT 0,
|
||||
tunnel_host TEXT,
|
||||
tunnel_port TEXT,
|
||||
tunnel_username TEXT,
|
||||
tunnel_authentication INTEGER DEFAULT 0,
|
||||
tunnel_identity_file TEXT,
|
||||
shared BOOLEAN NOT NULL,
|
||||
save_password BOOLEAN NOT NULL,
|
||||
tunnel_password VARCHAR(64),
|
||||
connect_timeout INTEGER ,
|
||||
PRIMARY KEY(id),
|
||||
FOREIGN KEY(user_id) REFERENCES user(id),
|
||||
FOREIGN KEY(servergroup_id) REFERENCES servergroup(id)
|
||||
);
|
||||
""")
|
||||
|
||||
|
||||
def downgrade():
|
||||
pass
|
@ -28,7 +28,7 @@ from werkzeug.datastructures import ImmutableDict
|
||||
from werkzeug.local import LocalProxy
|
||||
from werkzeug.utils import find_modules
|
||||
|
||||
from pgadmin.model import db, Role, Server, ServerGroup, \
|
||||
from pgadmin.model import db, Role, Server, SharedServer, ServerGroup, \
|
||||
User, Keys, Version, SCHEMA_VERSION as CURRENT_SCHEMA_VERSION
|
||||
from pgadmin.utils import PgAdminModule, driver, KeyManager
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
|
@ -9,6 +9,7 @@
|
||||
from flask_babelex import gettext
|
||||
from pgadmin.utils.constants import PREF_LABEL_DISPLAY,\
|
||||
PREF_LABEL_KEYBOARD_SHORTCUTS
|
||||
import config
|
||||
|
||||
LOCK_LAYOUT_LEVEL = {
|
||||
'PREVENT_DOCKING': 'docking',
|
||||
@ -23,6 +24,15 @@ def register_browser_preferences(self):
|
||||
gettext("Show system objects?"), 'boolean', False,
|
||||
category_label=PREF_LABEL_DISPLAY
|
||||
)
|
||||
if config.SERVER_MODE:
|
||||
self.hide_shared_server = self.preference.register(
|
||||
'display', 'hide_shared_server',
|
||||
gettext("Hide shared server?"), 'boolean', False,
|
||||
category_label=gettext('Display'),
|
||||
help_str=gettext(
|
||||
'If set to true, then all shared server will be hidden'
|
||||
)
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'display', 'enable_acitree_animation',
|
||||
|
@ -13,7 +13,7 @@ import simplejson as json
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
import six
|
||||
from flask import request, jsonify
|
||||
from flask import request, jsonify, render_template
|
||||
from flask_babelex import gettext
|
||||
from flask_security import current_user, login_required
|
||||
from pgadmin.browser import BrowserPluginModule
|
||||
@ -22,7 +22,27 @@ from pgadmin.utils.ajax import make_json_response, gone, \
|
||||
make_response as ajax_response, bad_request
|
||||
from pgadmin.utils.menu import MenuItem
|
||||
from sqlalchemy import exc
|
||||
from pgadmin.model import db, ServerGroup
|
||||
from pgadmin.model import db, ServerGroup, Server
|
||||
import config
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
|
||||
|
||||
def get_icon_css_class(group_id, group_user_id,
|
||||
default_val='icon-server_group'):
|
||||
"""
|
||||
Returns css value
|
||||
:param group_id:
|
||||
:param group_user_id:
|
||||
:param default_val:
|
||||
:return: default_val
|
||||
"""
|
||||
if (config.SERVER_MODE and
|
||||
group_user_id != current_user.id and
|
||||
ServerGroupModule.has_shared_server(group_id)):
|
||||
default_val = 'icon-server_group_shared'
|
||||
|
||||
return default_val
|
||||
|
||||
|
||||
SG_NOT_FOUND_ERROR = 'The specified server group could not be found.'
|
||||
|
||||
@ -31,19 +51,50 @@ class ServerGroupModule(BrowserPluginModule):
|
||||
_NODE_TYPE = "server_group"
|
||||
node_icon = "icon-%s" % _NODE_TYPE
|
||||
|
||||
@property
|
||||
def csssnippets(self):
|
||||
"""
|
||||
Returns a snippet of css to include in the page
|
||||
"""
|
||||
snippets = [render_template("css/server_group.css")]
|
||||
|
||||
for submodule in self.submodules:
|
||||
snippets.extend(submodule.csssnippets)
|
||||
|
||||
return snippets
|
||||
|
||||
@staticmethod
|
||||
def has_shared_server(gid):
|
||||
"""
|
||||
To check whether given server group contains shared server or not
|
||||
:param gid:
|
||||
:return: True if servergroup contains shared server else false
|
||||
"""
|
||||
servers = Server.query.filter_by(servergroup_id=gid)
|
||||
for s in servers:
|
||||
if s.shared:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_nodes(self, *arg, **kwargs):
|
||||
"""Return a JSON document listing the server groups for the user"""
|
||||
groups = ServerGroup.query.filter_by(
|
||||
user_id=current_user.id
|
||||
).order_by("id")
|
||||
|
||||
if config.SERVER_MODE:
|
||||
groups = ServerGroupView.get_all_server_groups()
|
||||
else:
|
||||
groups = ServerGroup.query.filter_by(
|
||||
user_id=current_user.id
|
||||
).order_by("id")
|
||||
|
||||
for idx, group in enumerate(groups):
|
||||
yield self.generate_browser_node(
|
||||
"%d" % (group.id), None,
|
||||
group.name,
|
||||
self.node_icon,
|
||||
get_icon_css_class(group.id, group.user_id),
|
||||
True,
|
||||
self.node_type,
|
||||
can_delete=True if idx > 0 else False
|
||||
can_delete=True if idx > 0 else False,
|
||||
user_id=group.user_id
|
||||
)
|
||||
|
||||
@property
|
||||
@ -196,7 +247,7 @@ class ServerGroupView(NodeView):
|
||||
gid,
|
||||
None,
|
||||
servergroup.name,
|
||||
self.node_icon,
|
||||
get_icon_css_class(gid, servergroup.user_id),
|
||||
True,
|
||||
self.node_type,
|
||||
can_delete=True # This is user created hence can deleted
|
||||
@ -207,10 +258,7 @@ class ServerGroupView(NodeView):
|
||||
def properties(self, gid):
|
||||
"""Update the server-group properties"""
|
||||
|
||||
# There can be only one record at most
|
||||
sg = ServerGroup.query.filter_by(
|
||||
user_id=current_user.id,
|
||||
id=gid).first()
|
||||
sg = ServerGroup.query.filter(ServerGroup.id == gid).first()
|
||||
|
||||
if sg is None:
|
||||
return make_json_response(
|
||||
@ -220,7 +268,7 @@ class ServerGroupView(NodeView):
|
||||
)
|
||||
else:
|
||||
return ajax_response(
|
||||
response={'id': sg.id, 'name': sg.name},
|
||||
response={'id': sg.id, 'name': sg.name, 'user_id': sg.user_id},
|
||||
status=200
|
||||
)
|
||||
|
||||
@ -246,7 +294,7 @@ class ServerGroupView(NodeView):
|
||||
"%d" % sg.id,
|
||||
None,
|
||||
sg.name,
|
||||
self.node_icon,
|
||||
get_icon_css_class(sg.id, sg.user_id),
|
||||
True,
|
||||
self.node_type,
|
||||
# This is user created hence can deleted
|
||||
@ -292,13 +340,41 @@ class ServerGroupView(NodeView):
|
||||
def dependents(self, gid):
|
||||
return make_json_response(status=422)
|
||||
|
||||
@staticmethod
|
||||
def get_all_server_groups():
|
||||
"""
|
||||
Returns the list of server groups to show in server mode and
|
||||
if there is any shared server in the group.
|
||||
:return: server groups
|
||||
"""
|
||||
|
||||
# Don't display shared server if user has
|
||||
# selected 'Hide shared server'
|
||||
pref = Preferences.module('browser')
|
||||
hide_shared_server = pref.preference('hide_shared_server').get()
|
||||
|
||||
server_groups = ServerGroup.query.all()
|
||||
groups = []
|
||||
for group in server_groups:
|
||||
if hide_shared_server and \
|
||||
ServerGroupModule.has_shared_server(group.id) and \
|
||||
group.user_id != current_user.id:
|
||||
continue
|
||||
if group.user_id == current_user.id or \
|
||||
ServerGroupModule.has_shared_server(group.id):
|
||||
groups.append(group)
|
||||
return groups
|
||||
|
||||
@login_required
|
||||
def nodes(self, gid=None):
|
||||
"""Return a JSON document listing the server groups for the user"""
|
||||
nodes = []
|
||||
|
||||
if gid is None:
|
||||
groups = ServerGroup.query.filter_by(user_id=current_user.id)
|
||||
if config.SERVER_MODE:
|
||||
|
||||
groups = self.get_all_server_groups()
|
||||
else:
|
||||
groups = ServerGroup.query.filter_by(user_id=current_user.id)
|
||||
|
||||
for group in groups:
|
||||
nodes.append(
|
||||
@ -306,14 +382,14 @@ class ServerGroupView(NodeView):
|
||||
"%d" % group.id,
|
||||
None,
|
||||
group.name,
|
||||
self.node_icon,
|
||||
get_icon_css_class(group.id, group.user_id),
|
||||
True,
|
||||
self.node_type
|
||||
)
|
||||
)
|
||||
else:
|
||||
group = ServerGroup.query.filter_by(user_id=current_user.id,
|
||||
id=gid).first()
|
||||
group = ServerGroup.query.filter(ServerGroup.id == gid).first()
|
||||
|
||||
if not group:
|
||||
return gone(
|
||||
errormsg=gettext("Could not find the server group.")
|
||||
@ -322,7 +398,7 @@ class ServerGroupView(NodeView):
|
||||
nodes = self.blueprint.generate_browser_node(
|
||||
"%d" % (group.id), None,
|
||||
group.name,
|
||||
self.node_icon,
|
||||
get_icon_css_class(group.id, group.user_id),
|
||||
True,
|
||||
self.node_type
|
||||
)
|
||||
|
@ -23,7 +23,7 @@ from pgadmin.tools.sqleditor.utils.query_history import QueryHistory
|
||||
|
||||
import config
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
from pgadmin.model import db, Server, ServerGroup, User
|
||||
from pgadmin.model import db, Server, ServerGroup, User, SharedServer
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from pgadmin.utils.master_password import get_crypt_key
|
||||
from pgadmin.utils.exception import CryptKeyMissing
|
||||
@ -32,6 +32,8 @@ from psycopg2 import Error as psycopg2_Error, OperationalError
|
||||
from pgadmin.browser.server_groups.servers.utils import is_valid_ipaddress
|
||||
from pgadmin.utils.constants import UNAUTH_REQ, MIMETYPE_APP_JS, \
|
||||
SERVER_CONNECTION_CLOSED
|
||||
from sqlalchemy import or_
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
|
||||
|
||||
def has_any(data, keys):
|
||||
@ -65,6 +67,19 @@ def recovery_state(connection, postgres_version):
|
||||
return status, result, in_recovery, wal_paused
|
||||
|
||||
|
||||
def get_preferences():
|
||||
"""
|
||||
Get preferences setting
|
||||
:return: whether to hide shared server or not.
|
||||
"""
|
||||
hide_shared_server = None
|
||||
if config.SERVER_MODE:
|
||||
pref = Preferences.module('browser')
|
||||
hide_shared_server = pref.preference('hide_shared_server').get()
|
||||
|
||||
return hide_shared_server
|
||||
|
||||
|
||||
def server_icon_and_background(is_connected, manager, server):
|
||||
"""
|
||||
|
||||
@ -92,6 +107,10 @@ def server_icon_and_background(is_connected, manager, server):
|
||||
return 'icon-{0}{1}'.format(
|
||||
manager.server_type, server_background_color
|
||||
)
|
||||
elif server.shared and config.SERVER_MODE:
|
||||
return 'icon-shared-server-not-connected{0}'.format(
|
||||
server_background_color
|
||||
)
|
||||
else:
|
||||
return 'icon-server-not-connected{0}'.format(
|
||||
server_background_color
|
||||
@ -114,25 +133,93 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
"""
|
||||
return sg.ServerGroupModule.node_type
|
||||
|
||||
@staticmethod
|
||||
def get_shared_server_properties(server, sharedserver):
|
||||
"""
|
||||
Return shared server properties
|
||||
:param server:
|
||||
:param sharedserver:
|
||||
:return:
|
||||
"""
|
||||
|
||||
server.bgcolor = sharedserver.bgcolor
|
||||
server.fgcolor = sharedserver.fgcolor
|
||||
server.name = sharedserver.name
|
||||
server.role = sharedserver.role
|
||||
server.tunnel_username = sharedserver.tunnel_username
|
||||
server.tunnel_password = sharedserver.tunnel_password
|
||||
server.save_password = sharedserver.save_password
|
||||
server.passfile = sharedserver.passfile
|
||||
server.servergroup_id = sharedserver.servergroup_id
|
||||
server.sslcert = sharedserver.sslcert
|
||||
server.username = sharedserver.username
|
||||
server.server_owner = sharedserver.server_owner
|
||||
|
||||
return server
|
||||
|
||||
@staticmethod
|
||||
def check_to_hide_shared_server(hide_shared_server, shared_server,
|
||||
auto_detected_server):
|
||||
|
||||
hide_server = False
|
||||
if hide_shared_server or \
|
||||
shared_server.name == auto_detected_server:
|
||||
hide_server = True
|
||||
|
||||
return hide_server
|
||||
|
||||
@login_required
|
||||
def get_nodes(self, gid):
|
||||
"""Return a JSON document listing the server groups for the user"""
|
||||
servers = Server.query.filter_by(user_id=current_user.id,
|
||||
servergroup_id=gid)
|
||||
|
||||
hide_shared_server = get_preferences()
|
||||
|
||||
servers = Server.query.filter(
|
||||
or_(Server.user_id == current_user.id, Server.shared),
|
||||
Server.servergroup_id == gid)
|
||||
|
||||
driver = get_driver(PG_DEFAULT_DRIVER)
|
||||
|
||||
for server in servers:
|
||||
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
|
||||
shared_server, auto_detected_server = \
|
||||
self.get_shared_server(server, gid)
|
||||
|
||||
if self.check_to_hide_shared_server(hide_shared_server,
|
||||
shared_server,
|
||||
auto_detected_server):
|
||||
# Don't include shared server if hide shared server is
|
||||
# set to true
|
||||
continue
|
||||
|
||||
# if hide_shared_server or \
|
||||
# shared_server.name == auto_detected_server:
|
||||
# # Don't include shared server if hide shared server is
|
||||
# # set to true
|
||||
# continue
|
||||
|
||||
# if shared_server.name == auto_detected_server:
|
||||
# continue
|
||||
server = self.get_shared_server_properties(server,
|
||||
shared_server)
|
||||
connected = False
|
||||
manager = None
|
||||
errmsg = None
|
||||
was_connected = False
|
||||
in_recovery = None
|
||||
wal_paused = None
|
||||
server_type = 'pg'
|
||||
user_info = None
|
||||
try:
|
||||
manager = driver.connection_manager(server.id)
|
||||
conn = manager.connection()
|
||||
was_connected = conn.wasConnected
|
||||
connected = conn.connected()
|
||||
if connected:
|
||||
server_type = manager.server_type
|
||||
user_info = manager.user_info
|
||||
except CryptKeyMissing:
|
||||
# show the nodes at least even if not able to connect.
|
||||
pass
|
||||
@ -148,17 +235,20 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
True,
|
||||
self.node_type,
|
||||
connected=connected,
|
||||
server_type=manager.server_type if connected else "pg",
|
||||
server_type=server_type,
|
||||
version=manager.version,
|
||||
db=manager.db,
|
||||
user=manager.user_info if connected else None,
|
||||
user=user_info,
|
||||
in_recovery=in_recovery,
|
||||
wal_pause=wal_paused,
|
||||
is_password_saved=bool(server.save_password),
|
||||
is_tunnel_password_saved=True
|
||||
if server.tunnel_password is not None else False,
|
||||
was_connected=was_connected,
|
||||
errmsg=errmsg
|
||||
errmsg=errmsg,
|
||||
user_id=server.user_id,
|
||||
user_name=server.username,
|
||||
shared=server.shared
|
||||
)
|
||||
|
||||
@property
|
||||
@ -230,6 +320,82 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
def get_exposed_url_endpoints(self):
|
||||
return ['NODE-server.connect_id']
|
||||
|
||||
@staticmethod
|
||||
def create_shared_server(data, gid):
|
||||
"""
|
||||
Create shared server
|
||||
:param data:
|
||||
:param gid:
|
||||
:return: None
|
||||
"""
|
||||
|
||||
shared_server = None
|
||||
try:
|
||||
user = User.query.filter_by(id=data.user_id).first()
|
||||
shared_server = SharedServer(
|
||||
user_id=current_user.id,
|
||||
server_owner=user.username,
|
||||
servergroup_id=gid,
|
||||
name=data.name,
|
||||
host=data.host,
|
||||
hostaddr=data.hostaddr,
|
||||
port=data.port,
|
||||
maintenance_db=None,
|
||||
username=None,
|
||||
save_password=0,
|
||||
ssl_mode=data.ssl_mode,
|
||||
comment=None,
|
||||
role=data.role,
|
||||
sslcert=None,
|
||||
sslkey=None,
|
||||
sslrootcert=None,
|
||||
sslcrl=None,
|
||||
bgcolor=data.bgcolor if data.bgcolor else None,
|
||||
fgcolor=data.fgcolor if data.fgcolor else None,
|
||||
service=data.service if data.service else None,
|
||||
connect_timeout=0,
|
||||
use_ssh_tunnel=0,
|
||||
tunnel_host=None,
|
||||
tunnel_port=22,
|
||||
tunnel_username=None,
|
||||
tunnel_authentication=0,
|
||||
tunnel_identity_file=None,
|
||||
shared=data.shared if data.shared else None
|
||||
)
|
||||
db.session.add(shared_server)
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
if shared_server:
|
||||
db.session.delete(shared_server)
|
||||
db.session.commit()
|
||||
|
||||
current_app.logger.exception(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
@staticmethod
|
||||
def get_shared_server(server, gid):
|
||||
"""
|
||||
return the shared server
|
||||
:param server:
|
||||
:param gid:
|
||||
:return: shared_server
|
||||
"""
|
||||
auto_detected_server = None
|
||||
shared_server = SharedServer.query.filter_by(
|
||||
name=server.name, user_id=current_user.id,
|
||||
servergroup_id=gid).first()
|
||||
if server.discovery_id:
|
||||
auto_detected_server = server.name
|
||||
|
||||
if shared_server is None:
|
||||
ServerModule.create_shared_server(server, gid)
|
||||
|
||||
shared_server = SharedServer.query.filter_by(
|
||||
name=server.name, user_id=current_user.id,
|
||||
servergroup_id=gid).first()
|
||||
|
||||
return shared_server, auto_detected_server
|
||||
|
||||
|
||||
class ServerMenuItem(MenuItem):
|
||||
def __init__(self, **kwargs):
|
||||
@ -327,19 +493,29 @@ class ServerNode(PGChildNodeView):
|
||||
Return a JSON document listing the servers under this server group
|
||||
for the user.
|
||||
"""
|
||||
servers = Server.query.filter_by(user_id=current_user.id,
|
||||
servergroup_id=gid)
|
||||
servers = Server.query.filter(
|
||||
or_(Server.user_id == current_user.id,
|
||||
Server.shared),
|
||||
Server.servergroup_id == gid)
|
||||
|
||||
driver = get_driver(PG_DEFAULT_DRIVER)
|
||||
|
||||
for server in servers:
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
shared_server, auto_detected_server = \
|
||||
ServerModule.get_shared_server(server, gid)
|
||||
server = \
|
||||
ServerModule.get_shared_server_properties(server,
|
||||
shared_server)
|
||||
manager = driver.connection_manager(server.id)
|
||||
conn = manager.connection()
|
||||
connected = conn.connected()
|
||||
errmsg = None
|
||||
in_recovery = None
|
||||
wal_paused = None
|
||||
server_type = 'pg'
|
||||
if connected:
|
||||
server_type = manager.server_type
|
||||
status, result, in_recovery, wal_paused =\
|
||||
recovery_state(conn, manager.version)
|
||||
if not status:
|
||||
@ -356,7 +532,7 @@ class ServerNode(PGChildNodeView):
|
||||
True,
|
||||
self.node_type,
|
||||
connected=connected,
|
||||
server_type=manager.server_type if connected else 'pg',
|
||||
server_type=server_type,
|
||||
version=manager.version,
|
||||
db=manager.db,
|
||||
user=manager.user_info if connected else None,
|
||||
@ -365,7 +541,9 @@ class ServerNode(PGChildNodeView):
|
||||
is_password_saved=bool(server.save_password),
|
||||
is_tunnel_password_saved=True
|
||||
if server.tunnel_password is not None else False,
|
||||
errmsg=errmsg
|
||||
errmsg=errmsg,
|
||||
user_name=server.username,
|
||||
shared=server.shared
|
||||
)
|
||||
)
|
||||
|
||||
@ -379,9 +557,13 @@ class ServerNode(PGChildNodeView):
|
||||
@login_required
|
||||
def node(self, gid, sid):
|
||||
"""Return a JSON document listing the server groups for the user"""
|
||||
server = Server.query.filter_by(user_id=current_user.id,
|
||||
servergroup_id=gid,
|
||||
id=sid).first()
|
||||
server = Server.query.filter_by(id=sid).first()
|
||||
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
shared_server, auto_detected_server = \
|
||||
ServerModule.get_shared_server(server, gid)
|
||||
server = ServerModule.get_shared_server_properties(server,
|
||||
shared_server)
|
||||
|
||||
if server is None:
|
||||
return make_json_response(
|
||||
@ -426,14 +608,37 @@ class ServerNode(PGChildNodeView):
|
||||
is_password_saved=bool(server.save_password),
|
||||
is_tunnel_password_saved=True
|
||||
if server.tunnel_password is not None else False,
|
||||
errmsg=errmsg
|
||||
errmsg=errmsg,
|
||||
shared=server.shared,
|
||||
user_name=server.username
|
||||
),
|
||||
)
|
||||
|
||||
def delete_shared_server(self, server_name, gid):
|
||||
"""
|
||||
Delete the shared server
|
||||
:param server_name:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
shared_server = SharedServer.query.filter_by(name=server_name,
|
||||
servergroup_id=gid)
|
||||
for s in shared_server:
|
||||
get_driver(PG_DEFAULT_DRIVER).delete_manager(s.id)
|
||||
db.session.delete(s)
|
||||
db.session.commit()
|
||||
|
||||
except Exception as e:
|
||||
current_app.logger.exception(e)
|
||||
return make_json_response(
|
||||
success=0,
|
||||
errormsg=e.message)
|
||||
|
||||
@login_required
|
||||
def delete(self, gid, sid):
|
||||
"""Delete a server node in the settings database."""
|
||||
servers = Server.query.filter_by(user_id=current_user.id, id=sid)
|
||||
server_name = None
|
||||
|
||||
# TODO:: A server, which is connected, cannot be deleted
|
||||
if servers is None:
|
||||
@ -449,10 +654,11 @@ class ServerNode(PGChildNodeView):
|
||||
else:
|
||||
try:
|
||||
for s in servers:
|
||||
server_name = s.name
|
||||
get_driver(PG_DEFAULT_DRIVER).delete_manager(s.id)
|
||||
db.session.delete(s)
|
||||
db.session.commit()
|
||||
|
||||
self.delete_shared_server(server_name, gid)
|
||||
QueryHistory.clear_history(current_user.id, sid)
|
||||
|
||||
except Exception as e:
|
||||
@ -467,8 +673,8 @@ class ServerNode(PGChildNodeView):
|
||||
@login_required
|
||||
def update(self, gid, sid):
|
||||
"""Update the server settings"""
|
||||
server = Server.query.filter_by(
|
||||
user_id=current_user.id, id=sid).first()
|
||||
server = Server.query.filter_by(id=sid).first()
|
||||
sharedserver = None
|
||||
|
||||
if server is None:
|
||||
return make_json_response(
|
||||
@ -477,6 +683,11 @@ class ServerNode(PGChildNodeView):
|
||||
errormsg=gettext("Could not find the required server.")
|
||||
)
|
||||
|
||||
if config.SERVER_MODE and server.shared and \
|
||||
server.user_id != current_user.id:
|
||||
sharedserver, auto_detected_server = \
|
||||
ServerModule.get_shared_server(server, gid)
|
||||
|
||||
# Not all parameters can be modified, while the server is connected
|
||||
config_param_map = {
|
||||
'name': 'name',
|
||||
@ -506,11 +717,12 @@ class ServerNode(PGChildNodeView):
|
||||
'tunnel_username': 'tunnel_username',
|
||||
'tunnel_authentication': 'tunnel_authentication',
|
||||
'tunnel_identity_file': 'tunnel_identity_file',
|
||||
'shared': 'shared'
|
||||
}
|
||||
|
||||
disp_lbl = {
|
||||
'name': gettext('name'),
|
||||
'host': gettext('Host name/address'),
|
||||
'hostaddr': gettext('Host name/address'),
|
||||
'port': gettext('Port'),
|
||||
'db': gettext('Maintenance database'),
|
||||
'username': gettext('Username'),
|
||||
@ -541,7 +753,8 @@ class ServerNode(PGChildNodeView):
|
||||
self._server_modify_disallowed_when_connected(
|
||||
connected, data, disp_lbl)
|
||||
|
||||
idx = self._set_valid_attr_value(data, config_param_map, server)
|
||||
idx = self._set_valid_attr_value(gid, data, config_param_map, server,
|
||||
sharedserver)
|
||||
|
||||
if idx == 0:
|
||||
return make_json_response(
|
||||
@ -568,7 +781,11 @@ class ServerNode(PGChildNodeView):
|
||||
node=self.blueprint.generate_browser_node(
|
||||
"%d" % (server.id), server.servergroup_id,
|
||||
server.name,
|
||||
server_icon_and_background(connected, manager, server),
|
||||
server_icon_and_background(
|
||||
connected, manager, sharedserver)
|
||||
if server.shared and server.user_id != current_user.id
|
||||
else server_icon_and_background(
|
||||
connected, manager, server),
|
||||
True,
|
||||
self.node_type,
|
||||
connected=connected,
|
||||
@ -577,7 +794,16 @@ class ServerNode(PGChildNodeView):
|
||||
)
|
||||
)
|
||||
|
||||
def _set_valid_attr_value(self, data, config_param_map, server):
|
||||
@staticmethod
|
||||
def _update_server_details(server, sharedserver,
|
||||
config_param_map, arg, value):
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
setattr(sharedserver, config_param_map[arg], value)
|
||||
else:
|
||||
setattr(server, config_param_map[arg], value)
|
||||
|
||||
def _set_valid_attr_value(self, gid, data, config_param_map, server,
|
||||
sharedserver):
|
||||
|
||||
idx = 0
|
||||
for arg in config_param_map:
|
||||
@ -585,9 +811,14 @@ class ServerNode(PGChildNodeView):
|
||||
value = data[arg]
|
||||
# sqlite3 do not have boolean type so we need to convert
|
||||
# it manually to integer
|
||||
if 'shared' in data and not data['shared']:
|
||||
# Delete the shared server from DB if server
|
||||
# owner uncheck shared property
|
||||
self.delete_shared_server(server.name, gid)
|
||||
if arg == 'sslcompression':
|
||||
value = 1 if value else 0
|
||||
setattr(server, config_param_map[arg], value)
|
||||
self._update_server_details(server, sharedserver,
|
||||
config_param_map, arg, value)
|
||||
idx += 1
|
||||
|
||||
return idx
|
||||
@ -613,11 +844,11 @@ class ServerNode(PGChildNodeView):
|
||||
"""
|
||||
Return list of attributes of all servers.
|
||||
"""
|
||||
servers = Server.query.filter_by(
|
||||
user_id=current_user.id,
|
||||
servergroup_id=gid).order_by(Server.name)
|
||||
servers = Server.query.filter(
|
||||
or_(Server.user_id == current_user.id,
|
||||
Server.shared),
|
||||
Server.servergroup_id == gid).order_by(Server.name)
|
||||
sg = ServerGroup.query.filter_by(
|
||||
user_id=current_user.id,
|
||||
id=gid
|
||||
).first()
|
||||
res = []
|
||||
@ -625,6 +856,12 @@ class ServerNode(PGChildNodeView):
|
||||
driver = get_driver(PG_DEFAULT_DRIVER)
|
||||
|
||||
for server in servers:
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
shared_server, auto_detected_server = \
|
||||
ServerModule.get_shared_server(server, gid)
|
||||
server = \
|
||||
ServerModule.get_shared_server_properties(server,
|
||||
shared_server)
|
||||
manager = driver.connection_manager(server.id)
|
||||
conn = manager.connection()
|
||||
connected = conn.connected()
|
||||
@ -653,8 +890,12 @@ class ServerNode(PGChildNodeView):
|
||||
@login_required
|
||||
def properties(self, gid, sid):
|
||||
"""Return list of attributes of a server"""
|
||||
|
||||
sslcert = None
|
||||
sslkey = None
|
||||
sslrootcert = None
|
||||
sslcrl = None
|
||||
server = Server.query.filter_by(
|
||||
user_id=current_user.id,
|
||||
id=sid).first()
|
||||
|
||||
if server is None:
|
||||
@ -663,9 +904,8 @@ class ServerNode(PGChildNodeView):
|
||||
success=0,
|
||||
errormsg=self.not_found_error_msg()
|
||||
)
|
||||
|
||||
server_owner = None
|
||||
sg = ServerGroup.query.filter_by(
|
||||
user_id=current_user.id,
|
||||
id=server.servergroup_id
|
||||
).first()
|
||||
|
||||
@ -675,52 +915,77 @@ class ServerNode(PGChildNodeView):
|
||||
conn = manager.connection()
|
||||
connected = conn.connected()
|
||||
|
||||
# if server.shared and not current_user.has_role("Administrator"):
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
shared_server, auto_detected_server = \
|
||||
ServerModule.get_shared_server(server, gid)
|
||||
server = ServerModule.get_shared_server_properties(server,
|
||||
shared_server)
|
||||
server_owner = server.server_owner
|
||||
|
||||
is_ssl = True if server.ssl_mode in self.SSL_MODES else False
|
||||
|
||||
return ajax_response(
|
||||
response={
|
||||
'id': server.id,
|
||||
'name': server.name,
|
||||
'host': server.host,
|
||||
'hostaddr': server.hostaddr,
|
||||
'port': server.port,
|
||||
'db': server.maintenance_db,
|
||||
'username': server.username,
|
||||
'gid': str(server.servergroup_id),
|
||||
'group-name': sg.name,
|
||||
'comment': server.comment,
|
||||
'role': server.role,
|
||||
'connected': connected,
|
||||
'version': manager.ver,
|
||||
'sslmode': server.ssl_mode,
|
||||
'server_type': manager.server_type if connected else 'pg',
|
||||
'bgcolor': server.bgcolor,
|
||||
'fgcolor': server.fgcolor,
|
||||
'db_res': server.db_res.split(',') if server.db_res else None,
|
||||
'passfile': server.passfile if server.passfile else None,
|
||||
'sslcert': server.sslcert if is_ssl else None,
|
||||
'sslkey': server.sslkey if is_ssl else None,
|
||||
'sslrootcert': server.sslrootcert if is_ssl else None,
|
||||
'sslcrl': server.sslcrl if is_ssl else None,
|
||||
'sslcompression': True if is_ssl and server.sslcompression
|
||||
else False,
|
||||
'service': server.service if server.service else None,
|
||||
'connect_timeout':
|
||||
server.connect_timeout if server.connect_timeout else 0,
|
||||
'use_ssh_tunnel': server.use_ssh_tunnel
|
||||
if server.use_ssh_tunnel else 0,
|
||||
'tunnel_host': server.tunnel_host if server.tunnel_host
|
||||
else None,
|
||||
'tunnel_port': server.tunnel_port if server.tunnel_port
|
||||
else 22,
|
||||
'tunnel_username': server.tunnel_username
|
||||
if server.tunnel_username else None,
|
||||
'tunnel_identity_file': server.tunnel_identity_file
|
||||
if server.tunnel_identity_file else None,
|
||||
'tunnel_authentication': server.tunnel_authentication
|
||||
if server.tunnel_authentication else 0
|
||||
}
|
||||
)
|
||||
if is_ssl:
|
||||
sslcert = server.sslcert
|
||||
sslkey = server.sslkey
|
||||
sslrootcert = server.sslrootcert
|
||||
sslcrl = server.sslcrl
|
||||
|
||||
use_ssh_tunnel = 0
|
||||
tunnel_host = None
|
||||
tunnel_port = 22
|
||||
tunnel_username = None
|
||||
tunnel_authentication = 0
|
||||
|
||||
if server.use_ssh_tunnel:
|
||||
use_ssh_tunnel = server.use_ssh_tunnel
|
||||
tunnel_host = server.tunnel_host
|
||||
tunnel_port = server.tunnel_port
|
||||
tunnel_username = server.tunnel_username
|
||||
tunnel_authentication = server.tunnel_authentication
|
||||
|
||||
response = {
|
||||
'id': server.id,
|
||||
'name': server.name,
|
||||
'server_owner': server_owner,
|
||||
'user_id': server.user_id,
|
||||
'host': server.host,
|
||||
'hostaddr': server.hostaddr,
|
||||
'port': server.port,
|
||||
'db': server.maintenance_db,
|
||||
'shared': server.shared if config.SERVER_MODE else None,
|
||||
'username': server.username,
|
||||
'gid': str(server.servergroup_id),
|
||||
'group-name': sg.name,
|
||||
'comment': server.comment,
|
||||
'role': server.role,
|
||||
'connected': connected,
|
||||
'version': manager.ver,
|
||||
'sslmode': server.ssl_mode,
|
||||
'server_type': manager.server_type if connected else 'pg',
|
||||
'bgcolor': server.bgcolor,
|
||||
'fgcolor': server.fgcolor,
|
||||
'db_res': server.db_res.split(',') if server.db_res else None,
|
||||
'passfile': server.passfile if server.passfile else None,
|
||||
'sslcert': sslcert,
|
||||
'sslkey': sslkey,
|
||||
'sslrootcert': sslrootcert,
|
||||
'sslcrl': sslcrl,
|
||||
'sslcompression': True if is_ssl and server.sslcompression
|
||||
else False,
|
||||
'service': server.service if server.service else None,
|
||||
'connect_timeout':
|
||||
server.connect_timeout if server.connect_timeout else 0,
|
||||
'use_ssh_tunnel': use_ssh_tunnel,
|
||||
'tunnel_host': tunnel_host,
|
||||
'tunnel_port': tunnel_port,
|
||||
'tunnel_username': tunnel_username,
|
||||
'tunnel_identity_file': server.tunnel_identity_file
|
||||
if server.tunnel_identity_file else None,
|
||||
'tunnel_authentication': tunnel_authentication
|
||||
}
|
||||
|
||||
return ajax_response(response)
|
||||
|
||||
@login_required
|
||||
def create(self, gid):
|
||||
@ -802,11 +1067,11 @@ class ServerNode(PGChildNodeView):
|
||||
tunnel_port=data.get('tunnel_port', 22),
|
||||
tunnel_username=data.get('tunnel_username', None),
|
||||
tunnel_authentication=data.get('tunnel_authentication', 0),
|
||||
tunnel_identity_file=data.get('tunnel_identity_file', None)
|
||||
tunnel_identity_file=data.get('tunnel_identity_file', None),
|
||||
shared=data.get('shared', None)
|
||||
)
|
||||
db.session.add(server)
|
||||
db.session.commit()
|
||||
|
||||
connected = False
|
||||
user = None
|
||||
manager = None
|
||||
@ -1006,9 +1271,23 @@ class ServerNode(PGChildNodeView):
|
||||
|
||||
# Fetch Server Details
|
||||
server = Server.query.filter_by(id=sid).first()
|
||||
shared_server = None
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
shared_server, auto_detected_server = \
|
||||
ServerModule.get_shared_server(server, gid)
|
||||
server = ServerModule.get_shared_server_properties(server,
|
||||
shared_server)
|
||||
if server is None:
|
||||
return bad_request(self.not_found_error_msg())
|
||||
|
||||
# Return if username is blank
|
||||
if server.username is None:
|
||||
return make_json_response(
|
||||
status=200,
|
||||
success=0,
|
||||
errormsg=gettext(
|
||||
u"Please enter the server details to connect")
|
||||
)
|
||||
if current_user and hasattr(current_user, 'id'):
|
||||
# Fetch User Details.
|
||||
user = User.query.filter_by(id=current_user.id).first()
|
||||
@ -1063,7 +1342,6 @@ class ServerNode(PGChildNodeView):
|
||||
except Exception as e:
|
||||
current_app.logger.exception(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
if 'password' not in data:
|
||||
conn_passwd = getattr(conn, 'password', None)
|
||||
if conn_passwd is None and not server.save_password and \
|
||||
@ -1125,10 +1403,18 @@ class ServerNode(PGChildNodeView):
|
||||
# every time user try to connect
|
||||
# 1 is True in SQLite as no boolean type
|
||||
setattr(server, 'save_password', 1)
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
setattr(shared_server, 'save_password', 1)
|
||||
else:
|
||||
setattr(server, 'save_password', 1)
|
||||
|
||||
# Save the encrypted password using the user's login
|
||||
# password key, if there is any password to save
|
||||
if password:
|
||||
setattr(server, 'password', password)
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
setattr(shared_server, 'password', password)
|
||||
else:
|
||||
setattr(server, 'password', password)
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
# Release Connection
|
||||
@ -1560,21 +1846,39 @@ class ServerNode(PGChildNodeView):
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
server = Server.query.filter_by(
|
||||
user_id=current_user.id, id=sid
|
||||
).first()
|
||||
|
||||
server = Server.query.filter_by(id=sid).first()
|
||||
shared_server = None
|
||||
if server is None:
|
||||
return make_json_response(
|
||||
success=0,
|
||||
info=self.not_found_error_msg()
|
||||
)
|
||||
|
||||
setattr(server, 'password', None)
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
shared_server = SharedServer.query.filter_by(
|
||||
name=server.name, user_id=current_user.id,
|
||||
servergroup_id=gid).first()
|
||||
|
||||
if shared_server is None:
|
||||
return make_json_response(
|
||||
success=0,
|
||||
info=gettext("Could not find the required server.")
|
||||
)
|
||||
server = ServerModule. \
|
||||
get_shared_server_properties(server, shared_server)
|
||||
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
setattr(shared_server, 'save_password', None)
|
||||
else:
|
||||
setattr(server, 'save_password', None)
|
||||
|
||||
# If password was saved then clear the flag also
|
||||
# 0 is False in SQLite db
|
||||
if server.save_password:
|
||||
setattr(server, 'save_password', 0)
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
setattr(shared_server, 'save_password', 0)
|
||||
else:
|
||||
setattr(server, 'save_password', 0)
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
current_app.logger.error(
|
||||
@ -1599,10 +1903,7 @@ class ServerNode(PGChildNodeView):
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
server = Server.query.filter_by(
|
||||
user_id=current_user.id, id=sid
|
||||
).first()
|
||||
|
||||
server = Server.query.filter_by(id=sid).first()
|
||||
if server is None:
|
||||
return make_json_response(
|
||||
success=0,
|
||||
|
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.2.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#F2F2F2;}
|
||||
.st1{fill:#9BA5B0;}
|
||||
.st2{fill:none;stroke:#9BA5B0;stroke-width:0.75;stroke-miterlimit:1;}
|
||||
.st3{fill:#F7F7F7;}
|
||||
.st4{fill:#354A5F;}
|
||||
.st5{fill:none;stroke:#D0021B;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M6.7,2.1h4.6c0.6,0,1.1,0.5,1.1,1.1v0.8c0,0.6-0.5,1.1-1.1,1.1H6.7c-0.6,0-1.1-0.5-1.1-1.1V3.2
|
||||
C5.6,2.6,6.1,2.1,6.7,2.1z"/>
|
||||
<path class="st1" d="M11.3,2.5c0.4,0,0.8,0.3,0.8,0.8v0.8c0,0.4-0.3,0.8-0.8,0.8H6.7C6.3,4.8,6,4.5,6,4.1V3.2
|
||||
c0-0.4,0.3-0.7,0.8-0.7H11.3 M11.3,1.7H6.7c-0.8,0-1.5,0.7-1.5,1.5v0.8c0,0.8,0.7,1.5,1.5,1.5h4.6c0.8,0,1.5-0.7,1.5-1.5V3.2
|
||||
C12.8,2.4,12.1,1.7,11.3,1.7L11.3,1.7z"/>
|
||||
<line class="st2" x1="8.9" y1="3.6" x2="6.8" y2="3.6"/>
|
||||
<path class="st0" d="M6.7,5.2h4.6c0.6,0,1.1,0.5,1.1,1.1v0.8c0,0.6-0.5,1.1-1.1,1.1H6.7c-0.6,0-1.1-0.5-1.1-1.1V6.3
|
||||
C5.6,5.7,6.1,5.2,6.7,5.2z"/>
|
||||
<path class="st1" d="M11.3,5.6c0.4,0,0.8,0.3,0.8,0.8v0.8c0,0.4-0.3,0.8-0.8,0.8H6.7C6.3,7.9,6,7.6,6,7.1V6.3
|
||||
c0-0.4,0.3-0.7,0.8-0.7H11.3 M11.3,4.8H6.7c-0.8,0-1.5,0.7-1.5,1.5v0.8c0,0.8,0.7,1.5,1.5,1.5h4.6c0.8,0,1.5-0.7,1.5-1.5V6.3
|
||||
C12.8,5.5,12.1,4.8,11.3,4.8L11.3,4.8z"/>
|
||||
<line class="st2" x1="8.9" y1="6.7" x2="6.8" y2="6.7"/>
|
||||
<path class="st0" d="M6.7,8.3h4.6c0.6,0,1.1,0.5,1.1,1.1v0.9c0,0.6-0.5,1.1-1.1,1.1c0,0,0,0,0,0H6.7c-0.6,0-1.1-0.5-1.1-1.1l0,0
|
||||
V9.4C5.6,8.8,6.1,8.3,6.7,8.3C6.7,8.3,6.7,8.3,6.7,8.3z"/>
|
||||
<path class="st1" d="M11.3,8.7c0.4,0,0.8,0.3,0.8,0.8v0.8c0,0.4-0.3,0.8-0.8,0.8H6.7C6.3,11,6,10.7,6,10.3V9.4C6,9,6.3,8.7,6.7,8.7
|
||||
H11.3 M11.3,7.9H6.7c-0.8,0-1.5,0.7-1.5,1.5v0.8c0,0.8,0.7,1.5,1.5,1.5h4.6c0.8,0,1.5-0.7,1.5-1.5V9.4C12.8,8.6,12.1,7.9,11.3,7.9z
|
||||
"/>
|
||||
<line class="st2" x1="8.9" y1="9.8" x2="6.8" y2="9.8"/>
|
||||
</g>
|
||||
<path class="st3" d="M11.6,10.5c-0.6,0.3-0.8,0.1-1.1-0.2c-0.1-0.2-0.3-0.4-0.6-0.5L7.1,8.5C6.8,8.4,6.4,8.3,6.1,8.3
|
||||
C5.1,8.1,4.2,8.4,3.4,9l-1.4,1.1v2.7h0.9v-0.2l3.7,1.8c0.4,0.2,0.7,0.3,1.1,0.3c0.3,0,0.7-0.1,1-0.2l6.1-2.6
|
||||
c0.3-0.1,0.6-0.4,0.7-0.7c0.1-0.3,0.1-0.7,0-1c-0.3-0.6-1.1-0.9-1.7-0.6l-0.4,0.2L11.6,10.5"/>
|
||||
<path class="st4" d="M15.5,10.2c-0.3-0.6-1.1-0.9-1.7-0.6l-0.4,0.2l-1.8,0.8l0.3,0.8l1.8-0.8l0.4-0.2c0.2-0.1,0.5,0,0.6,0.2
|
||||
c0.1,0.1,0.1,0.2,0,0.3c0,0.1-0.1,0.2-0.2,0.2l-6.1,2.6c-0.5,0.2-1,0.2-1.4,0l-4.1-2v-1.2l1-0.8C4.5,9.2,5.2,9,6,9.1
|
||||
c0.3,0,0.6,0.1,0.8,0.2l2.8,1.2c0.1,0,0.1,0.1,0.2,0.2c0.1,0.1,0.1,0.3,0,0.4c0,0,0,0.1-0.1,0.1c-0.1,0.1-0.3,0.2-0.5,0.1l-2.2-1
|
||||
l-0.4,0.8l2.2,1c0.2,0.1,0.4,0.1,0.5,0.1c0.4,0,0.7-0.2,1-0.4c0.1-0.1,0.2-0.2,0.2-0.3c0.2-0.4,0.1-0.9-0.1-1.2
|
||||
c-0.1-0.2-0.3-0.4-0.6-0.5L7.1,8.5C6.8,8.4,6.4,8.3,6.1,8.3C5.1,8.1,4.2,8.4,3.4,9L2.9,9.4V9.3c0-0.6-0.4-1-1-1H1.4
|
||||
c-0.6,0-1,0.4-1,1v4.1c0,0.6,0.4,1,1,1h0.5c0.6,0,1-0.4,1-1v-0.6h0v-0.2l3.7,1.8c0.4,0.2,0.7,0.3,1.1,0.3c0.3,0,0.7-0.1,1-0.2
|
||||
l6.1-2.6c0.3-0.1,0.6-0.4,0.7-0.7C15.7,10.9,15.7,10.5,15.5,10.2z M1.9,13.4H1.4V9.3h0.5L1.9,13.4z"/>
|
||||
<line class="st5" x1="13.8" y1="1.3" x2="10.8" y2="4.3"/>
|
||||
<line class="st5" x1="13.8" y1="4.3" x2="10.8" y2="1.3"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
@ -56,7 +56,12 @@ define('pgadmin.node.server', [
|
||||
type: 'server',
|
||||
dialogHelp: url_for('help.static', {'filename': 'server_dialog.html'}),
|
||||
label: gettext('Server'),
|
||||
canDrop: true,
|
||||
canDrop: function(node){
|
||||
var serverOwner = node.user_id;
|
||||
if (serverOwner != current_user.id)
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
dropAsRemove: true,
|
||||
dropPriority: 5,
|
||||
hasStatistics: true,
|
||||
@ -75,12 +80,12 @@ define('pgadmin.node.server', [
|
||||
name: 'create_server_on_sg', node: 'server_group', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 1, label: gettext('Server...'),
|
||||
data: {action: 'create'}, icon: 'wcTabIcon icon-server',
|
||||
data: {action: 'create'}, icon: 'wcTabIcon icon-server', enable: 'canCreate',
|
||||
},{
|
||||
name: 'create_server', node: 'server', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 3, label: gettext('Server...'),
|
||||
data: {action: 'create'}, icon: 'wcTabIcon icon-server',
|
||||
data: {action: 'create'}, icon: 'wcTabIcon icon-server', enable: 'canCreate',
|
||||
},{
|
||||
name: 'connect_server', node: 'server', module: this,
|
||||
applies: ['object', 'context'], callback: 'connect_server',
|
||||
@ -150,6 +155,13 @@ define('pgadmin.node.server', [
|
||||
is_not_connected: function(node) {
|
||||
return (node && node.connected != true);
|
||||
},
|
||||
canCreate: function(node){
|
||||
var serverOwner = node.user_id;
|
||||
if (serverOwner == current_user.id || _.isUndefined(serverOwner))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
},
|
||||
is_connected: function(node) {
|
||||
return (node && node.connected == true);
|
||||
},
|
||||
@ -226,28 +238,25 @@ define('pgadmin.node.server', [
|
||||
d = t.itemData(i);
|
||||
t.removeIcon(i);
|
||||
d.connected = false;
|
||||
d.icon = 'icon-server-not-connected';
|
||||
if (d.shared){
|
||||
d.icon = 'icon-shared-server-not-connected';
|
||||
}else{
|
||||
d.icon = 'icon-server-not-connected';
|
||||
}
|
||||
t.addIcon(i, {icon: d.icon});
|
||||
obj.callbacks.refresh.apply(obj, [null, i]);
|
||||
if (pgBrowser.serverInfo && d._id in pgBrowser.serverInfo) {
|
||||
delete pgBrowser.serverInfo[d._id];
|
||||
}
|
||||
pgBrowser.enable_disable_menus(i);
|
||||
// Trigger server disconnect event
|
||||
pgBrowser.Events.trigger(
|
||||
'pgadmin:server:disconnect',
|
||||
{item: i, data: d}, false
|
||||
);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Alertify.error(res.errormsg);
|
||||
} catch (e) {
|
||||
console.warn(e.stack || e);
|
||||
else {
|
||||
try {
|
||||
Alertify.error(res.errormsg);
|
||||
} catch (e) {
|
||||
console.warn(e.stack || e);
|
||||
}
|
||||
t.unload(i);
|
||||
}
|
||||
t.unload(i);
|
||||
}
|
||||
})
|
||||
}})
|
||||
.fail(function(xhr, status, error) {
|
||||
Alertify.pgRespErrorNotify(xhr, error);
|
||||
t.unload(i);
|
||||
@ -735,6 +744,7 @@ define('pgadmin.node.server', [
|
||||
// Default values!
|
||||
initialize: function(attrs, args) {
|
||||
var isNew = (_.size(attrs) === 0);
|
||||
console.warn('warn');
|
||||
|
||||
if (isNew) {
|
||||
this.set({'gid': args.node_info['server_group']._id});
|
||||
@ -745,12 +755,17 @@ define('pgadmin.node.server', [
|
||||
id: 'id', label: gettext('ID'), type: 'int', mode: ['properties'],
|
||||
},{
|
||||
id: 'name', label: gettext('Name'), type: 'text',
|
||||
mode: ['properties', 'edit', 'create'],
|
||||
},{
|
||||
mode: ['properties', 'edit', 'create'], disabled: 'isShared',
|
||||
},
|
||||
{
|
||||
id: 'gid', label: gettext('Server group'), type: 'int',
|
||||
control: 'node-list-by-id', node: 'server_group',
|
||||
mode: ['create', 'edit'], select2: {allowClear: false},
|
||||
},{
|
||||
mode: ['create', 'edit'], select2: {allowClear: false}, visible: 'isVisible',
|
||||
},
|
||||
{
|
||||
id: 'server_owner', label: gettext('Shared Server Owner'), type: 'text', mode: ['properties'],
|
||||
},
|
||||
{
|
||||
id: 'server_type', label: gettext('Server type'), type: 'options',
|
||||
mode: ['properties'], visible: 'isConnected',
|
||||
'options': supported_servers,
|
||||
@ -773,11 +788,27 @@ define('pgadmin.node.server', [
|
||||
id: 'connect_now', controlLabel: gettext('Connect now?'), type: 'checkbox',
|
||||
group: null, mode: ['create'],
|
||||
},{
|
||||
id: 'shared', label: gettext('Shared with all?'), type: 'switch',
|
||||
mode: ['properties', 'create', 'edit'], 'options': {'size': 'mini'},
|
||||
readonly: function(model){
|
||||
var serverOwner = model.attributes.user_id;
|
||||
if (!model.isNew() && serverOwner != current_user.id){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},visible: function(){
|
||||
if (current_user.is_admin && pgAdmin.server_mode == 'True')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'comment', label: gettext('Comments'), type: 'multiline', group: null,
|
||||
mode: ['properties', 'edit', 'create'],
|
||||
},{
|
||||
id: 'host', label: gettext('Host name/address'), type: 'text', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'],
|
||||
mode: ['properties', 'edit', 'create'],disabled: 'isShared',
|
||||
control: Backform.InputControl.extend({
|
||||
onChange: function() {
|
||||
Backform.InputControl.prototype.onChange.apply(this, arguments);
|
||||
@ -798,7 +829,7 @@ define('pgadmin.node.server', [
|
||||
}),
|
||||
},{
|
||||
id: 'port', label: gettext('Port'), type: 'int', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'], min: 1, max: 65535,
|
||||
mode: ['properties', 'edit', 'create'], min: 1, max: 65535, disabled: 'isShared',
|
||||
control: Backform.InputControl.extend({
|
||||
onChange: function() {
|
||||
Backform.InputControl.prototype.onChange.apply(this, arguments);
|
||||
@ -819,7 +850,7 @@ define('pgadmin.node.server', [
|
||||
}),
|
||||
},{
|
||||
id: 'db', label: gettext('Maintenance database'), type: 'text', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected',
|
||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected',disabled: 'isShared',
|
||||
},{
|
||||
id: 'username', label: gettext('Username'), type: 'text', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'],
|
||||
@ -1057,6 +1088,21 @@ define('pgadmin.node.server', [
|
||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected',
|
||||
min: 0,
|
||||
}],
|
||||
isVisible: function(model){
|
||||
var serverOwner = model.attributes.user_id;
|
||||
if (!model.isNew() && serverOwner != current_user.id){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
},
|
||||
isShared: function(model){
|
||||
var serverOwner = model.attributes.user_id;
|
||||
if (!model.isNew() && serverOwner != current_user.id && model.attributes.shared){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
validate: function() {
|
||||
const validateModel = new modelValidation.ModelValidation(this);
|
||||
return validateModel.validate();
|
||||
@ -1153,7 +1199,36 @@ define('pgadmin.node.server', [
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var connect_to_server = function(obj, data, tree, item, reconnect) {
|
||||
// Open properties dialog in edit mode
|
||||
const selectedTreeNode = tree.selected().length > 0 ? tree.selected() : tree.first();
|
||||
const selectedTreeNodeData = selectedTreeNode && selectedTreeNode.length === 1 ? tree.itemData(selectedTreeNode) : undefined;
|
||||
var server_url = obj.generate_url(item, 'obj', data, true);
|
||||
// Fetch the updated data
|
||||
$.get(server_url)
|
||||
.done(function(res) {
|
||||
if (res.shared && _.isNull(res.username) && data.user_id != current_user.id){
|
||||
if (selectedTreeNodeData._type == 'server'){
|
||||
pgAdmin.Browser.Node.callbacks.show_obj_properties.call(
|
||||
pgAdmin.Browser.Nodes[tree.itemData(item)._type], {action: 'edit'}
|
||||
);
|
||||
data.is_connecting = false;
|
||||
tree.unload(item);
|
||||
tree.setInode(item);
|
||||
tree.addIcon(item, {icon: 'icon-shared-server-not-connected'});
|
||||
}else{
|
||||
data.is_connecting = false;
|
||||
tree.unload(item);
|
||||
tree.setInode(item);
|
||||
tree.addIcon(item, {icon: 'icon-shared-server-not-connected'});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}).always(function(){
|
||||
data.is_connecting = false;
|
||||
});
|
||||
|
||||
var wasConnected = reconnect || data.connected,
|
||||
onFailure = function(
|
||||
xhr, status, error, _node, _data, _tree, _item, _wasConnected
|
||||
@ -1164,7 +1239,12 @@ define('pgadmin.node.server', [
|
||||
// Let's not change the status of the tree node now.
|
||||
if (!_wasConnected) {
|
||||
tree.setInode(_item);
|
||||
tree.addIcon(_item, {icon: 'icon-server-not-connected'});
|
||||
if (data.shared){
|
||||
tree.addIcon(_item, {icon: 'icon-shared-server-not-connected'});
|
||||
}else{
|
||||
tree.addIcon(_item, {icon: 'icon-server-not-connected'});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Alertify.pgNotifier('error', xhr, error, function(msg) {
|
||||
@ -1321,7 +1401,11 @@ define('pgadmin.node.server', [
|
||||
_tree.unload(_item);
|
||||
_tree.setInode(_item);
|
||||
_tree.removeIcon(_item);
|
||||
_tree.addIcon(_item, {icon: 'icon-server-not-connected'});
|
||||
if (_data.shared){
|
||||
_tree.addIcon(_item, {icon: 'icon-shared-server-not-connected'});
|
||||
}else{
|
||||
_tree.addIcon(_item, {icon: 'icon-server-not-connected'});
|
||||
}
|
||||
obj.trigger('connect:cancelled', data._id, data.db, obj, _item, _data);
|
||||
pgBrowser.Events.trigger(
|
||||
'pgadmin:server:connect:cancelled', data._id, _item, _data, obj
|
||||
@ -1387,7 +1471,11 @@ define('pgadmin.node.server', [
|
||||
})
|
||||
.fail(function(xhr, status, error) {
|
||||
tree.setInode(item);
|
||||
tree.addIcon(item, {icon: 'icon-server-not-connected'});
|
||||
if (data.shared){
|
||||
tree.addIcon(item, {icon: 'icon-shared-server-not-connected'});
|
||||
}else{
|
||||
tree.addIcon(item, {icon: 'icon-server-not-connected'});
|
||||
}
|
||||
Alertify.pgRespErrorNotify(xhr, error);
|
||||
});
|
||||
};
|
||||
|
@ -15,3 +15,21 @@
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
.icon-shared-server-not-connected {
|
||||
background-image: url('{{ url_for('NODE-server.static', filename='img/sharedserverbad.svg') }}') !important;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 20px !important;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
.icon-shared-server-not-connected {
|
||||
background-image: url('{{ url_for('NODE-server.static', filename='img/sharedserverbad.svg') }}') !important;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 20px !important;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
||||
|
@ -0,0 +1,862 @@
|
||||
{
|
||||
"add_server": [
|
||||
{
|
||||
"name": "Add server with service id",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"owner_server": true,
|
||||
"test_data": {
|
||||
"service": "TestDB"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Test default server url",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"owner_server": true,
|
||||
"test_data": {
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Add server with connect timeout",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"test_data": {
|
||||
"connect_timeout": 5
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Add server using SSH tunnel with password",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"ssh_tunnel": true,
|
||||
"with_password": true,
|
||||
"save_password": false,
|
||||
"test_data": {
|
||||
"use_ssh_tunnel": 1,
|
||||
"tunnel_host": "127.0.0.1",
|
||||
"tunnel_port": 22,
|
||||
"tunnel_username": "user",
|
||||
"tunnel_authentication": 1,
|
||||
"tunnel_identity_file": "pkey_rsa"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Add server using SSH tunnel with identity file",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"ssh_tunnel": true,
|
||||
"with_password": false,
|
||||
"save_password": false,
|
||||
"test_data": {
|
||||
"use_ssh_tunnel": 1,
|
||||
"tunnel_host": "127.0.0.1",
|
||||
"tunnel_port": 22,
|
||||
"tunnel_username": "user",
|
||||
"tunnel_authentication": 1,
|
||||
"tunnel_identity_file": "pkey_rsa"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Add server using SSH tunnel with password and saved it",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"ssh_tunnel": true,
|
||||
"with_password": true,
|
||||
"save_password": true,
|
||||
"test_data": {
|
||||
"use_ssh_tunnel": 1,
|
||||
"tunnel_host": "127.0.0.1",
|
||||
"tunnel_port": 22,
|
||||
"tunnel_username": "user",
|
||||
"tunnel_authentication": 0,
|
||||
"tunnel_password": "123456"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Add server using SSH tunnel with identity file and save the password",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"ssh_tunnel": true,
|
||||
"with_password": false,
|
||||
"save_password": true,
|
||||
"test_data": {
|
||||
"use_ssh_tunnel": 1,
|
||||
"tunnel_host": "127.0.0.1",
|
||||
"tunnel_port": 22,
|
||||
"tunnel_username": "user",
|
||||
"tunnel_authentication": 1,
|
||||
"tunnel_identity_file": "pkey_rsa",
|
||||
"tunnel_password": "123456"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Add server with password and save password to true",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"with_pwd": true,
|
||||
"with_save": true,
|
||||
"owner_server": true,
|
||||
"test_data": {
|
||||
"service": "TestDB"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Add server with password and save password to false",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"with_pwd": true,
|
||||
"with_save": false,
|
||||
"owner_server": true,
|
||||
"test_data": {
|
||||
"service": "TestDB"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Add server without password and save password to true",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"with_pwd": false,
|
||||
"with_save": true,
|
||||
"owner_server": true,
|
||||
"test_data": {
|
||||
"service": "TestDB"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Add server with connect now",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"owner_server": true,
|
||||
"test_data": {
|
||||
"service": "TestDB"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
}
|
||||
],
|
||||
"is_password_saved": [
|
||||
{
|
||||
"name": "Connect server with 'save password",
|
||||
"url": "/browser/server/connect/",
|
||||
"is_positive_test": true,
|
||||
"test_data": {
|
||||
"is_password_saved": true
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200,
|
||||
"message": "Server connected."
|
||||
}
|
||||
}
|
||||
],
|
||||
"get_server": [
|
||||
{
|
||||
"name": "Get a server URL",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Reload a server configuration",
|
||||
"url": "/browser/server/reload/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get a server URL using wrong server id",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"incorrect_server_id": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 410
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get a server Node dependants",
|
||||
"url": "/browser/server/dependent/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get a server Node dependency",
|
||||
"url": "/browser/server/dependency/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get a server Node sql",
|
||||
"url": "/browser/server/sql/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get a server Node msql",
|
||||
"url": "/browser/server/msql/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get a server Node statistics",
|
||||
"url": "/browser/server/stats/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get a server pgpass details",
|
||||
"url": "/browser/server/check_pgpass/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 410
|
||||
}
|
||||
}
|
||||
],
|
||||
"get_shared_server": [
|
||||
{
|
||||
"name": "Get a shared server",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"shared": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get a all shared server",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"shared": true,
|
||||
"no_server_id": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get the all available shared server",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"no_server_id": true,
|
||||
"shared": true,
|
||||
"server_list": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
}
|
||||
],
|
||||
"get_all_server": [
|
||||
{
|
||||
"name": "Get the all children of server",
|
||||
"url": "/browser/server/children/",
|
||||
"is_positive_test": true,
|
||||
"children": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 500
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get the all available servers",
|
||||
"url": "/browser/server/nodes/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get the all available server of server group",
|
||||
"url": "/browser/server/nodes/",
|
||||
"is_positive_test": true,
|
||||
"server_list": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get the all available server of server group",
|
||||
"url": "/browser/server/nodes/",
|
||||
"is_positive_test": true,
|
||||
"server_list": true,
|
||||
"servers": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get the all connected servers",
|
||||
"url": "/browser/server/nodes/",
|
||||
"is_positive_test": true,
|
||||
"server_list": true,
|
||||
"servers": true,
|
||||
"connected": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
}
|
||||
],
|
||||
"connect_server": [
|
||||
{
|
||||
"name": "Get a server connection",
|
||||
"url": "/browser/server/connect/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "connect to a server using password",
|
||||
"url": "/browser/server/connect/",
|
||||
"is_positive_test": true,
|
||||
"connect": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Disconnect server test",
|
||||
"url": "/browser/server/connect/",
|
||||
"is_positive_test": true,
|
||||
"disconnect": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Disconnect server when wrong server id passed",
|
||||
"url": "/browser/server/connect/",
|
||||
"is_positive_test": true,
|
||||
"disconnect": true,
|
||||
"wrong_server_id": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 400
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Reload a server configuration",
|
||||
"url": "/browser/server/reload/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Error while creating server restore point",
|
||||
"url": "/browser/server/restore_point/",
|
||||
"is_positive_test": true,
|
||||
"restore_point": true,
|
||||
"test_data": {
|
||||
"Named restore point created": "PLACE_HOLDER"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 500
|
||||
}
|
||||
}
|
||||
],
|
||||
"delete_server": [
|
||||
{
|
||||
"name": "Delete a server URL",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Disconnect server test",
|
||||
"url": "/browser/server/connect/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Error while fetching a server to delete",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": false,
|
||||
"mocking_required": true,
|
||||
"mock_data": {
|
||||
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_dict",
|
||||
"return_value": "(True, 'Mocked Internal Server Error')"
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 500
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "server not found while deleting a server",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"invalid_server_id": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 410
|
||||
}
|
||||
}
|
||||
],
|
||||
"update_server": [
|
||||
{
|
||||
"name": "update a server name",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"sslcompression": 1
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "update a server details without data",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"test_data": {},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Update server with wrong server id",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": false,
|
||||
"clear_save_password": true,
|
||||
"wrong_server_id": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 410
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Update server with incorrect hostaddr",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"hostaddr": "PLACE_HOLDER",
|
||||
"db_res": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 400
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "update a server , make server shared",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"owner_server": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"shared": true
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Clear saved password",
|
||||
"url": "/browser/server/clear_saved_password/",
|
||||
"is_positive_test": true,
|
||||
"clear_save_password": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"is_password_saved": false
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Clear saved password with wrong server id",
|
||||
"url": "/browser/server/clear_saved_password/",
|
||||
"is_positive_test": false,
|
||||
"clear_save_password": true,
|
||||
"wrong_server_id": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"is_password_saved": false
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "wal replay",
|
||||
"url": "/browser/server/wal_replay/",
|
||||
"is_positive_test": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"is_password_saved": false
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 410
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Clear ssh tunnel password",
|
||||
"url": "/browser/server/clear_sshtunnel_password/",
|
||||
"is_positive_test": true,
|
||||
"clear_save_password": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"is_password_saved": false
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Clear ssh tunnel password with wrong server id",
|
||||
"url": "/browser/server/clear_sshtunnel_password/",
|
||||
"is_positive_test": false,
|
||||
"clear_save_password": true,
|
||||
"wrong_server_id": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"is_password_saved": false
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "error while clearing a ssh password",
|
||||
"url": "/browser/server/clear_sshtunnel_password/",
|
||||
"is_positive_test": false,
|
||||
"error_clearing_password": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"is_password_saved": false
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
}
|
||||
],
|
||||
"update_shared_server": [
|
||||
{
|
||||
"name": "update a server name",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"sslcompression": 1
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "update a server details without data",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"test_data": {},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Update server with wrong server id",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": false,
|
||||
"clear_save_password": true,
|
||||
"wrong_server_id": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 410
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Update server with incorrect hostaddr",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"hostaddr": "PLACE_HOLDER",
|
||||
"db_res": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 400
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "update a server , make server shared",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"owner_server": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"shared": true
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Clear saved password when login user is not owner of server",
|
||||
"url": "/browser/server/clear_saved_password/",
|
||||
"is_positive_test": true,
|
||||
"clear_save_password": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"is_password_saved": false
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Clear saved password with wrong server id",
|
||||
"url": "/browser/server/clear_saved_password/",
|
||||
"is_positive_test": false,
|
||||
"clear_save_password": true,
|
||||
"wrong_server_id": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"is_password_saved": false
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Clear ssh tunnel password",
|
||||
"url": "/browser/server/clear_sshtunnel_password/",
|
||||
"is_positive_test": true,
|
||||
"clear_save_password": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"is_password_saved": false
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Clear ssh tunnel password with wrong server id",
|
||||
"url": "/browser/server/clear_sshtunnel_password/",
|
||||
"is_positive_test": false,
|
||||
"clear_save_password": true,
|
||||
"wrong_server_id": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"is_password_saved": false
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "error while clearing a ssh password",
|
||||
"url": "/browser/server/clear_sshtunnel_password/",
|
||||
"is_positive_test": false,
|
||||
"error_clearing_password": true,
|
||||
"test_data": {
|
||||
"comment": "PLACE_HOLDER",
|
||||
"id": "PLACE_HOLDER",
|
||||
"is_password_saved": false
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
}
|
||||
],
|
||||
"delete_multiple_server": [
|
||||
{
|
||||
"name": "Delete multiple server",
|
||||
"url": "/browser/server/obj/",
|
||||
"is_positive_test": true,
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import json
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as servers_utils
|
||||
|
||||
|
||||
class AddServerTest(BaseTestGenerator):
|
||||
""" This class will add the servers under default server group. """
|
||||
|
||||
scenarios = utils.generate_scenarios('add_server',
|
||||
servers_utils.test_cases)
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def create_server(self, url):
|
||||
return self.tester.post(
|
||||
url,
|
||||
data=json.dumps(self.server),
|
||||
content_type='html/json'
|
||||
)
|
||||
|
||||
def runTest(self):
|
||||
""" This function will add the server under default server group."""
|
||||
url = "{0}{1}/".format(self.url, utils.SERVER_GROUP)
|
||||
|
||||
# Add service name in the config
|
||||
if 'connect_timeout' in self.test_data:
|
||||
self.server['connect_timeout'] = self.test_data['connect_timeout']
|
||||
elif 'shared' in self.test_data:
|
||||
self.server['shared'] = self.test_data['shared']
|
||||
elif 'service' in self.test_data:
|
||||
self.server['service'] = self.test_data['service']
|
||||
|
||||
if hasattr(self, 'ssh_tunnel'):
|
||||
self.server['use_ssh_tunnel'] = self.test_data['use_ssh_tunnel']
|
||||
self.server['tunnel_host'] = self.test_data['tunnel_host']
|
||||
self.server['tunnel_port'] = self.test_data['tunnel_port']
|
||||
self.server['tunnel_username'] = self.test_data['tunnel_username']
|
||||
|
||||
if self.with_password:
|
||||
self.server['tunnel_authentication'] = self.test_data[
|
||||
'tunnel_authentication']
|
||||
else:
|
||||
self.server['tunnel_authentication'] = 1
|
||||
self.server['tunnel_identity_file'] = 'pkey_rsa'
|
||||
|
||||
if self.save_password:
|
||||
self.server['tunnel_password'] = self.test_data[
|
||||
'tunnel_password']
|
||||
if 'connect_now' in self.test_data:
|
||||
self.server['connect_now'] = self.test_data['connect_now']
|
||||
self.server['password'] = self.server['db_password']
|
||||
|
||||
if self.is_positive_test:
|
||||
if hasattr(self, 'with_save'):
|
||||
self.server['save_password'] = self.with_save
|
||||
if hasattr(self, 'with_pwd') and not self.with_pwd:
|
||||
# Remove the password from server object
|
||||
db_password = self.server['db_password']
|
||||
del self.server['db_password']
|
||||
response = self.create_server(url)
|
||||
self.assertEquals(response.status_code,
|
||||
self.expected_data["status_code"])
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
self.server_id = response_data['node']['_id']
|
||||
|
||||
if hasattr(self, 'with_pwd') and not self.with_pwd:
|
||||
# Remove the password from server object
|
||||
self.server['db_password'] = db_password
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite """
|
||||
utils.delete_server_with_api(self.tester, self.server_id)
|
@ -1,47 +0,0 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import json
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
|
||||
|
||||
class ServersWithConnectTimeoutAddTestCase(BaseTestGenerator):
|
||||
""" This class will add the servers under default server group. """
|
||||
|
||||
scenarios = [
|
||||
# Fetch the default url for server object
|
||||
(
|
||||
'Default Server Node url', dict(
|
||||
url='/browser/server/obj/'
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def runTest(self):
|
||||
""" This function will add the server under default server group."""
|
||||
url = "{0}{1}/".format(self.url, utils.SERVER_GROUP)
|
||||
# Add service name in the config
|
||||
self.server['connect_timeout'] = 5
|
||||
response = self.tester.post(
|
||||
url,
|
||||
data=json.dumps(self.server),
|
||||
content_type='html/json'
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
self.server_id = response_data['node']['_id']
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite """
|
||||
utils.delete_server_with_api(self.tester, self.server_id)
|
@ -1,47 +0,0 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import json
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
|
||||
|
||||
class ServersWithServiceIDAddTestCase(BaseTestGenerator):
|
||||
""" This class will add the servers under default server group. """
|
||||
|
||||
scenarios = [
|
||||
# Fetch the default url for server object
|
||||
(
|
||||
'Default Server Node url', dict(
|
||||
url='/browser/server/obj/'
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def runTest(self):
|
||||
""" This function will add the server under default server group."""
|
||||
url = "{0}{1}/".format(self.url, utils.SERVER_GROUP)
|
||||
# Add service name in the config
|
||||
self.server['service'] = "TestDB"
|
||||
response = self.tester.post(
|
||||
url,
|
||||
data=json.dumps(self.server),
|
||||
content_type='html/json'
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
self.server_id = response_data['node']['_id']
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite """
|
||||
utils.delete_server_with_api(self.tester, self.server_id)
|
@ -1,82 +0,0 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import json
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
|
||||
|
||||
class ServersWithSSHTunnelAddTestCase(BaseTestGenerator):
|
||||
""" This class will add the servers under default server group. """
|
||||
|
||||
scenarios = [
|
||||
(
|
||||
'Add server using SSH tunnel with password', dict(
|
||||
url='/browser/server/obj/',
|
||||
with_password=True,
|
||||
save_password=False,
|
||||
)
|
||||
),
|
||||
(
|
||||
'Add server using SSH tunnel with identity file', dict(
|
||||
url='/browser/server/obj/',
|
||||
with_password=False,
|
||||
save_password=False,
|
||||
)
|
||||
),
|
||||
(
|
||||
'Add server using SSH tunnel with password and saved it', dict(
|
||||
url='/browser/server/obj/',
|
||||
with_password=True,
|
||||
save_password=True,
|
||||
)
|
||||
),
|
||||
(
|
||||
'Add server using SSH tunnel with identity file and save the '
|
||||
'password', dict(
|
||||
url='/browser/server/obj/',
|
||||
with_password=False,
|
||||
save_password=True,
|
||||
)
|
||||
),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def runTest(self):
|
||||
""" This function will add the server under default server group."""
|
||||
url = "{0}{1}/".format(self.url, utils.SERVER_GROUP)
|
||||
# Add service name in the config
|
||||
self.server['use_ssh_tunnel'] = 1
|
||||
self.server['tunnel_host'] = '127.0.0.1'
|
||||
self.server['tunnel_port'] = 22
|
||||
self.server['tunnel_username'] = 'user'
|
||||
if self.with_password:
|
||||
self.server['tunnel_authentication'] = 0
|
||||
else:
|
||||
self.server['tunnel_authentication'] = 1
|
||||
self.server['tunnel_identity_file'] = 'pkey_rsa'
|
||||
|
||||
if self.save_password:
|
||||
self.server['tunnel_password'] = '123456'
|
||||
|
||||
response = self.tester.post(
|
||||
url,
|
||||
data=json.dumps(self.server),
|
||||
content_type='html/json'
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
self.server_id = response_data['node']['_id']
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite """
|
||||
utils.delete_server_with_api(self.tester, self.server_id)
|
@ -0,0 +1,78 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
import random
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression import parent_node_dict
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as servers_utils
|
||||
|
||||
|
||||
class AllServersGetTestCase(BaseTestGenerator):
|
||||
"""
|
||||
This class will fetch added servers under default server group
|
||||
by response code.
|
||||
"""
|
||||
|
||||
scenarios = utils.generate_scenarios('get_all_server',
|
||||
servers_utils.test_cases)
|
||||
|
||||
def setUp(self):
|
||||
"""This function add the server to test the GET API"""
|
||||
self.server['password'] = 'edb'
|
||||
self.server_id = utils.create_server(self.server)
|
||||
server_dict = {"server_id": self.server_id}
|
||||
utils.write_node_info("sid", server_dict)
|
||||
|
||||
def get_server(self):
|
||||
return self.tester.get(self.url, follow_redirects=True)
|
||||
|
||||
def connect_to_server(self, url):
|
||||
return self.tester.post(
|
||||
url,
|
||||
data=self.server,
|
||||
content_type='html/json'
|
||||
)
|
||||
|
||||
def runTest(self):
|
||||
""" This function will fetch the added servers to object browser. """
|
||||
server_id = parent_node_dict["server"][-1]["server_id"]
|
||||
if not server_id:
|
||||
raise Exception("Server not found to test GET API")
|
||||
response = None
|
||||
if self.is_positive_test:
|
||||
if hasattr(self, 'invalid_server_group'):
|
||||
self.url = self.url + '{0}/{1}?_={1}'.format(
|
||||
utils.SERVER_GROUP, random.randint(1, 9999999))
|
||||
elif hasattr(self, 'children'):
|
||||
|
||||
self.url = self.url + '{0}/{1}'.format(
|
||||
utils.SERVER_GROUP, server_id)
|
||||
elif hasattr(self, 'server_list'):
|
||||
if hasattr(self, 'servers'):
|
||||
server_id = ''
|
||||
self.url = self.url + '{0}/{1}'.format(
|
||||
utils.SERVER_GROUP, server_id)
|
||||
else:
|
||||
if hasattr(self, "connected"):
|
||||
url = '/browser/server/connect/' + '{0}/{1}'.format(
|
||||
utils.SERVER_GROUP,
|
||||
self.server_id)
|
||||
self.server['password'] = 'edb'
|
||||
|
||||
self.connect_to_server(url)
|
||||
self.url = self.url + '{0}/{1}?_={2}'.format(
|
||||
utils.SERVER_GROUP, server_id, random.randint(1, 9999999))
|
||||
response = self.get_server()
|
||||
self.assertEquals(response.status_code,
|
||||
self.expected_data["status_code"])
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite """
|
||||
utils.delete_server_with_api(self.tester, self.server_id)
|
@ -0,0 +1,107 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression import parent_node_dict
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as servers_utils
|
||||
import json
|
||||
|
||||
|
||||
class ServersConnectTestCase(BaseTestGenerator):
|
||||
"""
|
||||
This class will fetch added servers under default server group
|
||||
by response code.
|
||||
"""
|
||||
|
||||
scenarios = utils.generate_scenarios('connect_server',
|
||||
servers_utils.test_cases)
|
||||
|
||||
def get_ssh_tunnel(self):
|
||||
print("in_get_ssh")
|
||||
self.server['use_ssh_tunnel'] = 1
|
||||
self.server['tunnel_host'] = '127.0.0.1'
|
||||
self.server['tunnel_port'] = 22
|
||||
self.server['tunnel_username'] = 'user'
|
||||
if self.with_password:
|
||||
self.server['tunnel_authentication'] = 0
|
||||
else:
|
||||
self.server['tunnel_authentication'] = 1
|
||||
self.server['tunnel_identity_file'] = 'pkey_rsa'
|
||||
|
||||
if self.save_password:
|
||||
self.server['tunnel_password'] = '123456'
|
||||
|
||||
def setUp(self):
|
||||
"""This function add the server to test the GET API"""
|
||||
|
||||
self.server_id = utils.create_server(self.server)
|
||||
server_dict = {"server_id": self.server_id}
|
||||
utils.write_node_info("sid", server_dict)
|
||||
|
||||
def get_server_connection(self, server_id):
|
||||
return self.tester.get(self.url + str(utils.SERVER_GROUP) + '/' +
|
||||
str(server_id),
|
||||
follow_redirects=True)
|
||||
|
||||
def server_disonnect(self, server_id):
|
||||
return self.tester.delete(self.url + str(utils.SERVER_GROUP) + '/' +
|
||||
str(server_id))
|
||||
|
||||
def connect_to_server(self, url):
|
||||
return self.tester.post(
|
||||
url,
|
||||
data=json.dumps(self.server),
|
||||
content_type='html/json'
|
||||
)
|
||||
|
||||
def add_server_details(self, url):
|
||||
return self.tester.post(
|
||||
url,
|
||||
data=str(self.test_data),
|
||||
content_type='html/json'
|
||||
)
|
||||
|
||||
def runTest(self):
|
||||
""" This function will fetch the added servers to object browser. """
|
||||
server_id = parent_node_dict["server"][-1]["server_id"]
|
||||
if not server_id:
|
||||
raise Exception("Server not found to test GET API")
|
||||
response = None
|
||||
if self.is_positive_test:
|
||||
if hasattr(self, 'disconnect'):
|
||||
if hasattr(self, 'wrong_server_id'):
|
||||
server_id = 99999
|
||||
response = self.server_disonnect(server_id)
|
||||
elif hasattr(self, "connect"):
|
||||
url = self.url + '{0}/{1}'.format(
|
||||
utils.SERVER_GROUP,
|
||||
self.server_id)
|
||||
self.server['password'] = self.server['db_password']
|
||||
response = self.connect_to_server(url)
|
||||
elif hasattr(self, 'restore_point') or hasattr(self,
|
||||
'change_password'):
|
||||
connect_url = '/browser/server/connect/{0}/{1}'.format(
|
||||
utils.SERVER_GROUP,
|
||||
self.server_id)
|
||||
url = self.url + '{0}/{1}'.format(
|
||||
utils.SERVER_GROUP,
|
||||
self.server_id)
|
||||
|
||||
self.connect_to_server(connect_url)
|
||||
response = self.add_server_details(url)
|
||||
else:
|
||||
response = self.get_server_connection(server_id)
|
||||
|
||||
self.assertEquals(response.status_code,
|
||||
self.expected_data["status_code"])
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite """
|
||||
utils.delete_server_with_api(self.tester, self.server_id)
|
@ -0,0 +1,52 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import json
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as servers_utils
|
||||
|
||||
|
||||
class IsPasswordSaved(BaseTestGenerator):
|
||||
""" This class will test the save password functionality. """
|
||||
|
||||
scenarios = utils.generate_scenarios('is_password_saved',
|
||||
servers_utils.test_cases)
|
||||
|
||||
def setUp(self):
|
||||
self.server_id = utils.create_server(self.server)
|
||||
server_dict = {"server_id": self.server_id}
|
||||
utils.write_node_info("sid", server_dict)
|
||||
|
||||
def runTest(self):
|
||||
"""This function will execute the connect server APIs"""
|
||||
response = self.tester.post(
|
||||
self.url + str(utils.SERVER_GROUP) + '/' + str(self.server_id),
|
||||
data=dict(
|
||||
password=self.server['db_password'],
|
||||
save_password='on'),
|
||||
follow_redirects=True)
|
||||
|
||||
expected_status_code = self.expected_data["status_code"]
|
||||
actual_status_code = response.status_code
|
||||
self.assertEquals(actual_status_code, expected_status_code)
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
|
||||
expected_message = self.expected_data["message"]
|
||||
actual_message = response_data["info"]
|
||||
self.assertEquals(actual_message, expected_message)
|
||||
|
||||
expected_is_password_saved = self.test_data["is_password_saved"]
|
||||
actual_is_password_saved = response_data["data"]["is_password_saved"]
|
||||
self.assertEquals(actual_is_password_saved, expected_is_password_saved)
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite """
|
||||
utils.delete_server_with_api(self.tester, self.server_id)
|
@ -1,86 +0,0 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import json
|
||||
import copy
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
|
||||
|
||||
class ServersAddTestCase(BaseTestGenerator):
|
||||
""" This class will add the servers under default server group. """
|
||||
|
||||
scenarios = [
|
||||
# Fetch the default url for server object
|
||||
('Default Server Node url', dict(url='/browser/server/obj/'))
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def runTest(self):
|
||||
""" This function will add the server under default server group."""
|
||||
url = "{0}{1}/".format(self.url, utils.SERVER_GROUP)
|
||||
response = self.tester.post(url, data=json.dumps(self.server),
|
||||
content_type='html/json')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
self.server_id = response_data['node']['_id']
|
||||
server_dict = {"server_id": int(self.server_id)}
|
||||
utils.write_node_info("sid", server_dict)
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite """
|
||||
utils.delete_server_with_api(self.tester, self.server_id)
|
||||
|
||||
|
||||
class AddServersWithSavePasswordTestCase(BaseTestGenerator):
|
||||
""" This class will add the servers under default server group. """
|
||||
|
||||
scenarios = [
|
||||
# Fetch the default url for server object
|
||||
('Add server with password and save password to true',
|
||||
dict(url='/browser/server/obj/', with_pwd=True, with_save=True)),
|
||||
('Add server with password and save password to false',
|
||||
dict(url='/browser/server/obj/', with_pwd=True, with_save=False)),
|
||||
('Add server without password and save password to true',
|
||||
dict(url='/browser/server/obj/', with_pwd=False, with_save=True)),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def runTest(self):
|
||||
""" This function will add the server under default server group."""
|
||||
url = "{0}{1}/".format(self.url, utils.SERVER_GROUP)
|
||||
_server = copy.deepcopy(self.server)
|
||||
# Update the flag as required
|
||||
_server['save_password'] = self.with_save
|
||||
if not self.with_pwd:
|
||||
# Remove the password from server object
|
||||
del _server['db_password']
|
||||
|
||||
response = self.tester.post(url, data=json.dumps(_server),
|
||||
content_type='html/json')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
self.server_id = response_data['node']['_id']
|
||||
server_dict = {"server_id": int(self.server_id)}
|
||||
# Fetch the node info to check if password was saved or not
|
||||
response = self.tester.get(self.url.replace('obj', 'nodes') +
|
||||
str(utils.SERVER_GROUP) + '/' +
|
||||
str(self.server_id),
|
||||
follow_redirects=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTrue('is_password_saved' in response.json['result'])
|
||||
utils.write_node_info("sid", server_dict)
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite """
|
||||
utils.delete_server_with_api(self.tester, self.server_id)
|
@ -9,15 +9,14 @@
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as servers_utils
|
||||
|
||||
|
||||
class ServerDeleteTestCase(BaseTestGenerator):
|
||||
""" This class will delete the last server present under tree node."""
|
||||
|
||||
scenarios = [
|
||||
# Fetching the default url for server node
|
||||
('Default Server Node url', dict(url='/browser/server/obj/'))
|
||||
]
|
||||
scenarios = utils.generate_scenarios('delete_server',
|
||||
servers_utils.test_cases)
|
||||
|
||||
def setUp(self):
|
||||
"""This function add the server to test the DELETE API"""
|
||||
|
@ -10,6 +10,8 @@
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression import parent_node_dict
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as servers_utils
|
||||
import json
|
||||
|
||||
|
||||
class ServersGetTestCase(BaseTestGenerator):
|
||||
@ -18,26 +20,50 @@ class ServersGetTestCase(BaseTestGenerator):
|
||||
by response code.
|
||||
"""
|
||||
|
||||
scenarios = [
|
||||
# Fetch the default url for server node
|
||||
('Default Server Node url', dict(url='/browser/server/obj/'))
|
||||
]
|
||||
scenarios = utils.generate_scenarios('get_server',
|
||||
servers_utils.test_cases)
|
||||
|
||||
def setUp(self):
|
||||
"""This function add the server to test the GET API"""
|
||||
self.server_id = utils.create_server(self.server)
|
||||
if hasattr(self, 'shared'):
|
||||
|
||||
self.server['shared'] = True
|
||||
url = "{0}{1}/".format(self.url, utils.SERVER_GROUP)
|
||||
response = self.tester.post(
|
||||
url,
|
||||
data=json.dumps(self.server),
|
||||
content_type='html/json'
|
||||
)
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
self.server_id = response_data['node']['_id']
|
||||
else:
|
||||
self.server_id = utils.create_server(self.server)
|
||||
server_dict = {"server_id": self.server_id}
|
||||
utils.write_node_info("sid", server_dict)
|
||||
|
||||
def get_server(self, server_id):
|
||||
return self.tester.get(self.url + str(utils.SERVER_GROUP) + '/' +
|
||||
str(server_id),
|
||||
follow_redirects=True)
|
||||
|
||||
def runTest(self):
|
||||
""" This function will fetch the added servers to object browser. """
|
||||
server_id = parent_node_dict["server"][-1]["server_id"]
|
||||
if not server_id:
|
||||
raise Exception("Server not found to test GET API")
|
||||
response = self.tester.get(self.url + str(utils.SERVER_GROUP) + '/' +
|
||||
str(server_id),
|
||||
follow_redirects=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response = None
|
||||
if self.is_positive_test:
|
||||
if hasattr(self, "incorrect_server_id"):
|
||||
server_id = 9999
|
||||
if hasattr(self, "server_list"):
|
||||
server_id = ''
|
||||
if hasattr(self, "server_node"):
|
||||
server_id = ''
|
||||
if hasattr(self, 'shared'):
|
||||
server_id = self.server_id
|
||||
response = self.get_server(server_id)
|
||||
self.assertEquals(response.status_code,
|
||||
self.expected_data["status_code"])
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite """
|
||||
|
@ -11,32 +11,61 @@ import json
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as servers_utils
|
||||
|
||||
|
||||
class ServerUpdateTestCase(BaseTestGenerator):
|
||||
""" This class will update server's comment field. """
|
||||
|
||||
scenarios = [
|
||||
# Fetching the default url for server node
|
||||
('Default Server Node url', dict(url='/browser/server/obj/'))
|
||||
]
|
||||
scenarios = utils.generate_scenarios('update_server',
|
||||
servers_utils.test_cases)
|
||||
|
||||
def setUp(self):
|
||||
"""This function add the server to test the PUT API"""
|
||||
self.server_id = utils.create_server(self.server)
|
||||
if hasattr(self, 'clear_save_password'):
|
||||
self.server['save_password'] = 1
|
||||
create_server_url = "/browser/server/obj/{0}/".format(
|
||||
utils.SERVER_GROUP)
|
||||
|
||||
self.server_id = \
|
||||
servers_utils.create_server_with_api(self, create_server_url)
|
||||
server_dict = {"server_id": self.server_id}
|
||||
utils.write_node_info("sid", server_dict)
|
||||
|
||||
def update_server(self):
|
||||
return self.tester.put(
|
||||
self.url + str(utils.SERVER_GROUP) + '/' +
|
||||
str(self.server_id), data=json.dumps(self.test_data),
|
||||
content_type='html/json')
|
||||
|
||||
def connect_to_server(self, url):
|
||||
return self.tester.post(
|
||||
url,
|
||||
data=json.dumps(self.server),
|
||||
content_type='html/json'
|
||||
)
|
||||
|
||||
def runTest(self):
|
||||
"""This function update the server details"""
|
||||
if not self.server_id:
|
||||
raise Exception("No server to update.")
|
||||
data = {"comment": self.server['comment'], "id": self.server_id}
|
||||
put_response = self.tester.put(
|
||||
self.url + str(utils.SERVER_GROUP) + '/' +
|
||||
str(self.server_id), data=json.dumps(data),
|
||||
content_type='html/json')
|
||||
self.assertEqual(put_response.status_code, 200)
|
||||
if 'comment' in self.test_data:
|
||||
self.test_data["comment"] = self.server['comment']
|
||||
self.test_data["id"] = self.server_id
|
||||
if self.is_positive_test:
|
||||
if hasattr(self, 'server_connected'):
|
||||
url = '/browser/server/connect/{0}/{1}'.format(
|
||||
utils.SERVER_GROUP,
|
||||
self.server_id)
|
||||
self.server['password'] = self.server['db_password']
|
||||
self.connect_to_server(url)
|
||||
put_response = self.update_server()
|
||||
else:
|
||||
if hasattr(self, 'wrong_server_id'):
|
||||
self.server_id = 9999
|
||||
put_response = self.update_server()
|
||||
self.assertEquals(put_response.status_code,
|
||||
self.expected_data["status_code"])
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite"""
|
||||
|
@ -0,0 +1,134 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression import parent_node_dict
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as servers_utils
|
||||
import json
|
||||
from regression.test_setup import config_data
|
||||
from regression.python_test_utils.test_utils import \
|
||||
create_user_wise_test_client
|
||||
import config
|
||||
|
||||
test_user_details = config_data[
|
||||
'pgAdmin4_test_non_admin_credentials']
|
||||
|
||||
|
||||
class SharedServersGetTestCase(BaseTestGenerator):
|
||||
"""
|
||||
This class will fetch added servers under default server group
|
||||
by response code.
|
||||
"""
|
||||
|
||||
scenarios = utils.generate_scenarios('get_shared_server',
|
||||
servers_utils.test_cases)
|
||||
|
||||
def setUp(self):
|
||||
"""This function add the server to test the GET API"""
|
||||
|
||||
if config.SERVER_MODE is False:
|
||||
self.skipTest(
|
||||
"Can not run shared servers test cases in the SERVER mode."
|
||||
)
|
||||
self.server['shared'] = True
|
||||
url = "{0}{1}/".format(self.url, utils.SERVER_GROUP)
|
||||
response = self.tester.post(
|
||||
url,
|
||||
data=json.dumps(self.server),
|
||||
content_type='html/json'
|
||||
)
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
self.server_id = response_data['node']['_id']
|
||||
|
||||
server_dict = {"server_id": self.server_id}
|
||||
utils.write_node_info("sid", server_dict)
|
||||
|
||||
def get_server(self, server_id):
|
||||
return self.tester.get(self.url + str(utils.SERVER_GROUP) + '/' +
|
||||
str(server_id),
|
||||
follow_redirects=True)
|
||||
|
||||
@create_user_wise_test_client(test_user_details)
|
||||
def runTest(self):
|
||||
""" This function will fetch the added servers to object browser. """
|
||||
if not self.server_id:
|
||||
raise Exception("Server not found to test GET API")
|
||||
response = None
|
||||
if self.is_positive_test:
|
||||
if hasattr(self, 'no_server_id'):
|
||||
if hasattr(self, 'server_list'):
|
||||
self.url = '/browser/server/nodes/'
|
||||
server_id = ''
|
||||
response = self.get_server(server_id)
|
||||
else:
|
||||
response = self.get_server(self.server_id)
|
||||
self.assertEquals(response.status_code,
|
||||
self.expected_data["status_code"])
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite """
|
||||
utils.delete_server_with_api(self.tester, self.server_id)
|
||||
|
||||
|
||||
class SharedServerUpdateTestCase(BaseTestGenerator):
|
||||
""" This class will update server's comment field. """
|
||||
|
||||
scenarios = utils.generate_scenarios('update_shared_server',
|
||||
servers_utils.test_cases)
|
||||
|
||||
def setUp(self):
|
||||
"""This function add the server to test the PUT API"""
|
||||
if config.SERVER_MODE is False:
|
||||
self.skipTest(
|
||||
"Can not run shared servers test cases in the Desktop mode."
|
||||
)
|
||||
self.server['shared'] = True
|
||||
if hasattr(self, 'clear_save_password'):
|
||||
self.server['save_password'] = 1
|
||||
create_server_url = "/browser/server/obj/{0}/".format(
|
||||
utils.SERVER_GROUP)
|
||||
|
||||
self.server_id = \
|
||||
servers_utils.create_server_with_api(self, create_server_url)
|
||||
server_dict = {"server_id": self.server_id}
|
||||
utils.write_node_info("sid", server_dict)
|
||||
|
||||
def update_server(self):
|
||||
return self.tester.put(
|
||||
self.url + str(utils.SERVER_GROUP) + '/' +
|
||||
str(self.server_id), data=json.dumps(self.test_data),
|
||||
content_type='html/json')
|
||||
|
||||
def connect_to_server(self, url):
|
||||
return self.tester.post(
|
||||
url,
|
||||
data=json.dumps(self.server),
|
||||
content_type='html/json'
|
||||
)
|
||||
|
||||
def runTest(self):
|
||||
"""This function update the server details"""
|
||||
if not self.server_id:
|
||||
raise Exception("No server to update.")
|
||||
if 'comment' in self.test_data:
|
||||
self.test_data["comment"] = self.server['comment']
|
||||
self.test_data["id"] = self.server_id
|
||||
if self.is_positive_test:
|
||||
put_response = self.update_server()
|
||||
else:
|
||||
if hasattr(self, 'wrong_server_id'):
|
||||
self.server_id = 9999
|
||||
put_response = self.update_server()
|
||||
self.assertEquals(put_response.status_code,
|
||||
self.expected_data["status_code"])
|
||||
|
||||
def tearDown(self):
|
||||
"""This function delete the server from SQLite"""
|
||||
utils.delete_server_with_api(self.tester, self.server_id)
|
52
web/pgadmin/browser/server_groups/servers/tests/utils.py
Normal file
52
web/pgadmin/browser/server_groups/servers/tests/utils.py
Normal file
@ -0,0 +1,52 @@
|
||||
import os
|
||||
import json
|
||||
import sqlite3
|
||||
import config
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
|
||||
|
||||
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||
with open(CURRENT_PATH + "/servers_test_data.json") as data_file:
|
||||
test_cases = json.load(data_file)
|
||||
|
||||
|
||||
def create_server(server, SERVER_GROUP):
|
||||
"""This function is used to create server"""
|
||||
try:
|
||||
conn = sqlite3.connect(config.TEST_SQLITE_PATH)
|
||||
# Create the server
|
||||
cur = conn.cursor()
|
||||
if 'shared' not in server:
|
||||
server['shared'] = False
|
||||
server_details = (1, SERVER_GROUP, server['name'], server['host'],
|
||||
server['port'], server['db'], server['username'],
|
||||
server['role'], server['sslmode'], server['comment'],
|
||||
server['shared'])
|
||||
cur.execute('INSERT INTO server (user_id, servergroup_id, name, host, '
|
||||
'port, maintenance_db, username, role, ssl_mode,'
|
||||
' comment, shared) VALUES (?,?,?,?,?,?,?,?,?,?,?)',
|
||||
server_details)
|
||||
server_id = cur.lastrowid
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
type = utils.get_server_type(server)
|
||||
server['type'] = type
|
||||
|
||||
return server_id
|
||||
except Exception as exception:
|
||||
raise Exception("Error while creating server. %s" % exception)
|
||||
|
||||
|
||||
def create_server_with_api(self, url):
|
||||
try:
|
||||
response = self.tester.post(
|
||||
url,
|
||||
data=json.dumps(self.server),
|
||||
content_type='html/json'
|
||||
)
|
||||
response_data = json.loads(response.data.decode('utf-8'))
|
||||
server_id = response_data['node']['_id']
|
||||
return server_id
|
||||
except Exception as exception:
|
||||
raise Exception("Error while creating server. %s" % exception)
|
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#F2F2F2;}
|
||||
.st1{fill:#9BA5B0;}
|
||||
.st2{fill:none;stroke:#9BA5B0;stroke-width:0.75;stroke-miterlimit:1;}
|
||||
.st3{fill:#F7F7F7;}
|
||||
.st4{fill:#354A5F;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M6.7,2.1h4.6c0.6,0,1.1,0.5,1.1,1.1V4c0,0.6-0.5,1.1-1.1,1.1H6.7C6.1,5.1,5.6,4.6,5.6,4V3.2
|
||||
C5.6,2.6,6.1,2.1,6.7,2.1z"/>
|
||||
<path class="st1" d="M11.3,2.5c0.4,0,0.8,0.3,0.8,0.8v0.8c0,0.4-0.3,0.8-0.8,0.8H6.7C6.3,4.8,6,4.5,6,4.1V3.2
|
||||
c0-0.4,0.3-0.7,0.8-0.7H11.3 M11.3,1.7H6.7c-0.8,0-1.5,0.7-1.5,1.5V4c0,0.8,0.7,1.5,1.5,1.5h4.6c0.8,0,1.5-0.7,1.5-1.5V3.2
|
||||
C12.8,2.4,12.1,1.7,11.3,1.7L11.3,1.7z"/>
|
||||
<line class="st2" x1="8.9" y1="3.6" x2="6.8" y2="3.6"/>
|
||||
<path class="st0" d="M6.7,5.2h4.6c0.6,0,1.1,0.5,1.1,1.1v0.8c0,0.6-0.5,1.1-1.1,1.1H6.7c-0.6,0-1.1-0.5-1.1-1.1V6.3
|
||||
C5.6,5.7,6.1,5.2,6.7,5.2z"/>
|
||||
<path class="st1" d="M11.3,5.6c0.4,0,0.8,0.3,0.8,0.8v0.8c0,0.4-0.3,0.8-0.8,0.8H6.7C6.3,7.9,6,7.6,6,7.1V6.3
|
||||
c0-0.4,0.3-0.7,0.8-0.7L11.3,5.6 M11.3,4.8H6.7c-0.8,0-1.5,0.7-1.5,1.5v0.8c0,0.8,0.7,1.5,1.5,1.5h4.6c0.8,0,1.5-0.7,1.5-1.5V6.3
|
||||
C12.8,5.5,12.1,4.8,11.3,4.8L11.3,4.8z"/>
|
||||
<line class="st2" x1="8.9" y1="6.7" x2="6.8" y2="6.7"/>
|
||||
<path class="st0" d="M6.7,8.3h4.6c0.6,0,1.1,0.5,1.1,1.1v0.9c0,0.6-0.5,1.1-1.1,1.1l0,0H6.7c-0.6,0-1.1-0.5-1.1-1.1l0,0V9.4
|
||||
C5.6,8.8,6.1,8.3,6.7,8.3L6.7,8.3z"/>
|
||||
<path class="st1" d="M11.3,8.7c0.4,0,0.8,0.3,0.8,0.8v0.8c0,0.4-0.3,0.8-0.8,0.8H6.7C6.3,11,6,10.7,6,10.3V9.4C6,9,6.3,8.7,6.7,8.7
|
||||
H11.3 M11.3,7.9H6.7c-0.8,0-1.5,0.7-1.5,1.5v0.8c0,0.8,0.7,1.5,1.5,1.5h4.6c0.8,0,1.5-0.7,1.5-1.5V9.4C12.8,8.6,12.1,7.9,11.3,7.9z
|
||||
"/>
|
||||
<line class="st2" x1="8.9" y1="9.8" x2="6.8" y2="9.8"/>
|
||||
</g>
|
||||
<path class="st3" d="M11.6,10.5c-0.6,0.3-0.8,0.1-1.1-0.2c-0.1-0.2-0.3-0.4-0.6-0.5L7.1,8.5c-0.3-0.1-0.7-0.2-1-0.2
|
||||
C5.1,8.1,4.2,8.4,3.4,9L2,10.1v2.7h0.9v-0.2l3.7,1.8c0.4,0.2,0.7,0.3,1.1,0.3c0.3,0,0.7-0.1,1-0.2l6.1-2.6c0.3-0.1,0.6-0.4,0.7-0.7
|
||||
c0.1-0.3,0.1-0.7,0-1c-0.3-0.6-1.1-0.9-1.7-0.6l-0.4,0.2L11.6,10.5"/>
|
||||
<path class="st4" d="M15.5,10.2c-0.3-0.6-1.1-0.9-1.7-0.6l-0.4,0.2l-1.8,0.8l0.3,0.8l1.8-0.8l0.4-0.2c0.2-0.1,0.5,0,0.6,0.2
|
||||
c0.1,0.1,0.1,0.2,0,0.3c0,0.1-0.1,0.2-0.2,0.2l-6.1,2.6c-0.5,0.2-1,0.2-1.4,0l-4.1-2v-1.2l1-0.8C4.5,9.2,5.2,9,6,9.1
|
||||
c0.3,0,0.6,0.1,0.8,0.2l2.8,1.2c0.1,0,0.1,0.1,0.2,0.2c0.1,0.1,0.1,0.3,0,0.4c0,0,0,0.1-0.1,0.1c-0.1,0.1-0.3,0.2-0.5,0.1l-2.2-1
|
||||
l-0.4,0.8l2.2,1c0.2,0.1,0.4,0.1,0.5,0.1c0.4,0,0.7-0.2,1-0.4c0.1-0.1,0.2-0.2,0.2-0.3c0.2-0.4,0.1-0.9-0.1-1.2
|
||||
c-0.1-0.2-0.3-0.4-0.6-0.5L7.1,8.5c-0.3-0.1-0.7-0.2-1-0.2C5.1,8.1,4.2,8.4,3.4,9L2.9,9.4V9.3c0-0.6-0.4-1-1-1H1.4c-0.6,0-1,0.4-1,1
|
||||
v4.1c0,0.6,0.4,1,1,1h0.5c0.6,0,1-0.4,1-1v-0.6l0,0v-0.2l3.7,1.8c0.4,0.2,0.7,0.3,1.1,0.3c0.3,0,0.7-0.1,1-0.2l6.1-2.6
|
||||
c0.3-0.1,0.6-0.4,0.7-0.7C15.7,10.9,15.7,10.5,15.5,10.2z M1.9,13.4H1.4V9.3h0.5V13.4z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.0 KiB |
@ -9,8 +9,8 @@
|
||||
|
||||
define('pgadmin.node.server_group', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.browser.node',
|
||||
], function(gettext, url_for, $, _, pgAdmin) {
|
||||
'sources/pgadmin', 'pgadmin.user_management.current_user', 'pgadmin.browser', 'pgadmin.browser.node',
|
||||
], function(gettext, url_for, $, _, pgAdmin, current_user) {
|
||||
|
||||
if (!pgAdmin.Browser.Nodes['server_group']) {
|
||||
pgAdmin.Browser.Nodes['server_group'] = pgAdmin.Browser.Node.extend({
|
||||
@ -39,14 +39,25 @@ define('pgadmin.node.server_group', [
|
||||
defaults: {
|
||||
id: undefined,
|
||||
name: null,
|
||||
user_id: undefined,
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
id: 'id', label: gettext('ID'), type: 'int', group: null,
|
||||
mode: ['properties'],
|
||||
visible: function(model){
|
||||
if (model.attributes.user_id != current_user.id && !current_user.is_admin)
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
},{
|
||||
id: 'name', label: gettext('Name'), type: 'text', group: null,
|
||||
mode: ['properties', 'edit', 'create'],
|
||||
disabled: function(model){
|
||||
if (model.attributes.user_id != current_user.id && !_.isUndefined(model.attributes.user_id))
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
},
|
||||
],
|
||||
validate: function() {
|
||||
@ -69,7 +80,12 @@ define('pgadmin.node.server_group', [
|
||||
return null;
|
||||
},
|
||||
}),
|
||||
canDrop: function(itemData) { return itemData.can_delete; },
|
||||
|
||||
canDrop: function(itemData) {
|
||||
var serverOwner = itemData.user_id;
|
||||
if (serverOwner != current_user.id)
|
||||
return false;
|
||||
return true; },
|
||||
dropAsRemove: true,
|
||||
canDelete: function(i) {
|
||||
var s = pgAdmin.Browser.tree.siblings(i, true);
|
||||
|
@ -0,0 +1,17 @@
|
||||
.icon-server_group {
|
||||
background-image: url('{{ url_for('NODE-server_group.static', filename='img/server_group.svg') }}') !important;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 20px !important;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
.icon-server_group_shared {
|
||||
background-image: url('{{ url_for('NODE-server_group.static', filename='img/server_group_shared.svg') }}') !important;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 20px !important;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
@ -19,7 +19,7 @@ define('pgadmin.browser', [
|
||||
'pgadmin.browser.error', 'pgadmin.browser.frame',
|
||||
'pgadmin.browser.node', 'pgadmin.browser.collection', 'pgadmin.browser.activity',
|
||||
'sources/codemirror/addon/fold/pgadmin-sqlfoldcode',
|
||||
'pgadmin.browser.keyboard', 'sources/tree/pgadmin_tree_save_state',
|
||||
'pgadmin.browser.keyboard', 'sources/tree/pgadmin_tree_save_state','jquery.acisortable', 'jquery.acifragment',
|
||||
], function(
|
||||
tree,
|
||||
gettext, url_for, require, $, _,
|
||||
|
@ -44,6 +44,7 @@ define('pgadmin.browser.utils',
|
||||
|
||||
pgAdmin['csrf_token_header'] = '{{ current_app.config.get('WTF_CSRF_HEADERS')[0] }}';
|
||||
pgAdmin['csrf_token'] = '{{ csrf_token() }}';
|
||||
pgAdmin['server_mode'] = '{{ current_app.config.get('SERVER_MODE') }}';
|
||||
|
||||
/* Get the inactivity related config */
|
||||
pgAdmin['user_inactivity_timeout'] = {{ current_app.config.get('USER_INACTIVITY_TIMEOUT') }};
|
||||
|
@ -29,7 +29,7 @@ from flask_sqlalchemy import SQLAlchemy
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
SCHEMA_VERSION = 25
|
||||
SCHEMA_VERSION = 26
|
||||
|
||||
##########################################################################
|
||||
#
|
||||
@ -173,6 +173,7 @@ class Server(db.Model):
|
||||
)
|
||||
tunnel_identity_file = db.Column(db.String(64), nullable=True)
|
||||
tunnel_password = db.Column(db.String(64), nullable=True)
|
||||
shared = db.Column(db.Boolean(), nullable=False)
|
||||
|
||||
|
||||
class ModulePreference(db.Model):
|
||||
@ -305,3 +306,88 @@ class Database(db.Model):
|
||||
nullable=False,
|
||||
primary_key=True
|
||||
)
|
||||
|
||||
|
||||
class SharedServer(db.Model):
|
||||
"""Define a shared Postgres server"""
|
||||
|
||||
__tablename__ = 'sharedserver'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
user_id = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('user.id')
|
||||
)
|
||||
server_owner = db.Column(
|
||||
db.String(128),
|
||||
db.ForeignKey('user.username')
|
||||
)
|
||||
servergroup_id = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('servergroup.id'),
|
||||
nullable=False
|
||||
)
|
||||
name = db.Column(db.String(128), nullable=False)
|
||||
host = db.Column(db.String(128), nullable=True)
|
||||
hostaddr = db.Column(db.String(128), nullable=True)
|
||||
port = db.Column(
|
||||
db.Integer(),
|
||||
db.CheckConstraint('port >= 1 AND port <= 65534'),
|
||||
nullable=False)
|
||||
maintenance_db = db.Column(db.String(64), nullable=True)
|
||||
username = db.Column(db.String(64), nullable=False)
|
||||
password = db.Column(db.String(64), nullable=True)
|
||||
save_password = db.Column(
|
||||
db.Integer(),
|
||||
db.CheckConstraint('save_password >= 0 AND save_password <= 1'),
|
||||
nullable=False
|
||||
)
|
||||
role = db.Column(db.String(64), nullable=True)
|
||||
ssl_mode = db.Column(
|
||||
db.String(16),
|
||||
db.CheckConstraint(
|
||||
"ssl_mode IN ('allow', 'prefer', 'require', 'disable', "
|
||||
"'verify-ca', 'verify-full')"
|
||||
),
|
||||
nullable=False)
|
||||
comment = db.Column(db.String(1024), nullable=True)
|
||||
discovery_id = db.Column(db.String(128), nullable=True)
|
||||
servers = db.relationship(
|
||||
'ServerGroup',
|
||||
backref=db.backref('sharedserver', cascade="all, delete-orphan"),
|
||||
lazy='joined'
|
||||
)
|
||||
db_res = db.Column(db.Text(), nullable=True)
|
||||
passfile = db.Column(db.Text(), nullable=True)
|
||||
sslcert = db.Column(db.Text(), nullable=True)
|
||||
sslkey = db.Column(db.Text(), nullable=True)
|
||||
sslrootcert = db.Column(db.Text(), nullable=True)
|
||||
sslcrl = db.Column(db.Text(), nullable=True)
|
||||
sslcompression = db.Column(
|
||||
db.Integer(),
|
||||
db.CheckConstraint('sslcompression >= 0 AND sslcompression <= 1'),
|
||||
nullable=False
|
||||
)
|
||||
bgcolor = db.Column(db.Text(10), nullable=True)
|
||||
fgcolor = db.Column(db.Text(10), nullable=True)
|
||||
service = db.Column(db.Text(), nullable=True)
|
||||
connect_timeout = db.Column(db.Integer(), nullable=False)
|
||||
use_ssh_tunnel = db.Column(
|
||||
db.Integer(),
|
||||
db.CheckConstraint('use_ssh_tunnel >= 0 AND use_ssh_tunnel <= 1'),
|
||||
nullable=False
|
||||
)
|
||||
tunnel_host = db.Column(db.String(128), nullable=True)
|
||||
tunnel_port = db.Column(
|
||||
db.Integer(),
|
||||
db.CheckConstraint('port <= 65534'),
|
||||
nullable=True)
|
||||
tunnel_username = db.Column(db.String(64), nullable=True)
|
||||
tunnel_authentication = db.Column(
|
||||
db.Integer(),
|
||||
db.CheckConstraint('tunnel_authentication >= 0 AND '
|
||||
'tunnel_authentication <= 1'),
|
||||
nullable=False
|
||||
)
|
||||
tunnel_identity_file = db.Column(db.String(64), nullable=True)
|
||||
tunnel_password = db.Column(db.String(64), nullable=True)
|
||||
shared = db.Column(db.Boolean(), nullable=False)
|
||||
|
@ -23,6 +23,7 @@ from pgadmin.utils.ajax import success_return, \
|
||||
from pgadmin.utils.menu import MenuItem
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
from pgadmin.utils.constants import MIMETYPE_APP_JS
|
||||
from pgadmin.browser.server_groups import ServerGroupModule as sgm
|
||||
|
||||
MODULE_NAME = 'preferences'
|
||||
|
||||
@ -203,6 +204,7 @@ def save(pid):
|
||||
|
||||
res, msg = Preferences.save(
|
||||
data['mid'], data['category_id'], data['id'], data['value'])
|
||||
sgm.get_nodes(sgm)
|
||||
|
||||
if not res:
|
||||
return internal_server_error(errormsg=msg)
|
||||
|
@ -463,6 +463,7 @@ define('pgadmin.preferences', [
|
||||
}
|
||||
|
||||
if (e.button.text == gettext('Save')) {
|
||||
debugger;
|
||||
let requires_refresh = false;
|
||||
preferences.updateAll();
|
||||
|
||||
@ -477,6 +478,29 @@ define('pgadmin.preferences', [
|
||||
if(pref.name == 'theme') {
|
||||
requires_refresh = true;
|
||||
}
|
||||
|
||||
if(pref.name == 'hide_shared_server') {
|
||||
Alertify.confirm(
|
||||
gettext('Browser tree refresh required'),
|
||||
gettext('A browser tree refresh is required. Do you wish to refresh the tree?'),
|
||||
function() {
|
||||
pgAdmin.Browser.tree.destroy({
|
||||
success: function() {
|
||||
pgAdmin.Browser.initializeBrowserTree(pgAdmin.Browser);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
},
|
||||
function() {
|
||||
preferences.reset();
|
||||
changed = {};
|
||||
return true;
|
||||
}
|
||||
).set('labels', {
|
||||
ok: gettext('Refresh'),
|
||||
cancel: gettext('Later'),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if(requires_refresh) {
|
||||
|
@ -20,13 +20,14 @@ from flask_babelex import gettext
|
||||
from pgadmin.utils import PgAdminModule
|
||||
from pgadmin.utils.ajax import make_json_response, bad_request, \
|
||||
make_response as ajax_response, internal_server_error
|
||||
from pgadmin.model import Server
|
||||
from pgadmin.model import Server, SharedServer
|
||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||
from pgadmin.tools.schema_diff.model import SchemaDiffModel
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
from pgadmin.utils.constants import PREF_LABEL_DISPLAY, MIMETYPE_APP_JS
|
||||
from sqlalchemy import or_
|
||||
|
||||
MODULE_NAME = 'schema_diff'
|
||||
|
||||
@ -270,6 +271,7 @@ def servers():
|
||||
server id.
|
||||
"""
|
||||
res = {}
|
||||
auto_detected_server = None
|
||||
try:
|
||||
"""Return a JSON document listing the server groups for the user"""
|
||||
driver = get_driver(PG_DEFAULT_DRIVER)
|
||||
@ -277,7 +279,19 @@ def servers():
|
||||
from pgadmin.browser.server_groups.servers import\
|
||||
server_icon_and_background
|
||||
|
||||
for server in Server.query.filter_by(user_id=current_user.id):
|
||||
for server in Server.query.filter(
|
||||
or_(Server.user_id == current_user.id, Server.shared)):
|
||||
|
||||
shared_server = SharedServer.query.filter_by(
|
||||
name=server.name, user_id=current_user.id,
|
||||
servergroup_id=server.servergroup_id).first()
|
||||
|
||||
if server.discovery_id:
|
||||
auto_detected_server = server.name
|
||||
|
||||
if shared_server and shared_server.name == auto_detected_server:
|
||||
continue
|
||||
|
||||
manager = driver.connection_manager(server.id)
|
||||
conn = manager.connection()
|
||||
connected = conn.connected()
|
||||
|
@ -175,7 +175,7 @@ let SchemaDiffSelect2Control =
|
||||
let span = this.$el.find('.select2-selection .select2-selection__rendered span.wcTabIcon'),
|
||||
selSpan = this.$el.find('option:selected');
|
||||
|
||||
if (span.hasClass('icon-server-not-connected')) {
|
||||
if (span.hasClass('icon-server-not-connected') || span.hasClass('icon-shared-server-not-connected')) {
|
||||
let icon = (data.icon) ? data.icon : 'icon-pg';
|
||||
span.removeClass('icon-server-not-connected');
|
||||
span.addClass(icon);
|
||||
|
@ -66,6 +66,7 @@ class ServerManager(object):
|
||||
self.hostaddr = server.hostaddr
|
||||
self.port = server.port
|
||||
self.db = server.maintenance_db
|
||||
self.shared = server.shared
|
||||
self.did = None
|
||||
self.user = server.username
|
||||
self.password = server.password
|
||||
|
@ -36,6 +36,8 @@ from regression import test_setup
|
||||
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
|
||||
from functools import wraps
|
||||
|
||||
CURRENT_PATH = os.path.abspath(os.path.join(os.path.dirname(
|
||||
os.path.realpath(__file__)), "../"))
|
||||
|
||||
@ -1598,3 +1600,107 @@ def get_selenoid_browsers_list(arguments):
|
||||
list_of_browsers = test_setup.config_data['selenoid_config'][
|
||||
'browsers_list']
|
||||
return list_of_browsers
|
||||
|
||||
|
||||
def login_using_user_account(tester):
|
||||
"""
|
||||
This function login the test client username and password
|
||||
:param tester: test client
|
||||
:type tester: flask test client object
|
||||
:return: None
|
||||
"""
|
||||
username = tester.test_config_data['login_username']
|
||||
password = tester.test_config_data['login_password']
|
||||
response = tester.login(username, password)
|
||||
|
||||
if response.status_code != 302:
|
||||
print("Unable to login test client, email and password not found.",
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def logout_tester_account(tester):
|
||||
"""
|
||||
This function logout the test account
|
||||
:param tester: test client
|
||||
:type tester: flask test client object
|
||||
:return: None
|
||||
"""
|
||||
tester.logout()
|
||||
|
||||
|
||||
def create_user(user_details):
|
||||
try:
|
||||
conn = sqlite3.connect(config.TEST_SQLITE_PATH)
|
||||
# Create the server
|
||||
cur = conn.cursor()
|
||||
user_details = (
|
||||
user_details['login_username'], user_details['login_username'],
|
||||
user_details['login_password'], 1)
|
||||
|
||||
cur.execute(
|
||||
'select * from user where username = "%s"' % user_details[0])
|
||||
user = cur.fetchone()
|
||||
if user is None:
|
||||
cur.execute('INSERT INTO user (username, email, password, active) '
|
||||
'VALUES (?,?,?,?)', user_details)
|
||||
user_id = cur.lastrowid
|
||||
conn.commit()
|
||||
else:
|
||||
user_id = user[0]
|
||||
conn.close()
|
||||
|
||||
return user_id
|
||||
except Exception as exception:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
raise ("Error while creating server. %s" % exception)
|
||||
|
||||
|
||||
def get_test_user(self, user_details,
|
||||
is_api=True, create_conn=True):
|
||||
if user_details is None:
|
||||
return None, None
|
||||
|
||||
if is_api is True:
|
||||
|
||||
# Create test_client for this user, and login through it.
|
||||
test_client = self.app.test_client()
|
||||
user = create_user(user_details)
|
||||
if user is not None:
|
||||
test_client.test_config_data = dict({
|
||||
"login_username": user_details['login_username'],
|
||||
"login_password": user_details['login_password']
|
||||
})
|
||||
else:
|
||||
return "User not created"
|
||||
login_using_user_account(test_client)
|
||||
user = test_client
|
||||
|
||||
return user
|
||||
|
||||
|
||||
def create_user_wise_test_client(user):
|
||||
"""
|
||||
This function creates new test client and pem database connection as per
|
||||
provided user and execute the test cases.
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def multi_user_decorator(func):
|
||||
@wraps(func)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
main_tester = self.__class__.tester
|
||||
try:
|
||||
# Login with non-admin_user
|
||||
test_user = get_test_user(self, user)
|
||||
self.setTestClient(test_user)
|
||||
|
||||
# Call 'runTest' with new test client
|
||||
func(self, *args, **kwargs)
|
||||
finally:
|
||||
# Restore the original user and driver
|
||||
self.__class__.tester = main_tester
|
||||
|
||||
return wrapper
|
||||
|
||||
return multi_user_decorator
|
||||
|
@ -11,6 +11,11 @@
|
||||
"login_password": "PASSWORD",
|
||||
"login_username": "USER2@EXAMPLE.COM"
|
||||
},
|
||||
"pgAdmin4_test_non_admin_credentials": {
|
||||
"new_password": "NEWPASSWORD",
|
||||
"login_password": "PASSWORD",
|
||||
"login_username": "USER@EXAMPLE.COM"
|
||||
},
|
||||
"pgAdmin4_ldap_credentials": {
|
||||
"login_password": "PASSWORD",
|
||||
"login_username": "USERNAME"
|
||||
|
@ -110,6 +110,7 @@ def dump_servers(args):
|
||||
add_value(attr_dict, "Role", server.role)
|
||||
add_value(attr_dict, "SSLMode", server.ssl_mode)
|
||||
add_value(attr_dict, "Comment", server.comment)
|
||||
add_value(attr_dict, "Shared", server.shared)
|
||||
add_value(attr_dict, "DBRestriction", server.db_res)
|
||||
add_value(attr_dict, "PassFile", server.passfile)
|
||||
add_value(attr_dict, "SSLCert", server.sslcert)
|
||||
@ -258,6 +259,14 @@ def load_servers(args):
|
||||
for server in data["Servers"]:
|
||||
obj = data["Servers"][server]
|
||||
|
||||
# Check if server is shared.Won't import if user is non-admin
|
||||
if 'Shared' in obj \
|
||||
and obj['Shared'] and \
|
||||
not user.has_role("Administrator"):
|
||||
print("Can't import the server '%s' as it is shared " %
|
||||
obj["Name"])
|
||||
continue
|
||||
|
||||
# Get the group. Create if necessary
|
||||
group_id = next(
|
||||
(g.id for g in groups if g.name == obj["Group"]), -1)
|
||||
|
Loading…
Reference in New Issue
Block a user