2015-02-15 16:10:53 -06:00
|
|
|
##########################################################################
|
|
|
|
#
|
|
|
|
# pgAdmin 4 - PostgreSQL Tools
|
|
|
|
#
|
2017-01-04 07:33:32 -06:00
|
|
|
# Copyright (C) 2013 - 2017, The pgAdmin Development Team
|
2015-02-15 16:10:53 -06:00
|
|
|
# This software is released under the PostgreSQL Licence
|
|
|
|
#
|
|
|
|
##########################################################################
|
2016-01-18 08:48:14 -06:00
|
|
|
|
2016-06-21 08:12:14 -05:00
|
|
|
import json
|
2015-06-29 01:58:41 -05:00
|
|
|
from abc import ABCMeta, abstractmethod, abstractproperty
|
2016-06-21 08:12:14 -05:00
|
|
|
|
2016-06-21 08:21:06 -05:00
|
|
|
import six
|
2017-03-24 09:20:10 -05:00
|
|
|
from flask import current_app, render_template, url_for, make_response, flash,\
|
2017-06-12 01:31:22 -05:00
|
|
|
Response
|
2016-07-22 10:25:23 -05:00
|
|
|
from flask_babel import gettext
|
|
|
|
from flask_login import current_user
|
|
|
|
from flask_security import login_required
|
2016-01-18 07:27:40 -06:00
|
|
|
from flask_gravatar import Gravatar
|
2016-06-21 08:12:14 -05:00
|
|
|
from pgadmin.settings import get_setting
|
|
|
|
from pgadmin.utils import PgAdminModule
|
|
|
|
from pgadmin.utils.ajax import make_json_response
|
|
|
|
from pgadmin.utils.preferences import Preferences
|
2016-02-08 10:28:20 -06:00
|
|
|
|
|
|
|
import config
|
2016-06-21 08:12:14 -05:00
|
|
|
from pgadmin import current_blueprint
|
2016-02-08 10:28:20 -06:00
|
|
|
|
|
|
|
try:
|
|
|
|
import urllib.request as urlreq
|
|
|
|
except:
|
2016-03-17 23:38:32 -05:00
|
|
|
import urllib2 as urlreq
|
2015-02-15 16:10:53 -06:00
|
|
|
|
2015-06-29 01:58:41 -05:00
|
|
|
MODULE_NAME = 'browser'
|
|
|
|
|
2016-03-07 05:48:24 -06:00
|
|
|
|
2015-10-20 02:03:18 -05:00
|
|
|
class BrowserModule(PgAdminModule):
|
2016-03-07 05:48:24 -06:00
|
|
|
LABEL = gettext('Browser')
|
|
|
|
|
2015-06-29 01:58:41 -05:00
|
|
|
def get_own_stylesheets(self):
|
|
|
|
stylesheets = []
|
|
|
|
# Add browser stylesheets
|
|
|
|
for (endpoint, filename) in [
|
2017-02-24 11:01:20 -06:00
|
|
|
('static', 'vendor/codemirror/codemirror.css'),
|
|
|
|
('static', 'vendor/codemirror/addon/dialog/dialog.css'),
|
|
|
|
('static', 'vendor/jQuery-contextMenu/jquery.contextMenu.css' if current_app.debug
|
2017-02-27 06:39:13 -06:00
|
|
|
else 'vendor/jQuery-contextMenu/jquery.contextMenu.min.css'),
|
2017-02-24 11:01:20 -06:00
|
|
|
('static', 'vendor/wcDocker/wcDocker.css' if current_app.debug
|
|
|
|
else 'vendor/wcDocker/wcDocker.min.css'),
|
2016-06-21 08:21:06 -05:00
|
|
|
('browser.static', 'css/browser.css'),
|
2017-02-24 11:01:20 -06:00
|
|
|
('browser.static', 'vendor/aciTree/css/aciTree.css')
|
2016-06-21 08:21:06 -05:00
|
|
|
]:
|
2015-06-29 01:58:41 -05:00
|
|
|
stylesheets.append(url_for(endpoint, filename=filename))
|
|
|
|
stylesheets.append(url_for('browser.browser_css'))
|
|
|
|
return stylesheets
|
|
|
|
|
|
|
|
def get_own_javascripts(self):
|
2015-06-30 00:51:55 -05:00
|
|
|
scripts = list()
|
|
|
|
scripts.append({
|
|
|
|
'name': 'alertify',
|
2015-10-20 02:03:18 -05:00
|
|
|
'path': url_for(
|
2016-06-21 08:21:06 -05:00
|
|
|
'static',
|
2017-02-24 11:01:20 -06:00
|
|
|
filename='vendor/alertifyjs/alertify' if current_app.debug
|
|
|
|
else 'vendor/alertifyjs/alertify.min'
|
2016-06-21 08:21:06 -05:00
|
|
|
),
|
2015-06-30 00:51:55 -05:00
|
|
|
'exports': 'alertify',
|
|
|
|
'preloaded': True
|
2016-06-21 08:21:06 -05:00
|
|
|
})
|
2015-06-30 00:51:55 -05:00
|
|
|
scripts.append({
|
|
|
|
'name': 'jqueryui.position',
|
2015-10-20 02:03:18 -05:00
|
|
|
'path': url_for(
|
2016-03-17 14:41:22 -05:00
|
|
|
'static',
|
2017-02-24 11:01:20 -06:00
|
|
|
filename='vendor/jQuery-contextMenu/jquery.ui.position' if \
|
2016-06-21 08:21:06 -05:00
|
|
|
current_app.debug else \
|
2017-02-24 11:01:20 -06:00
|
|
|
'vendor/jQuery-contextMenu/jquery.ui.position.min'
|
2016-06-21 08:21:06 -05:00
|
|
|
),
|
2015-06-30 00:51:55 -05:00
|
|
|
'deps': ['jquery'],
|
|
|
|
'exports': 'jQuery.ui.position',
|
|
|
|
'preloaded': True
|
2016-06-21 08:21:06 -05:00
|
|
|
})
|
2015-06-30 00:51:55 -05:00
|
|
|
scripts.append({
|
|
|
|
'name': 'jquery.contextmenu',
|
2015-10-20 02:03:18 -05:00
|
|
|
'path': url_for(
|
2016-03-17 14:41:22 -05:00
|
|
|
'static',
|
2017-02-24 11:01:20 -06:00
|
|
|
filename='vendor/jQuery-contextMenu/jquery.contextMenu' if \
|
2016-06-21 08:21:06 -05:00
|
|
|
current_app.debug else \
|
2017-02-24 11:01:20 -06:00
|
|
|
'vendor/jQuery-contextMenu/jquery.contextMenu.min'
|
2016-06-21 08:21:06 -05:00
|
|
|
),
|
2015-06-30 00:51:55 -05:00
|
|
|
'deps': ['jquery', 'jqueryui.position'],
|
|
|
|
'exports': 'jQuery.contextMenu',
|
|
|
|
'preloaded': True
|
2016-06-21 08:21:06 -05:00
|
|
|
})
|
2015-06-30 00:51:55 -05:00
|
|
|
scripts.append({
|
|
|
|
'name': 'jquery.aciplugin',
|
2015-10-20 02:03:18 -05:00
|
|
|
'path': url_for(
|
2016-06-21 08:21:06 -05:00
|
|
|
'browser.static',
|
2017-02-24 11:01:20 -06:00
|
|
|
filename='vendor/aciTree/jquery.aciPlugin.min'
|
2016-06-21 08:21:06 -05:00
|
|
|
),
|
2015-06-30 00:51:55 -05:00
|
|
|
'deps': ['jquery'],
|
|
|
|
'exports': 'aciPluginClass',
|
|
|
|
'preloaded': True
|
2016-06-21 08:21:06 -05:00
|
|
|
})
|
2015-06-30 00:51:55 -05:00
|
|
|
scripts.append({
|
|
|
|
'name': 'jquery.acitree',
|
2015-10-20 02:03:18 -05:00
|
|
|
'path': url_for(
|
2016-06-21 08:21:06 -05:00
|
|
|
'browser.static',
|
2017-02-24 11:01:20 -06:00
|
|
|
filename='vendor/aciTree/jquery.aciTree' if
|
|
|
|
current_app.debug else 'vendor/aciTree/jquery.aciTree.min'
|
2016-06-21 08:21:06 -05:00
|
|
|
),
|
2015-06-30 00:51:55 -05:00
|
|
|
'deps': ['jquery', 'jquery.aciplugin'],
|
|
|
|
'exports': 'aciPluginClass.plugins.aciTree',
|
|
|
|
'preloaded': True
|
2016-06-21 08:21:06 -05:00
|
|
|
})
|
2016-03-24 03:53:16 -05:00
|
|
|
scripts.append({
|
|
|
|
'name': 'jquery.acisortable',
|
|
|
|
'path': url_for(
|
2016-06-21 08:21:06 -05:00
|
|
|
'browser.static',
|
2017-02-24 11:01:20 -06:00
|
|
|
filename='vendor/aciTree/jquery.aciSortable.min'
|
2016-06-21 08:21:06 -05:00
|
|
|
),
|
2016-03-24 03:53:16 -05:00
|
|
|
'deps': ['jquery', 'jquery.aciplugin'],
|
2016-04-19 13:16:50 -05:00
|
|
|
'exports': 'aciPluginClass.plugins.aciSortable',
|
|
|
|
'when': None,
|
|
|
|
'preloaded': True
|
2016-06-21 08:21:06 -05:00
|
|
|
})
|
2016-04-19 13:16:50 -05:00
|
|
|
scripts.append({
|
|
|
|
'name': 'jquery.acifragment',
|
|
|
|
'path': url_for(
|
2016-06-21 08:21:06 -05:00
|
|
|
'browser.static',
|
2017-02-24 11:01:20 -06:00
|
|
|
filename='vendor/aciTree/jquery.aciFragment.min'
|
2016-06-21 08:21:06 -05:00
|
|
|
),
|
2016-04-19 13:16:50 -05:00
|
|
|
'deps': ['jquery', 'jquery.aciplugin'],
|
|
|
|
'exports': 'aciPluginClass.plugins.aciFragment',
|
2016-03-24 03:53:16 -05:00
|
|
|
'when': None,
|
|
|
|
'preloaded': True
|
2016-06-21 08:21:06 -05:00
|
|
|
})
|
2015-06-30 00:51:55 -05:00
|
|
|
scripts.append({
|
|
|
|
'name': 'wcdocker',
|
2015-10-20 02:03:18 -05:00
|
|
|
'path': url_for(
|
2016-06-21 08:21:06 -05:00
|
|
|
'static',
|
2017-02-24 11:01:20 -06:00
|
|
|
filename='vendor/wcDocker/wcDocker' if current_app.debug
|
|
|
|
else 'vendor/wcDocker/wcDocker.min'
|
2016-06-21 08:21:06 -05:00
|
|
|
),
|
2015-06-30 00:51:55 -05:00
|
|
|
'deps': ['jquery.contextmenu'],
|
|
|
|
'exports': '',
|
|
|
|
'preloaded': True
|
2016-06-21 08:21:06 -05:00
|
|
|
})
|
2015-06-30 00:51:55 -05:00
|
|
|
|
2016-01-18 22:45:04 -06:00
|
|
|
scripts.append({
|
|
|
|
'name': 'pgadmin.browser.datamodel',
|
|
|
|
'path': url_for('browser.static', filename='js/datamodel'),
|
|
|
|
'preloaded': True
|
2016-06-21 08:21:06 -05:00
|
|
|
})
|
2016-01-18 22:45:04 -06:00
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
for name, script in [
|
2016-06-21 08:21:06 -05:00
|
|
|
['pgadmin.browser', 'js/browser'],
|
2017-06-12 01:31:22 -05:00
|
|
|
['pgadmin.browser.endpoints', 'js/endpoints'],
|
2016-06-21 08:21:06 -05:00
|
|
|
['pgadmin.browser.error', 'js/error']]:
|
2015-10-20 02:03:18 -05:00
|
|
|
scripts.append({
|
|
|
|
'name': name,
|
|
|
|
'path': url_for('browser.index') + script,
|
|
|
|
'preloaded': True
|
2016-06-21 08:21:06 -05:00
|
|
|
})
|
2015-06-30 00:51:55 -05:00
|
|
|
|
2016-01-18 22:45:04 -06:00
|
|
|
for name, script in [
|
2016-06-21 08:21:06 -05:00
|
|
|
['pgadmin.browser.node', 'js/node'],
|
|
|
|
['pgadmin.browser.messages', 'js/messages'],
|
|
|
|
['pgadmin.browser.collection', 'js/collection']]:
|
2016-01-18 22:45:04 -06:00
|
|
|
scripts.append({
|
|
|
|
'name': name,
|
|
|
|
'path': url_for('browser.index') + script,
|
|
|
|
'preloaded': True,
|
|
|
|
'deps': ['pgadmin.browser.datamodel']
|
2016-06-21 08:21:06 -05:00
|
|
|
})
|
2016-01-18 22:45:04 -06:00
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
for name, end in [
|
2016-06-21 08:21:06 -05:00
|
|
|
['pgadmin.browser.menu', 'js/menu'],
|
|
|
|
['pgadmin.browser.panel', 'js/panel'],
|
|
|
|
['pgadmin.browser.frame', 'js/frame']]:
|
2015-06-30 00:51:55 -05:00
|
|
|
scripts.append({
|
|
|
|
'name': name, 'path': url_for('browser.static', filename=end),
|
|
|
|
'preloaded': True})
|
|
|
|
|
2015-12-27 13:30:20 -06:00
|
|
|
scripts.append({
|
|
|
|
'name': 'pgadmin.browser.node.ui',
|
|
|
|
'path': url_for('browser.static', filename='js/node.ui'),
|
2017-09-11 00:46:58 -05:00
|
|
|
'when': 'server_group'
|
2016-06-21 08:21:06 -05:00
|
|
|
})
|
2015-12-27 13:30:20 -06:00
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
for module in self.submodules:
|
|
|
|
scripts.extend(module.get_own_javascripts())
|
2015-06-29 01:58:41 -05:00
|
|
|
return scripts
|
|
|
|
|
2016-03-07 05:48:24 -06:00
|
|
|
def register_preferences(self):
|
|
|
|
self.show_system_objects = self.preference.register(
|
|
|
|
'display', 'show_system_objects',
|
2016-08-19 05:40:19 -05:00
|
|
|
gettext("Show system objects?"), 'boolean', False,
|
2016-03-07 05:48:24 -06:00
|
|
|
category_label=gettext('Display')
|
2016-06-21 08:21:06 -05:00
|
|
|
)
|
2017-11-02 04:35:44 -05:00
|
|
|
self.table_row_count_threshold = self.preference.register(
|
|
|
|
'properties', 'table_row_count_threshold',
|
|
|
|
gettext("Count rows if estimated less than"), 'integer', 2000,
|
|
|
|
category_label=gettext('Properties')
|
|
|
|
)
|
2016-06-21 08:21:06 -05:00
|
|
|
|
2017-06-12 01:31:22 -05:00
|
|
|
def get_exposed_url_endpoints(self):
|
|
|
|
"""
|
|
|
|
Returns:
|
|
|
|
list: a list of url endpoints exposed to the client.
|
|
|
|
"""
|
|
|
|
return ['browser.index', 'browser.nodes']
|
|
|
|
|
2015-06-29 01:58:41 -05:00
|
|
|
blueprint = BrowserModule(MODULE_NAME, __name__)
|
|
|
|
|
2016-03-07 05:48:24 -06:00
|
|
|
|
2015-11-06 04:23:19 -06:00
|
|
|
@six.add_metaclass(ABCMeta)
|
2015-06-29 01:58:41 -05:00
|
|
|
class BrowserPluginModule(PgAdminModule):
|
|
|
|
"""
|
2016-03-07 05:48:24 -06:00
|
|
|
Abstract base class for browser submodules.
|
|
|
|
|
|
|
|
It helps to define the node for each and every node comes under the browser
|
|
|
|
tree. It makes sure every module comes under browser will have prefix
|
|
|
|
'/browser', and sets the 'url_prefix', 'static_url_path', etc.
|
|
|
|
|
|
|
|
Also, creates some of the preferences to be used by the node.
|
2015-06-29 01:58:41 -05:00
|
|
|
"""
|
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
browser_url_prefix = blueprint.url_prefix + '/'
|
2016-03-07 05:48:24 -06:00
|
|
|
SHOW_ON_BROWSER = True
|
2015-06-29 01:58:41 -05:00
|
|
|
|
|
|
|
def __init__(self, import_name, **kwargs):
|
2016-03-07 05:48:24 -06:00
|
|
|
"""
|
|
|
|
Construct a new 'BrowserPluginModule' object.
|
|
|
|
|
|
|
|
:param import_name: Name of the module
|
|
|
|
:param **kwargs: Extra parameters passed to the base class
|
|
|
|
pgAdminModule.
|
|
|
|
|
|
|
|
:return: returns nothing
|
|
|
|
|
|
|
|
It sets the url_prefix to based on the 'node_path'. And,
|
|
|
|
static_url_path to relative path to '/static'.
|
|
|
|
|
|
|
|
Every module extended from this will be identified as 'NODE-<type>'.
|
|
|
|
|
|
|
|
Also, create a preference 'show_node_<type>' to fetch whether it
|
|
|
|
can be shown in the browser or not. Also, refer to the browser-preference.
|
|
|
|
"""
|
2015-06-29 01:58:41 -05:00
|
|
|
kwargs.setdefault("url_prefix", self.node_path)
|
2015-06-30 00:51:55 -05:00
|
|
|
kwargs.setdefault("static_url_path", '/static')
|
2016-03-07 05:48:24 -06:00
|
|
|
|
|
|
|
self.browser_preference = None
|
|
|
|
self.pref_show_system_objects = None
|
|
|
|
self.pref_show_node = None
|
|
|
|
|
2015-10-20 02:03:18 -05:00
|
|
|
super(BrowserPluginModule, self).__init__(
|
2016-06-21 08:21:06 -05:00
|
|
|
"NODE-%s" % self.node_type,
|
|
|
|
import_name,
|
|
|
|
**kwargs
|
|
|
|
)
|
2015-06-29 01:58:41 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def jssnippets(self):
|
|
|
|
"""
|
|
|
|
Returns a snippet of javascript to include in the page
|
|
|
|
"""
|
|
|
|
return []
|
|
|
|
|
2017-06-22 05:26:45 -05:00
|
|
|
@property
|
|
|
|
def module_use_template_javascript(self):
|
|
|
|
"""
|
|
|
|
Returns whether Jinja2 template is used for generating the javascript
|
|
|
|
module.
|
|
|
|
"""
|
|
|
|
return False
|
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
def get_own_javascripts(self):
|
2016-03-07 05:48:24 -06:00
|
|
|
"""
|
|
|
|
Returns the list of javascripts information used by the module.
|
|
|
|
|
|
|
|
Each javascripts information must contain name, path of the script.
|
|
|
|
|
|
|
|
The name must be unique for each module, hence - in order to refer them
|
|
|
|
properly, we do use 'pgadmin.node.<type>' as norm.
|
|
|
|
|
|
|
|
That can also refer to when to load the script.
|
|
|
|
|
|
|
|
i.e.
|
|
|
|
We may not need to load the javascript of table node, when we're
|
|
|
|
not yet connected to a server, and no database is loaded. Hence - it
|
|
|
|
make sense to load them when a database is loaded.
|
|
|
|
|
|
|
|
We may also add 'deps', which also refers to the list of javascripts,
|
|
|
|
it may depends on.
|
|
|
|
"""
|
2015-06-30 00:51:55 -05:00
|
|
|
scripts = []
|
|
|
|
|
2017-06-22 05:26:45 -05:00
|
|
|
if self.module_use_template_javascript:
|
|
|
|
scripts.extend([{
|
|
|
|
'name': 'pgadmin.node.%s' % self.node_type,
|
|
|
|
'path': url_for('browser.index') + '%s/module' % self.node_type,
|
|
|
|
'when': self.script_load,
|
|
|
|
'is_template': True
|
|
|
|
}])
|
|
|
|
else:
|
|
|
|
scripts.extend([{
|
|
|
|
'name': 'pgadmin.node.%s' % self.node_type,
|
|
|
|
'path': url_for(
|
|
|
|
'%s.static'% self.name, filename=('js/%s' % self.node_type)
|
|
|
|
),
|
|
|
|
'when': self.script_load,
|
|
|
|
'is_template': False
|
|
|
|
}])
|
2015-06-30 00:51:55 -05:00
|
|
|
|
|
|
|
for module in self.submodules:
|
|
|
|
scripts.extend(module.get_own_javascripts())
|
2017-06-22 05:26:45 -05:00
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
return scripts
|
|
|
|
|
2015-10-20 02:03:18 -05:00
|
|
|
def generate_browser_node(
|
2016-02-04 21:53:58 -06:00
|
|
|
self, node_id, parent_id, label, icon, inode, node_type, **kwargs
|
2016-06-21 08:21:06 -05:00
|
|
|
):
|
2016-03-07 05:48:24 -06:00
|
|
|
"""
|
|
|
|
Helper function to create a browser node for this particular subnode.
|
|
|
|
|
|
|
|
:param node_id: Unique Id for each node
|
|
|
|
:param parent_id: Id of the parent.
|
|
|
|
:param label: Label for the node
|
|
|
|
:param icon: Icon for displaying along with this node on browser
|
|
|
|
tree. Icon refers to a class name, it refers to.
|
|
|
|
:param inode: True/False.
|
|
|
|
Used by the browser tree node to check, if the
|
|
|
|
current node will have children or not.
|
|
|
|
:param node_type: String to refer to the node type.
|
|
|
|
:param **kwargs: A node can have extra information other than this
|
|
|
|
data, which can be passed as key-value pair as
|
|
|
|
argument here.
|
|
|
|
i.e. A database, server node can have extra
|
|
|
|
information like connected, or not.
|
|
|
|
|
|
|
|
Returns a dictionary object representing this node object for the
|
|
|
|
browser tree.
|
|
|
|
"""
|
2015-06-30 00:51:55 -05:00
|
|
|
obj = {
|
2016-06-21 08:21:06 -05:00
|
|
|
"id": "%s/%s" % (node_type, node_id),
|
|
|
|
"label": label,
|
|
|
|
"icon": icon,
|
|
|
|
"inode": inode,
|
|
|
|
"_type": node_type,
|
|
|
|
"_id": node_id,
|
|
|
|
"_pid": parent_id,
|
|
|
|
"module": 'pgadmin.node.%s' % node_type
|
|
|
|
}
|
2015-10-20 02:03:18 -05:00
|
|
|
for key in kwargs:
|
|
|
|
obj.setdefault(key, kwargs[key])
|
2015-06-30 00:51:55 -05:00
|
|
|
return obj
|
|
|
|
|
2015-06-29 01:58:41 -05:00
|
|
|
@property
|
|
|
|
def csssnippets(self):
|
|
|
|
"""
|
|
|
|
Returns a snippet of css to include in the page
|
|
|
|
"""
|
2015-10-20 02:03:18 -05:00
|
|
|
snippets = [
|
2016-06-21 08:21:06 -05:00
|
|
|
render_template(
|
|
|
|
"browser/css/node.css",
|
|
|
|
node_type=self.node_type,
|
|
|
|
_=gettext
|
|
|
|
)]
|
2015-06-29 01:58:41 -05:00
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
for submodule in self.submodules:
|
|
|
|
snippets.extend(submodule.csssnippets)
|
|
|
|
return snippets
|
|
|
|
|
2015-06-29 01:58:41 -05:00
|
|
|
@abstractmethod
|
|
|
|
def get_nodes(self):
|
|
|
|
"""
|
|
|
|
Each browser module is responsible for fetching
|
|
|
|
its own tree subnodes.
|
|
|
|
"""
|
|
|
|
return []
|
|
|
|
|
|
|
|
@abstractproperty
|
|
|
|
def node_type(self):
|
|
|
|
pass
|
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
@abstractproperty
|
|
|
|
def script_load(self):
|
|
|
|
"""
|
|
|
|
This property defines, when to load this script.
|
|
|
|
In order to allow creation of an object, we need to load script for any
|
|
|
|
node at the parent level.
|
|
|
|
|
|
|
|
i.e.
|
|
|
|
- In order to allow creating a server object, it should be loaded at
|
|
|
|
server-group node.
|
|
|
|
"""
|
|
|
|
pass
|
|
|
|
|
2015-06-29 01:58:41 -05:00
|
|
|
@property
|
|
|
|
def node_path(self):
|
2016-03-07 05:48:24 -06:00
|
|
|
"""
|
|
|
|
Defines the url path prefix for this submodule.
|
|
|
|
"""
|
2015-10-20 02:03:18 -05:00
|
|
|
return self.browser_url_prefix + self.node_type
|
2015-06-30 00:51:55 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def javascripts(self):
|
2016-03-07 05:48:24 -06:00
|
|
|
"""
|
|
|
|
Override the javascript of PgAdminModule, so that - we don't return
|
|
|
|
javascripts from the get_own_javascripts itself.
|
|
|
|
"""
|
2015-06-30 00:51:55 -05:00
|
|
|
return []
|
2015-06-29 01:58:41 -05:00
|
|
|
|
2016-03-07 05:48:24 -06:00
|
|
|
@property
|
|
|
|
def label(self):
|
|
|
|
"""
|
|
|
|
Module label.
|
|
|
|
"""
|
|
|
|
return self.LABEL
|
|
|
|
|
|
|
|
@property
|
|
|
|
def show_node(self):
|
|
|
|
"""
|
|
|
|
A proper to check to show node for this module on the browser tree or not.
|
|
|
|
|
|
|
|
Relies on show_node preference object, otherwise on the SHOW_ON_BROWSER
|
|
|
|
default value.
|
|
|
|
"""
|
|
|
|
if self.pref_show_node:
|
|
|
|
return self.pref_show_node.get()
|
|
|
|
else:
|
|
|
|
return self.SHOW_ON_BROWSER
|
|
|
|
|
|
|
|
@property
|
|
|
|
def show_system_objects(self):
|
|
|
|
"""
|
|
|
|
Show/Hide the system objects in the database server.
|
|
|
|
"""
|
|
|
|
if self.pref_show_system_objects:
|
|
|
|
return self.pref_show_system_objects.get()
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def register_preferences(self):
|
|
|
|
"""
|
|
|
|
Registers the preferences object for this module.
|
|
|
|
|
|
|
|
Sets the browser_preference, show_system_objects, show_node preference
|
|
|
|
objects for this submodule.
|
|
|
|
"""
|
|
|
|
# Add the node informaton for browser, not in respective node preferences
|
|
|
|
self.browser_preference = blueprint.preference
|
|
|
|
self.pref_show_system_objects = blueprint.preference.preference(
|
|
|
|
'display', 'show_system_objects'
|
2016-06-21 08:21:06 -05:00
|
|
|
)
|
2016-03-07 05:48:24 -06:00
|
|
|
self.pref_show_node = self.browser_preference.preference(
|
|
|
|
'node', 'show_node_' + self.node_type,
|
|
|
|
self.label, 'boolean', self.SHOW_ON_BROWSER, category_label=gettext('Nodes')
|
2016-06-21 08:21:06 -05:00
|
|
|
)
|
2016-03-07 05:48:24 -06:00
|
|
|
|
2015-06-29 01:58:41 -05:00
|
|
|
|
|
|
|
@blueprint.route("/")
|
|
|
|
@login_required
|
|
|
|
def index():
|
|
|
|
"""Render and process the main browser window."""
|
|
|
|
# Get the Gravatar
|
2016-05-24 01:19:38 -05:00
|
|
|
Gravatar(
|
|
|
|
current_app,
|
|
|
|
size=100,
|
|
|
|
rating='g',
|
|
|
|
default='retro',
|
|
|
|
force_default=False,
|
2016-09-13 07:39:26 -05:00
|
|
|
use_ssl=True,
|
2016-05-24 01:19:38 -05:00
|
|
|
base_url=None
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = None
|
2016-02-08 10:28:20 -06:00
|
|
|
# Get the current version info from the website, and flash a message if
|
|
|
|
# the user is out of date, and the check is enabled.
|
|
|
|
if config.UPGRADE_CHECK_ENABLED:
|
|
|
|
data = None
|
|
|
|
url = '%s?version=%s' % (config.UPGRADE_CHECK_URL, config.APP_VERSION)
|
|
|
|
current_app.logger.debug('Checking version data at: %s' % url)
|
|
|
|
|
|
|
|
try:
|
2016-03-17 23:27:57 -05:00
|
|
|
# Do not wait for more than 5 seconds.
|
|
|
|
# It stuck on rendering the browser.html, while working in the
|
|
|
|
# broken network.
|
|
|
|
response = urlreq.urlopen(url, data, 5)
|
2016-05-24 01:19:38 -05:00
|
|
|
current_app.logger.debug(
|
|
|
|
'Version check HTTP response code: %d' % response.getcode()
|
|
|
|
)
|
2016-02-08 10:28:20 -06:00
|
|
|
|
|
|
|
if response.getcode() == 200:
|
2016-11-16 03:13:59 -06:00
|
|
|
data = json.loads(response.read().decode('utf-8'))
|
2016-02-08 10:28:20 -06:00
|
|
|
current_app.logger.debug('Response data: %s' % data)
|
|
|
|
except:
|
2016-11-16 03:13:59 -06:00
|
|
|
current_app.logger.exception('Exception when checking for update')
|
2016-02-08 10:28:20 -06:00
|
|
|
|
2016-05-24 01:19:38 -05:00
|
|
|
if data is not None:
|
2016-07-22 10:14:57 -05:00
|
|
|
if data['pgadmin4']['version_int'] > config.APP_VERSION_INT:
|
2016-05-24 01:19:38 -05:00
|
|
|
msg = render_template(
|
|
|
|
MODULE_NAME + "/upgrade.html",
|
|
|
|
current_version=config.APP_VERSION,
|
|
|
|
upgrade_version=data['pgadmin4']['version'],
|
|
|
|
product_name=config.APP_NAME,
|
|
|
|
download_url=data['pgadmin4']['download_url']
|
|
|
|
)
|
2016-02-08 10:28:20 -06:00
|
|
|
|
2016-05-21 12:54:12 -05:00
|
|
|
flash(msg, 'warning')
|
2016-02-08 10:28:20 -06:00
|
|
|
|
2017-03-24 09:20:10 -05:00
|
|
|
response = Response(render_template(
|
2016-06-21 08:21:06 -05:00
|
|
|
MODULE_NAME + "/index.html",
|
|
|
|
username=current_user.email,
|
|
|
|
is_admin=current_user.has_role("Administrator"),
|
|
|
|
_=gettext
|
2017-03-24 09:20:10 -05:00
|
|
|
))
|
|
|
|
|
|
|
|
# Set the language cookie after login, so next time the user will have that
|
|
|
|
# same option at the login time.
|
|
|
|
misc_preference = Preferences.module('miscellaneous')
|
|
|
|
user_languages = misc_preference.preference(
|
|
|
|
'user_language'
|
2016-06-21 08:21:06 -05:00
|
|
|
)
|
2017-03-24 09:20:10 -05:00
|
|
|
language = 'en'
|
|
|
|
if user_languages:
|
|
|
|
language = user_languages.get() or 'en'
|
|
|
|
|
|
|
|
response.set_cookie("PGADMIN_LANGUAGE", language)
|
2015-10-20 02:03:18 -05:00
|
|
|
|
2017-03-24 09:20:10 -05:00
|
|
|
return response
|
2015-06-29 01:58:41 -05:00
|
|
|
|
2017-07-18 09:13:16 -05:00
|
|
|
@blueprint.route("/js/utils.js")
|
2015-06-29 01:58:41 -05:00
|
|
|
@login_required
|
2017-07-18 09:13:16 -05:00
|
|
|
def utils():
|
2015-06-29 01:58:41 -05:00
|
|
|
layout = get_setting('Browser/Layout', default='')
|
|
|
|
snippets = []
|
2016-06-13 10:17:36 -05:00
|
|
|
|
|
|
|
prefs = Preferences.module('paths')
|
|
|
|
|
|
|
|
pg_help_path_pref = prefs.preference('pg_help_path')
|
|
|
|
pg_help_path = pg_help_path_pref.get()
|
|
|
|
|
|
|
|
edbas_help_path_pref = prefs.preference('edbas_help_path')
|
|
|
|
edbas_help_path = edbas_help_path_pref.get()
|
|
|
|
|
2016-08-19 05:40:19 -05:00
|
|
|
# Get sqleditor options
|
|
|
|
prefs = Preferences.module('sqleditor')
|
|
|
|
|
|
|
|
editor_tab_size_pref = prefs.preference('tab_size')
|
|
|
|
editor_tab_size = editor_tab_size_pref.get()
|
|
|
|
|
|
|
|
editor_use_spaces_pref = prefs.preference('use_spaces')
|
|
|
|
editor_use_spaces = editor_use_spaces_pref.get()
|
|
|
|
|
2016-12-16 11:07:41 -06:00
|
|
|
editor_wrap_code_pref = prefs.preference('wrap_code')
|
|
|
|
editor_wrap_code = editor_wrap_code_pref.get()
|
|
|
|
|
2017-06-27 08:57:38 -05:00
|
|
|
brace_matching_pref = prefs.preference('brace_matching')
|
|
|
|
brace_matching = brace_matching_pref.get()
|
|
|
|
|
|
|
|
insert_pair_brackets_perf = prefs.preference('insert_pair_brackets')
|
|
|
|
insert_pair_brackets = insert_pair_brackets_perf.get()
|
|
|
|
|
2017-10-16 09:37:03 -05:00
|
|
|
# This will be opposite of use_space option
|
|
|
|
editor_indent_with_tabs = False if editor_use_spaces else True
|
|
|
|
|
2017-10-10 03:31:27 -05:00
|
|
|
# Try to fetch current libpq version from the driver
|
|
|
|
try:
|
|
|
|
from config import PG_DEFAULT_DRIVER
|
|
|
|
from pgadmin.utils.driver import get_driver
|
|
|
|
driver = get_driver(PG_DEFAULT_DRIVER)
|
|
|
|
pg_libpq_version = driver.libpq_version()
|
|
|
|
except:
|
|
|
|
pg_libpq_version = 0
|
|
|
|
|
2015-06-29 01:58:41 -05:00
|
|
|
for submodule in current_blueprint.submodules:
|
|
|
|
snippets.extend(submodule.jssnippets)
|
2015-06-29 03:11:56 -05:00
|
|
|
return make_response(
|
2016-06-21 08:21:06 -05:00
|
|
|
render_template(
|
2017-07-18 09:13:16 -05:00
|
|
|
'browser/js/utils.js',
|
2016-06-21 08:21:06 -05:00
|
|
|
layout=layout,
|
|
|
|
jssnippets=snippets,
|
|
|
|
pg_help_path=pg_help_path,
|
|
|
|
edbas_help_path=edbas_help_path,
|
2016-08-19 05:40:19 -05:00
|
|
|
editor_tab_size=editor_tab_size,
|
|
|
|
editor_use_spaces=editor_use_spaces,
|
2016-12-16 11:07:41 -06:00
|
|
|
editor_wrap_code=editor_wrap_code,
|
2017-06-27 08:57:38 -05:00
|
|
|
editor_brace_matching=brace_matching,
|
|
|
|
editor_insert_pair_brackets=insert_pair_brackets,
|
2017-10-16 09:37:03 -05:00
|
|
|
editor_indent_with_tabs=editor_indent_with_tabs,
|
2017-10-10 03:31:27 -05:00
|
|
|
app_name=config.APP_NAME,
|
|
|
|
pg_libpq_version=pg_libpq_version
|
2016-06-21 08:21:06 -05:00
|
|
|
),
|
|
|
|
200, {'Content-Type': 'application/x-javascript'})
|
2015-06-29 01:58:41 -05:00
|
|
|
|
2015-10-20 02:03:18 -05:00
|
|
|
|
2017-06-12 01:31:22 -05:00
|
|
|
@blueprint.route("/js/endpoints.js")
|
|
|
|
def exposed_urls():
|
|
|
|
return make_response(
|
|
|
|
render_template('browser/js/endpoints.js'),
|
|
|
|
200, {'Content-Type': 'application/x-javascript'}
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
@blueprint.route("/js/error.js")
|
|
|
|
@login_required
|
|
|
|
def error_js():
|
|
|
|
return make_response(
|
2016-06-21 08:21:06 -05:00
|
|
|
render_template('browser/js/error.js', _=gettext),
|
|
|
|
200, {'Content-Type': 'application/x-javascript'})
|
2015-06-30 00:51:55 -05:00
|
|
|
|
2015-10-20 02:03:18 -05:00
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
@blueprint.route("/js/node.js")
|
2016-04-12 07:35:47 -05:00
|
|
|
@login_required
|
2015-06-30 00:51:55 -05:00
|
|
|
def node_js():
|
2016-04-12 07:35:47 -05:00
|
|
|
prefs = Preferences.module('paths')
|
|
|
|
|
|
|
|
pg_help_path_pref = prefs.preference('pg_help_path')
|
|
|
|
pg_help_path = pg_help_path_pref.get()
|
|
|
|
|
|
|
|
edbas_help_path_pref = prefs.preference('edbas_help_path')
|
|
|
|
edbas_help_path = edbas_help_path_pref.get()
|
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
return make_response(
|
2016-06-21 08:21:06 -05:00
|
|
|
render_template('browser/js/node.js',
|
|
|
|
pg_help_path=pg_help_path,
|
|
|
|
edbas_help_path=edbas_help_path,
|
|
|
|
_=gettext
|
|
|
|
),
|
|
|
|
200, {'Content-Type': 'application/x-javascript'})
|
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
|
2016-04-11 06:35:49 -05:00
|
|
|
@blueprint.route("/js/messages.js")
|
|
|
|
def messages_js():
|
|
|
|
return make_response(
|
2016-06-21 08:21:06 -05:00
|
|
|
render_template('browser/js/messages.js', _=gettext),
|
|
|
|
200, {'Content-Type': 'application/x-javascript'})
|
2016-04-11 06:35:49 -05:00
|
|
|
|
|
|
|
|
2015-11-17 00:21:09 -06:00
|
|
|
@blueprint.route("/js/collection.js")
|
|
|
|
@login_required
|
|
|
|
def collection_js():
|
|
|
|
return make_response(
|
2016-06-21 08:21:06 -05:00
|
|
|
render_template('browser/js/collection.js', _=gettext),
|
|
|
|
200, {'Content-Type': 'application/x-javascript'})
|
2015-11-17 00:21:09 -06:00
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
|
2015-06-29 01:58:41 -05:00
|
|
|
@blueprint.route("/browser.css")
|
|
|
|
@login_required
|
|
|
|
def browser_css():
|
|
|
|
"""Render and return CSS snippets from the nodes and modules."""
|
|
|
|
snippets = []
|
2016-08-17 07:20:05 -05:00
|
|
|
|
|
|
|
# Get configurable options
|
2016-08-19 05:40:19 -05:00
|
|
|
prefs = Preferences.module('sqleditor')
|
2016-08-17 07:20:05 -05:00
|
|
|
|
|
|
|
sql_font_size_pref = prefs.preference('sql_font_size')
|
2016-08-17 07:45:52 -05:00
|
|
|
sql_font_size = round(float(sql_font_size_pref.get()), 2)
|
2016-08-17 07:20:05 -05:00
|
|
|
|
2016-08-17 07:45:52 -05:00
|
|
|
if sql_font_size != 0:
|
2016-08-19 05:08:42 -05:00
|
|
|
snippets.append('.CodeMirror { font-size: %sem; }' % str(sql_font_size))
|
2016-08-17 07:20:05 -05:00
|
|
|
|
2015-06-30 00:51:55 -05:00
|
|
|
for submodule in blueprint.submodules:
|
2015-06-29 01:58:41 -05:00
|
|
|
snippets.extend(submodule.csssnippets)
|
2015-06-29 03:11:56 -05:00
|
|
|
return make_response(
|
2016-06-21 08:21:06 -05:00
|
|
|
render_template(
|
|
|
|
'browser/css/browser.css', snippets=snippets, _=gettext
|
|
|
|
),
|
|
|
|
200, {'Content-Type': 'text/css'})
|
2015-06-29 01:58:41 -05:00
|
|
|
|
|
|
|
|
2017-06-12 01:31:22 -05:00
|
|
|
@blueprint.route("/nodes/", endpoint="nodes")
|
2015-06-29 01:58:41 -05:00
|
|
|
@login_required
|
|
|
|
def get_nodes():
|
|
|
|
"""Build a list of treeview nodes from the child nodes."""
|
|
|
|
nodes = []
|
|
|
|
for submodule in current_blueprint.submodules:
|
|
|
|
nodes.extend(submodule.get_nodes())
|
2017-06-12 01:31:22 -05:00
|
|
|
|
2015-06-29 01:58:41 -05:00
|
|
|
return make_json_response(data=nodes)
|