mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Introduced a PgAdmin class inherited from the Flask, which looks for
submodules inherited from the PgAdminModule instead of regular Blueprint. This allows us to load the module automatically from the under the pgadmin directory, and will work to extend the pgAdmin extension module. PgAdminModule is inherited from the Blueprint, and bring several methods: - get_own_stylesheets, which returns the stylesheets used by the module (excluding its submodules stylesheets) - get_own_javascripts - menu_items, which returns a dictionray mapping the old hook names (context_items etc) to a list of MenuItem instances For more specialized modules (as for now, any module that should be part of the browser tree construction), one can define an abstract base class defining additional methods. For example, the BrowserPluginModule abstract base class defines the following methods: - jssnippets - csssnipeets - node_type - get_nodes
This commit is contained in:
committed by
Ashesh Vashi
parent
9e0b011ec8
commit
eb6580b43a
@@ -7,7 +7,7 @@
|
|||||||
#
|
#
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
"""This is the main application entry point for pgAdmin 4. If running on
|
"""This is the main application entry point for pgAdmin 4. If running on
|
||||||
a webserver, this will provide the WSGI interface, otherwise, we're going
|
a webserver, this will provide the WSGI interface, otherwise, we're going
|
||||||
to start a web server."""
|
to start a web server."""
|
||||||
|
|
||||||
@@ -50,8 +50,11 @@ if not os.path.isfile(config.SQLITE_PATH):
|
|||||||
# Create the app!
|
# Create the app!
|
||||||
app = create_app()
|
app = create_app()
|
||||||
|
|
||||||
|
#if config.DEBUG:
|
||||||
|
# app.debug = True
|
||||||
|
|
||||||
# Start the web server. The port number should have already been set by the
|
# Start the web server. The port number should have already been set by the
|
||||||
# runtime if we're running in desktop mode, otherwise we'll just use the
|
# runtime if we're running in desktop mode, otherwise we'll just use the
|
||||||
# Flask default.
|
# Flask default.
|
||||||
if 'PGADMIN_PORT' in globals():
|
if 'PGADMIN_PORT' in globals():
|
||||||
app.logger.debug('PGADMIN_PORT set in the runtime environment to %s', PGADMIN_PORT)
|
app.logger.debug('PGADMIN_PORT set in the runtime environment to %s', PGADMIN_PORT)
|
||||||
@@ -64,4 +67,3 @@ try:
|
|||||||
app.run(port=server_port)
|
app.run(port=server_port)
|
||||||
except IOError:
|
except IOError:
|
||||||
app.logger.error("Error starting the app server: %s", sys.exc_info())
|
app.logger.error("Error starting the app server: %s", sys.exc_info())
|
||||||
|
|
||||||
|
@@ -10,27 +10,50 @@
|
|||||||
"""The main pgAdmin module. This handles the application initialisation tasks,
|
"""The main pgAdmin module. This handles the application initialisation tasks,
|
||||||
such as setup of logging, dynamic loading of modules etc."""
|
such as setup of logging, dynamic loading of modules etc."""
|
||||||
|
|
||||||
from flask import Flask, abort, request
|
from flask import Flask, abort, request, current_app
|
||||||
from flask.ext.babel import Babel
|
from flask.ext.babel import Babel
|
||||||
from flask.ext.sqlalchemy import SQLAlchemy
|
from flask.ext.security import Security, SQLAlchemyUserDatastore
|
||||||
from flask.ext.security import Security, SQLAlchemyUserDatastore, login_required
|
|
||||||
from flask_security.utils import login_user
|
from flask_security.utils import login_user
|
||||||
from flask_mail import Mail
|
from flask_mail import Mail
|
||||||
from htmlmin.minify import html_minify
|
from htmlmin.minify import html_minify
|
||||||
from settings.settings_model import db, Role, User
|
from settings.settings_model import db, Role, User
|
||||||
|
from importlib import import_module
|
||||||
import inspect, imp, logging, os, sys
|
from werkzeug.local import LocalProxy
|
||||||
|
from pgadmin.utils import PgAdminModule
|
||||||
|
from werkzeug.utils import find_modules
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
|
||||||
# Configuration settings
|
# Configuration settings
|
||||||
import config
|
import config
|
||||||
|
|
||||||
# Global module list
|
|
||||||
modules = [ ]
|
class PgAdmin(Flask):
|
||||||
|
|
||||||
|
def find_submodules(self, basemodule):
|
||||||
|
for module_name in find_modules(basemodule, True):
|
||||||
|
if module_name in self.config['MODULE_BLACKLIST']:
|
||||||
|
self.logger.info('Skipping blacklisted module: %s' %
|
||||||
|
module_name)
|
||||||
|
continue
|
||||||
|
self.logger.info('Examining potential module: %s' % module_name)
|
||||||
|
module = import_module(module_name)
|
||||||
|
for key, value in module.__dict__.items():
|
||||||
|
if isinstance(value, PgAdminModule):
|
||||||
|
yield value
|
||||||
|
|
||||||
|
|
||||||
|
def _find_blueprint():
|
||||||
|
if request.blueprint:
|
||||||
|
return current_app.blueprints[request.blueprint]
|
||||||
|
|
||||||
|
current_blueprint = LocalProxy(_find_blueprint)
|
||||||
|
|
||||||
|
|
||||||
def create_app(app_name=config.APP_NAME):
|
def create_app(app_name=config.APP_NAME):
|
||||||
"""Create the Flask application, startup logging and dynamically load
|
"""Create the Flask application, startup logging and dynamically load
|
||||||
additional modules (blueprints) that are found in this directory."""
|
additional modules (blueprints) that are found in this directory."""
|
||||||
app = Flask(__name__, static_url_path='/static')
|
app = PgAdmin(__name__, static_url_path='/static')
|
||||||
app.config.from_object(config)
|
app.config.from_object(config)
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
@@ -42,7 +65,7 @@ def create_app(app_name=config.APP_NAME):
|
|||||||
app.logger.setLevel(logging.DEBUG)
|
app.logger.setLevel(logging.DEBUG)
|
||||||
app.logger.handlers = []
|
app.logger.handlers = []
|
||||||
|
|
||||||
# We also need to update the handler on the webserver in order to see request.
|
# We also need to update the handler on the webserver in order to see request.
|
||||||
# Setting the level prevents werkzeug from setting up it's own stream handler
|
# Setting the level prevents werkzeug from setting up it's own stream handler
|
||||||
# thus ensuring all the logging goes through the pgAdmin logger.
|
# thus ensuring all the logging goes through the pgAdmin logger.
|
||||||
logger = logging.getLogger('werkzeug')
|
logger = logging.getLogger('werkzeug')
|
||||||
@@ -67,82 +90,48 @@ def create_app(app_name=config.APP_NAME):
|
|||||||
app.logger.info('Starting %s v%s...', config.APP_NAME, config.APP_VERSION)
|
app.logger.info('Starting %s v%s...', config.APP_NAME, config.APP_VERSION)
|
||||||
app.logger.info('################################################################################')
|
app.logger.info('################################################################################')
|
||||||
app.logger.debug("Python syspath: %s", sys.path)
|
app.logger.debug("Python syspath: %s", sys.path)
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# Setup i18n
|
# Setup i18n
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
# Initialise i18n
|
# Initialise i18n
|
||||||
babel = Babel(app)
|
babel = Babel(app)
|
||||||
|
|
||||||
app.logger.debug('Available translations: %s' % babel.list_translations())
|
app.logger.debug('Available translations: %s' % babel.list_translations())
|
||||||
|
|
||||||
@babel.localeselector
|
@babel.localeselector
|
||||||
def get_locale():
|
def get_locale():
|
||||||
"""Get the best language for the user."""
|
"""Get the best language for the user."""
|
||||||
language = request.accept_languages.best_match(config.LANGUAGES.keys())
|
language = request.accept_languages.best_match(config.LANGUAGES.keys())
|
||||||
return language
|
return language
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# Setup authentication
|
# Setup authentication
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + config.SQLITE_PATH.replace('\\', '/')
|
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + config.SQLITE_PATH.replace('\\', '/')
|
||||||
|
|
||||||
# Only enable password related functionality in server mode.
|
# Only enable password related functionality in server mode.
|
||||||
if config.SERVER_MODE == True:
|
if config.SERVER_MODE is True:
|
||||||
# TODO: Figure out how to disable /logout and /login
|
# TODO: Figure out how to disable /logout and /login
|
||||||
app.config['SECURITY_RECOVERABLE'] = True
|
app.config['SECURITY_RECOVERABLE'] = True
|
||||||
app.config['SECURITY_CHANGEABLE'] = True
|
app.config['SECURITY_CHANGEABLE'] = True
|
||||||
|
|
||||||
# Create database connection object and mailer
|
# Create database connection object and mailer
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
mail = Mail(app)
|
Mail(app)
|
||||||
|
|
||||||
# Setup Flask-Security
|
# Setup Flask-Security
|
||||||
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
|
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
|
||||||
security = Security(app, user_datastore)
|
Security(app, user_datastore)
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# Load plugin modules
|
# Load plugin modules
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
for module in app.find_submodules('pgadmin'):
|
||||||
path = os.path.dirname(os.path.realpath(__file__))
|
app.logger.info('Registering blueprint module: %s' % module)
|
||||||
files = os.listdir(path)
|
app.register_blueprint(module)
|
||||||
|
|
||||||
for f in files:
|
|
||||||
d = os.path.join(path, f)
|
|
||||||
if os.path.isdir(d) and os.path.isfile(os.path.join(d, '__init__.py')):
|
|
||||||
|
|
||||||
if f in config.MODULE_BLACKLIST:
|
|
||||||
app.logger.info('Skipping blacklisted module: %s' % f)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Construct the "real" module name
|
|
||||||
f = 'pgadmin.' + f
|
|
||||||
|
|
||||||
# Looks like a module, so import it, and register the blueprint if present
|
|
||||||
# We rely on the ordering of syspath to ensure we actually get the right
|
|
||||||
# module here. Note that we also try to load the 'hooks' module for
|
|
||||||
# the browser integration hooks and other similar functions.
|
|
||||||
app.logger.info('Examining potential module: %s' % d)
|
|
||||||
module = __import__(f, globals(), locals(), ['hooks', 'views'], -1)
|
|
||||||
|
|
||||||
# Add the module to the global module list
|
|
||||||
modules.append(module)
|
|
||||||
|
|
||||||
# Register the blueprint if present
|
|
||||||
if 'views' in dir(module) and 'blueprint' in dir(module.views):
|
|
||||||
app.logger.info('Registering blueprint module: %s' % f)
|
|
||||||
app.register_blueprint(module.views.blueprint)
|
|
||||||
app.logger.debug(' - root_path: %s' % module.views.blueprint.root_path)
|
|
||||||
app.logger.debug(' - static_folder: %s' % module.views.blueprint.static_folder)
|
|
||||||
app.logger.debug(' - template_folder: %s' % module.views.blueprint.template_folder)
|
|
||||||
|
|
||||||
# Register any sub-modules
|
|
||||||
if 'hooks' in dir(module) and 'register_submodules' in dir(module.hooks):
|
|
||||||
app.logger.info('Registering sub-modules in %s' % f)
|
|
||||||
module.hooks.register_submodules(app)
|
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# Handle the desktop login
|
# Handle the desktop login
|
||||||
@@ -151,7 +140,7 @@ def create_app(app_name=config.APP_NAME):
|
|||||||
@app.before_request
|
@app.before_request
|
||||||
def before_request():
|
def before_request():
|
||||||
"""Login the default user if running in desktop mode"""
|
"""Login the default user if running in desktop mode"""
|
||||||
if config.SERVER_MODE == False:
|
if config.SERVER_MODE is False:
|
||||||
user = user_datastore.get_user(config.DESKTOP_USER)
|
user = user_datastore.get_user(config.DESKTOP_USER)
|
||||||
|
|
||||||
# Throw an error if we failed to find the desktop user, to give
|
# Throw an error if we failed to find the desktop user, to give
|
||||||
@@ -165,7 +154,7 @@ def create_app(app_name=config.APP_NAME):
|
|||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# Minify output
|
# Minify output
|
||||||
##########################################################################
|
##########################################################################
|
||||||
@app.after_request
|
@app.after_request
|
||||||
def response_minify(response):
|
def response_minify(response):
|
||||||
"""Minify html response to decrease traffic"""
|
"""Minify html response to decrease traffic"""
|
||||||
@@ -177,10 +166,16 @@ def create_app(app_name=config.APP_NAME):
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@app.context_processor
|
||||||
|
def inject_blueprint():
|
||||||
|
"""Inject a reference to the current blueprint, if any."""
|
||||||
|
return {
|
||||||
|
'current_blueprint': current_blueprint,
|
||||||
|
'menu_items': getattr(current_blueprint, "menu_items", {})}
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# All done!
|
# All done!
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
app.logger.debug('URL map: %s' % app.url_map)
|
app.logger.debug('URL map: %s' % app.url_map)
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
@@ -6,7 +6,160 @@
|
|||||||
# This software is released under the PostgreSQL Licence
|
# This software is released under the PostgreSQL Licence
|
||||||
#
|
#
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
from abc import ABCMeta, abstractmethod, abstractproperty
|
||||||
|
from pgadmin import current_blueprint
|
||||||
|
from pgadmin.utils import PgAdminModule
|
||||||
|
from pgadmin.utils.ajax import make_json_response
|
||||||
|
from pgadmin.settings import get_setting
|
||||||
|
from flask import current_app, render_template, url_for, make_response
|
||||||
|
from flask.ext.security import login_required
|
||||||
|
from flask.ext.login import current_user
|
||||||
|
from flaskext.gravatar import Gravatar
|
||||||
|
|
||||||
# Define the node lists
|
MODULE_NAME = 'browser'
|
||||||
all_nodes = [ ]
|
|
||||||
sub_nodes = [ ]
|
class BrowserModule(PgAdminModule):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_own_stylesheets(self):
|
||||||
|
stylesheets = []
|
||||||
|
# Add browser stylesheets
|
||||||
|
for (endpoint, filename) in [
|
||||||
|
('static', 'css/codemirror/codemirror.css'),
|
||||||
|
('static', 'css/wcDocker/theme.css'),
|
||||||
|
('static', 'css/jQuery-contextMenu/jquery.contextMenu.css'),
|
||||||
|
('browser.static', 'css/browser.css'),
|
||||||
|
('browser.static', 'css/aciTree/css/aciTree.css')
|
||||||
|
]:
|
||||||
|
stylesheets.append(url_for(endpoint, filename=filename))
|
||||||
|
stylesheets.append(url_for('browser.browser_css'))
|
||||||
|
if current_app.debug:
|
||||||
|
stylesheets.append(url_for('static', filename='css/wcDocker/wcDockerSkeleton.css'))
|
||||||
|
else:
|
||||||
|
stylesheets.append(url_for('static', filename='css/wcDocker/wcDockerSkeleton.min.css'))
|
||||||
|
return stylesheets
|
||||||
|
|
||||||
|
def get_own_javascripts(self):
|
||||||
|
scripts = []
|
||||||
|
for (endpoint, filename) in [
|
||||||
|
('static', 'js/codemirror/codemirror.js'),
|
||||||
|
('static', 'js/codemirror/mode/sql.js'),
|
||||||
|
('static', 'js/jQuery-contextMenu/jquery.ui.position.js'),
|
||||||
|
('static', 'js/jQuery-contextMenu/jquery.contextMenu.js'),
|
||||||
|
('browser.static', 'js/aciTree/jquery.aciPlugin.min.js'),
|
||||||
|
('browser.static', 'js/aciTree/jquery.aciTree.dom.js'),
|
||||||
|
('browser.static', 'js/aciTree/jquery.aciTree.min.js')]:
|
||||||
|
scripts.append(url_for(endpoint, filename=filename))
|
||||||
|
scripts.append(url_for('browser.browser_js'))
|
||||||
|
if current_app.debug:
|
||||||
|
scripts.append(url_for(
|
||||||
|
'static',
|
||||||
|
filename='js/wcDocker/wcDocker.js'))
|
||||||
|
else:
|
||||||
|
scripts.append(url_for(
|
||||||
|
'static',
|
||||||
|
filename='js/wcDocker/wcDocker.min.js'))
|
||||||
|
return scripts
|
||||||
|
|
||||||
|
|
||||||
|
blueprint = BrowserModule(MODULE_NAME, __name__)
|
||||||
|
|
||||||
|
class BrowserPluginModule(PgAdminModule):
|
||||||
|
"""
|
||||||
|
Base class for browser submodules.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__metaclass__ = ABCMeta
|
||||||
|
|
||||||
|
def __init__(self, import_name, **kwargs):
|
||||||
|
kwargs.setdefault("url_prefix", self.node_path)
|
||||||
|
kwargs.setdefault("static_url_path", '')
|
||||||
|
super(BrowserPluginModule, self).__init__("NODE-%s" % self.node_type,
|
||||||
|
import_name,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def jssnippets(self):
|
||||||
|
"""
|
||||||
|
Returns a snippet of javascript to include in the page
|
||||||
|
"""
|
||||||
|
# TODO: move those methods to BrowserModule subclass ?
|
||||||
|
return []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def csssnippets(self):
|
||||||
|
"""
|
||||||
|
Returns a snippet of css to include in the page
|
||||||
|
"""
|
||||||
|
# TODO: move those methods to BrowserModule subclass ?
|
||||||
|
return render_template("browser/css/node.css",
|
||||||
|
node_type=self.node_type)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_nodes(self):
|
||||||
|
"""
|
||||||
|
Each browser module is responsible for fetching
|
||||||
|
its own tree subnodes.
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
@abstractproperty
|
||||||
|
def node_type(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def node_path(self):
|
||||||
|
return '/browser/nodes/' + self.node_type
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route("/")
|
||||||
|
@login_required
|
||||||
|
def index():
|
||||||
|
"""Render and process the main browser window."""
|
||||||
|
# Get the Gravatar
|
||||||
|
gravatar = Gravatar(current_app,
|
||||||
|
size=100,
|
||||||
|
rating='g',
|
||||||
|
default='retro',
|
||||||
|
force_default=False,
|
||||||
|
use_ssl=False,
|
||||||
|
base_url=None)
|
||||||
|
return render_template(MODULE_NAME + "/index.html",
|
||||||
|
username=current_user.email)
|
||||||
|
|
||||||
|
@blueprint.route("/browser.js")
|
||||||
|
@login_required
|
||||||
|
def browser_js():
|
||||||
|
layout = get_setting('Browser/Layout', default='')
|
||||||
|
snippets = []
|
||||||
|
for submodule in current_blueprint.submodules:
|
||||||
|
snippets.extend(submodule.jssnippets)
|
||||||
|
return make_response(render_template(
|
||||||
|
'browser/js/browser.js',
|
||||||
|
layout=layout,
|
||||||
|
jssnippets=snippets),
|
||||||
|
200, {'Content-Type': 'application/x-javascript'})
|
||||||
|
|
||||||
|
@blueprint.route("/browser.css")
|
||||||
|
@login_required
|
||||||
|
def browser_css():
|
||||||
|
"""Render and return CSS snippets from the nodes and modules."""
|
||||||
|
snippets = []
|
||||||
|
for submodule in current_blueprint.submodules:
|
||||||
|
snippets.extend(submodule.csssnippets)
|
||||||
|
return make_response(render_template('browser/css/browser.css',
|
||||||
|
snippets=snippets),
|
||||||
|
200, {'Content-Type': 'text/css'})
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route("/nodes/")
|
||||||
|
@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())
|
||||||
|
return make_json_response(data=nodes)
|
||||||
|
@@ -1,21 +0,0 @@
|
|||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# pgAdmin 4 - PostgreSQL Tools
|
|
||||||
#
|
|
||||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
|
||||||
# This software is released under the PostgreSQL Licence
|
|
||||||
#
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
"""Browser application hooks"""
|
|
||||||
|
|
||||||
import os, sys
|
|
||||||
import config
|
|
||||||
|
|
||||||
from pgadmin.browser.utils import register_modules
|
|
||||||
from pgadmin.browser import all_nodes
|
|
||||||
from . import sub_nodes
|
|
||||||
|
|
||||||
def register_submodules(app):
|
|
||||||
"""Register any child node blueprints"""
|
|
||||||
register_modules(app, __file__, all_nodes, sub_nodes, 'pgadmin.browser')
|
|
@@ -6,10 +6,202 @@
|
|||||||
# This software is released under the PostgreSQL Licence
|
# This software is released under the PostgreSQL Licence
|
||||||
#
|
#
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
"""Defines views for management of server groups"""
|
||||||
|
|
||||||
# Node meta data
|
from abc import ABCMeta, abstractmethod
|
||||||
NODE_TYPE = 'server-group'
|
import traceback
|
||||||
NODE_PATH = '/browser/nodes/' + NODE_TYPE
|
from flask import Blueprint, Response, current_app, request, render_template
|
||||||
|
from flask.ext.babel import gettext
|
||||||
|
from flask.ext.security import current_user, login_required
|
||||||
|
from pgadmin import current_blueprint
|
||||||
|
from pgadmin.utils.ajax import make_json_response
|
||||||
|
from pgadmin.browser import BrowserPluginModule
|
||||||
|
from pgadmin.utils.menu import MenuItem
|
||||||
|
from pgadmin.settings.settings_model import db, ServerGroup
|
||||||
|
import config
|
||||||
|
|
||||||
# Define the child node list
|
|
||||||
sub_nodes = [ ]
|
|
||||||
|
class ServerGroupModule(BrowserPluginModule):
|
||||||
|
|
||||||
|
NODE_TYPE = "server-group"
|
||||||
|
|
||||||
|
def get_own_menuitems(self):
|
||||||
|
return {
|
||||||
|
'standard_items': [
|
||||||
|
ServerGroupMenuItem(action="drop", priority=10, function="drop_server_group"),
|
||||||
|
ServerGroupMenuItem(action="rename", priority=10, function="rename_server_group")
|
||||||
|
],
|
||||||
|
'create_items': [
|
||||||
|
ServerGroupMenuItem(name="create_server_group",
|
||||||
|
label=gettext('Server Group...'),
|
||||||
|
priority=10,
|
||||||
|
function="create_server_group",
|
||||||
|
types=[self.node_type])
|
||||||
|
],
|
||||||
|
'context_items': [
|
||||||
|
ServerGroupMenuItem(name="delete_server_group",
|
||||||
|
label=gettext('Delete server group'),
|
||||||
|
priority=10,
|
||||||
|
onclick='drop_server_group(item);'),
|
||||||
|
ServerGroupMenuItem(name="rename_server_group",
|
||||||
|
label=gettext('Rename server group...'),
|
||||||
|
priority=10,
|
||||||
|
onclick='rename_server_group(item);')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def jssnippets(self):
|
||||||
|
snippets = [render_template("server_groups/server_groups.js")]
|
||||||
|
for module in self.submodules:
|
||||||
|
snippets.extend(module.jssnippets)
|
||||||
|
return snippets
|
||||||
|
|
||||||
|
def get_nodes(self, **kwargs):
|
||||||
|
"""Return a JSON document listing the server groups for the user"""
|
||||||
|
groups = ServerGroup.query.filter_by(user_id=current_user.id)
|
||||||
|
# TODO: Move this JSON generation to a Server method
|
||||||
|
# this code is duplicated somewhere else
|
||||||
|
for group in groups:
|
||||||
|
yield {
|
||||||
|
"id": "%s/%d" % (self.node_type, group.id),
|
||||||
|
"label": group.name,
|
||||||
|
"icon": "icon-%s" % self.node_type,
|
||||||
|
"inode": True,
|
||||||
|
"_type": self.node_type
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def node_type(self):
|
||||||
|
return self.NODE_TYPE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ServerGroupMenuItem(MenuItem):
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
kwargs.setdefault("type", ServerGroupModule.NODE_TYPE)
|
||||||
|
super(ServerGroupMenuItem, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class ServerGroupPluginModule(BrowserPluginModule):
|
||||||
|
"""
|
||||||
|
Base class for server group plugins.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__metaclass__ = ABCMeta
|
||||||
|
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_nodes(self, servergroup):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Initialise the module
|
||||||
|
blueprint = ServerGroupModule( __name__, static_url_path='')
|
||||||
|
|
||||||
|
@blueprint.route("/<server_group>")
|
||||||
|
@login_required
|
||||||
|
def get_nodes(server_group):
|
||||||
|
"""Build a list of treeview nodes from the child nodes."""
|
||||||
|
nodes = []
|
||||||
|
for module in current_blueprint.submodules:
|
||||||
|
nodes.extend(module.get_nodes(server_group=server_group))
|
||||||
|
return make_json_response(data=nodes)
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/add/', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def add():
|
||||||
|
"""Add a server group node to the settings database"""
|
||||||
|
success = 1
|
||||||
|
errormsg = ''
|
||||||
|
data = { }
|
||||||
|
|
||||||
|
if request.form['name'] != '':
|
||||||
|
servergroup = ServerGroup(user_id=current_user.id, name=request.form['name'])
|
||||||
|
|
||||||
|
try:
|
||||||
|
db.session.add(servergroup)
|
||||||
|
db.session.commit()
|
||||||
|
except Exception as e:
|
||||||
|
success = 0
|
||||||
|
errormsg = e.message
|
||||||
|
|
||||||
|
else:
|
||||||
|
success = 0
|
||||||
|
errormsg = gettext('No server group name was specified')
|
||||||
|
|
||||||
|
if success == 1:
|
||||||
|
data['id'] = servergroup.id
|
||||||
|
data['name'] = servergroup.name
|
||||||
|
|
||||||
|
return make_json_response(success=success,
|
||||||
|
errormsg=errormsg,
|
||||||
|
info=traceback.format_exc(),
|
||||||
|
result=request.form,
|
||||||
|
data=data)
|
||||||
|
|
||||||
|
@blueprint.route('/delete/', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def delete():
|
||||||
|
"""Delete a server group node in the settings database"""
|
||||||
|
success = 1
|
||||||
|
errormsg = ''
|
||||||
|
|
||||||
|
if request.form['id'] != '':
|
||||||
|
# There can be only one record at most
|
||||||
|
servergroup = ServerGroup.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
|
||||||
|
|
||||||
|
if servergroup is None:
|
||||||
|
success = 0
|
||||||
|
errormsg = gettext('The specified server group could not be found.')
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
db.session.delete(servergroup)
|
||||||
|
db.session.commit()
|
||||||
|
except Exception as e:
|
||||||
|
success = 0
|
||||||
|
errormsg = e.message
|
||||||
|
|
||||||
|
else:
|
||||||
|
success = 0
|
||||||
|
errormsg = gettext('No server group was specified.')
|
||||||
|
|
||||||
|
return make_json_response(success=success,
|
||||||
|
errormsg=errormsg,
|
||||||
|
info=traceback.format_exc(),
|
||||||
|
result=request.form)
|
||||||
|
|
||||||
|
@blueprint.route('/rename/', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def rename():
|
||||||
|
"""Rename a server group node in the settings database"""
|
||||||
|
success = 1
|
||||||
|
errormsg = ''
|
||||||
|
|
||||||
|
if request.form['id'] != '':
|
||||||
|
# There can be only one record at most
|
||||||
|
servergroup = ServerGroup.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
|
||||||
|
|
||||||
|
if servergroup is None:
|
||||||
|
success = 0
|
||||||
|
errormsg = gettext('The specified server group could not be found.')
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
servergroup.name = request.form['name']
|
||||||
|
db.session.commit()
|
||||||
|
except Exception as e:
|
||||||
|
success = 0
|
||||||
|
errormsg = e.message
|
||||||
|
|
||||||
|
else:
|
||||||
|
success = 0
|
||||||
|
errormsg = gettext('No server group was specified.')
|
||||||
|
|
||||||
|
return make_json_response(success=success,
|
||||||
|
errormsg=errormsg,
|
||||||
|
info=traceback.format_exc(),
|
||||||
|
result=request.form)
|
||||||
|
@@ -1,78 +0,0 @@
|
|||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# pgAdmin 4 - PostgreSQL Tools
|
|
||||||
#
|
|
||||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
|
||||||
# This software is released under the PostgreSQL Licence
|
|
||||||
#
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
"""Integration hooks for server groups."""
|
|
||||||
|
|
||||||
from flask import render_template, url_for
|
|
||||||
from flask.ext.babel import gettext
|
|
||||||
from flask.ext.security import current_user
|
|
||||||
|
|
||||||
from pgadmin.browser.utils import register_modules
|
|
||||||
from pgadmin.settings.settings_model import db, ServerGroup
|
|
||||||
|
|
||||||
from pgadmin.browser import all_nodes
|
|
||||||
from . import NODE_TYPE, sub_nodes
|
|
||||||
|
|
||||||
def register_submodules(app):
|
|
||||||
"""Register any child node blueprints"""
|
|
||||||
register_modules(app, __file__, all_nodes, sub_nodes, 'pgadmin.browser.server_groups')
|
|
||||||
|
|
||||||
def get_nodes():
|
|
||||||
"""Return a JSON document listing the server groups for the user"""
|
|
||||||
groups = ServerGroup.query.filter_by(user_id=current_user.id)
|
|
||||||
# TODO: Move this JSON generation to a Server method
|
|
||||||
# this code is duplicated somewhere else
|
|
||||||
for group in groups:
|
|
||||||
yield {
|
|
||||||
"id": "%s/%d" % (NODE_TYPE, group.id),
|
|
||||||
"label": group.name,
|
|
||||||
"icon": "icon-%s" % NODE_TYPE,
|
|
||||||
"inode": True,
|
|
||||||
"_type": NODE_TYPE
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_standard_menu_items():
|
|
||||||
"""Return a (set) of dicts of standard menu items (create/drop/rename), with
|
|
||||||
object type, action and the function name (no parens) to call on click."""
|
|
||||||
return [
|
|
||||||
{'type': 'server-group', 'action': 'drop', 'priority': 10, 'function': 'drop_server_group'},
|
|
||||||
{'type': 'server-group', 'action': 'rename', 'priority': 20, 'function': 'rename_server_group'}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_create_menu_items():
|
|
||||||
"""Return a (set) of dicts of create menu items, with a Javascript array of
|
|
||||||
object types on which the option should appear, name, label and the function
|
|
||||||
name (no parens) to call on click."""
|
|
||||||
return [
|
|
||||||
{'type': "['server-group']", 'name': 'create_server_group', 'label': gettext('Server Group...'), 'priority': 10, 'function': 'create_server_group'}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_context_menu_items():
|
|
||||||
"""Return a (set) of dicts of content menu items with name, node type, label, priority and JS"""
|
|
||||||
return [
|
|
||||||
{'name': 'delete_server_group', 'type': NODE_TYPE, 'label': gettext('Delete server group'), 'priority': 10, 'onclick': 'drop_server_group(item);'},
|
|
||||||
{'name': 'rename_server_group', 'type': NODE_TYPE, 'label': gettext('Rename server group...'), 'priority': 20, 'onclick': 'rename_server_group(item);'}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_script_snippets():
|
|
||||||
"""Return the script snippets needed to handle treeview node operations."""
|
|
||||||
return render_template('server_groups/server_groups.js')
|
|
||||||
|
|
||||||
|
|
||||||
def get_css_snippets():
|
|
||||||
"""Return the CSS needed to display the treeview node image."""
|
|
||||||
css = ".icon-server-group {\n"
|
|
||||||
css += " background: url('%s') 0 0 no-repeat !important;\n" % \
|
|
||||||
url_for('NODE-%s.static' % NODE_TYPE, filename='img/server-group.png')
|
|
||||||
css += "}\n"
|
|
||||||
|
|
||||||
return css
|
|
@@ -6,11 +6,167 @@
|
|||||||
# This software is released under the PostgreSQL Licence
|
# This software is released under the PostgreSQL Licence
|
||||||
#
|
#
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
from flask import render_template, request
|
||||||
|
from pgadmin.browser.server_groups import ServerGroupPluginModule
|
||||||
|
from flask.ext.security import login_required, current_user
|
||||||
|
from pgadmin.settings.settings_model import db, Server
|
||||||
|
from pgadmin.utils.menu import MenuItem
|
||||||
|
from pgadmin.utils.ajax import make_json_response
|
||||||
|
import traceback
|
||||||
|
from flask.ext.babel import gettext
|
||||||
|
|
||||||
# Node meta data
|
|
||||||
NODE_TYPE = 'server'
|
|
||||||
NODE_PATH = '/browser/nodes/' + NODE_TYPE
|
|
||||||
|
|
||||||
# Define the child node list
|
class ServerModule(ServerGroupPluginModule):
|
||||||
sub_nodes = [ ]
|
|
||||||
|
NODE_TYPE = "server"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def node_type(self):
|
||||||
|
return self.NODE_TYPE
|
||||||
|
|
||||||
|
def get_nodes(self, server_group):
|
||||||
|
"""Return a JSON document listing the server groups for the user"""
|
||||||
|
servers = Server.query.filter_by(user_id=current_user.id, servergroup_id=server_group)
|
||||||
|
|
||||||
|
# TODO: Move this JSON generation to a Server method
|
||||||
|
for server in servers:
|
||||||
|
yield {
|
||||||
|
"id": "%s/%d" % (NODE_TYPE, server.id),
|
||||||
|
"label": server.name,
|
||||||
|
"icon": "icon-%s" % NODE_TYPE,
|
||||||
|
"inode": True,
|
||||||
|
"_type": NODE_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_own_menuitems(self):
|
||||||
|
return {
|
||||||
|
'standard_items': [
|
||||||
|
ServerMenuItem(action="drop", priority=50, function='drop_server'),
|
||||||
|
ServerMenuItem(action="rename", priority=50, function='rename_server')
|
||||||
|
],
|
||||||
|
'create_items': [
|
||||||
|
ServerMenuItem(types=["server-group", "server"],
|
||||||
|
name="create_server",
|
||||||
|
label=gettext('Server...'),
|
||||||
|
priority=50,
|
||||||
|
function='create_server')
|
||||||
|
],
|
||||||
|
'context_items': [
|
||||||
|
ServerMenuItem(name='delete_server',
|
||||||
|
label=gettext('Delete server'),
|
||||||
|
priority=50,
|
||||||
|
onclick='drop_server'),
|
||||||
|
ServerMenuItem(name='rename_server',
|
||||||
|
label=gettext('Rename server...'),
|
||||||
|
priority=60,
|
||||||
|
onclick='rename_server(item);')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def jssnippets(self):
|
||||||
|
return [render_template("servers/servers.js")]
|
||||||
|
|
||||||
|
|
||||||
|
class ServerMenuItem(MenuItem):
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
kwargs.setdefault("type", ServerModule.NODE_TYPE)
|
||||||
|
super(ServerMenuItem, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
blueprint = ServerModule(__name__)
|
||||||
|
|
||||||
|
@blueprint.route('/add/', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def add():
|
||||||
|
"""Add a server node to the settings database"""
|
||||||
|
success = 1
|
||||||
|
errormsg = ''
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
success = False
|
||||||
|
errormsg = ''
|
||||||
|
if request.form['name'] != '':
|
||||||
|
server = Server(user_id=current_user.id, name=request.form['name'])
|
||||||
|
try:
|
||||||
|
db.session.add(server)
|
||||||
|
db.session.commit()
|
||||||
|
success = True
|
||||||
|
except Exception as e:
|
||||||
|
errormsg = e.message
|
||||||
|
else:
|
||||||
|
errormsg = gettext('No server name was specified')
|
||||||
|
|
||||||
|
if success:
|
||||||
|
data['id'] = server.id
|
||||||
|
data['name'] = server.name
|
||||||
|
|
||||||
|
return make_json_response(success=success,
|
||||||
|
errormsg=errormsg,
|
||||||
|
info=traceback.format_exc(),
|
||||||
|
result=request.form,
|
||||||
|
data=data)
|
||||||
|
|
||||||
|
@blueprint.route('/delete/', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def delete():
|
||||||
|
"""Delete a server node in the settings database"""
|
||||||
|
success = 1
|
||||||
|
errormsg = ''
|
||||||
|
|
||||||
|
if request.form['id'] != '':
|
||||||
|
# There can be only one record at most
|
||||||
|
servergroup = Server.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
|
||||||
|
|
||||||
|
if server is None:
|
||||||
|
success = 0
|
||||||
|
errormsg = gettext('The specified server could not be found.')
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
db.session.delete(server)
|
||||||
|
db.session.commit()
|
||||||
|
except Exception as e:
|
||||||
|
success = 0
|
||||||
|
errormsg = e.message
|
||||||
|
|
||||||
|
else:
|
||||||
|
success = 0
|
||||||
|
errormsg = gettext('No server was specified.')
|
||||||
|
|
||||||
|
return make_json_response(success=success,
|
||||||
|
errormsg=errormsg,
|
||||||
|
info=traceback.format_exc(),
|
||||||
|
result=request.form)
|
||||||
|
|
||||||
|
@blueprint.route('/rename/', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def rename():
|
||||||
|
"""Rename a server node in the settings database"""
|
||||||
|
success = 1
|
||||||
|
errormsg = ''
|
||||||
|
|
||||||
|
if request.form['id'] != '':
|
||||||
|
# There can be only one record at most
|
||||||
|
servergroup = Server.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
|
||||||
|
|
||||||
|
if server is None:
|
||||||
|
success = 0
|
||||||
|
errormsg = gettext('The specified server could not be found.')
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
server.name = request.form['name']
|
||||||
|
db.session.commit()
|
||||||
|
except Exception as e:
|
||||||
|
success = 0
|
||||||
|
errormsg = e.message
|
||||||
|
|
||||||
|
else:
|
||||||
|
success = 0
|
||||||
|
errormsg = gettext('No server was specified.')
|
||||||
|
|
||||||
|
return make_json_response(success=success,
|
||||||
|
errormsg=errormsg,
|
||||||
|
info=traceback.format_exc(),
|
||||||
|
result=request.form)
|
||||||
|
|
||||||
|
@@ -1,72 +0,0 @@
|
|||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# pgAdmin 4 - PostgreSQL Tools
|
|
||||||
#
|
|
||||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
|
||||||
# This software is released under the PostgreSQL Licence
|
|
||||||
#
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
"""Integration hooks for servers."""
|
|
||||||
|
|
||||||
from flask import render_template, url_for
|
|
||||||
from flask.ext.babel import gettext
|
|
||||||
from flask.ext.security import current_user
|
|
||||||
|
|
||||||
from pgadmin.settings.settings_model import db, Server
|
|
||||||
from . import NODE_TYPE
|
|
||||||
|
|
||||||
def get_nodes(server_group):
|
|
||||||
"""Return a JSON document listing the server groups for the user"""
|
|
||||||
servers = Server.query.filter_by(user_id=current_user.id, servergroup_id=server_group)
|
|
||||||
|
|
||||||
# TODO: Move this JSON generation to a Server method
|
|
||||||
for server in servers:
|
|
||||||
yield {
|
|
||||||
"id": "%s/%d" % (NODE_TYPE, server.id),
|
|
||||||
"label": server.name,
|
|
||||||
"icon": "icon-%s" % NODE_TYPE,
|
|
||||||
"inode": True,
|
|
||||||
"_type": NODE_TYPE
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def get_standard_menu_items():
|
|
||||||
"""Return a (set) of dicts of standard menu items (create/drop/rename), with
|
|
||||||
object type, action, priority and the function to call on click."""
|
|
||||||
return [
|
|
||||||
{'type': 'server', 'action': 'drop', 'priority': 50, 'function': 'drop_server'},
|
|
||||||
{'type': 'server', 'action': 'rename', 'priority': 60, 'function': 'rename_server'}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_create_menu_items():
|
|
||||||
"""Return a (set) of dicts of create menu items, with a Javascript array of
|
|
||||||
object types on which the option should appear, name, label, priority and
|
|
||||||
the function name (no parens) to call on click."""
|
|
||||||
return [
|
|
||||||
{'type': "['server-group', 'server']", 'name': 'create_server', 'label': gettext('Server...'), 'priority': 50, 'function': 'create_server'}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_context_menu_items():
|
|
||||||
"""Return a (set) of dicts of content menu items with name, node type, label, priority and JS"""
|
|
||||||
return [
|
|
||||||
{'name': 'delete_server', 'type': NODE_TYPE, 'label': gettext('Delete server'), 'priority': 50, 'onclick': 'drop_server(item);'},
|
|
||||||
{'name': 'rename_server', 'type': NODE_TYPE, 'label': gettext('Rename server...'), 'priority': 60, 'onclick': 'rename_server(item);'}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_script_snippets():
|
|
||||||
"""Return the script snippets needed to handle treeview node operations."""
|
|
||||||
return render_template('servers/servers.js')
|
|
||||||
|
|
||||||
|
|
||||||
def get_css_snippets():
|
|
||||||
"""Return the CSS needed to display the treeview node image."""
|
|
||||||
css = ".icon-server {\n"
|
|
||||||
css += " background: url('%s') 0 0 no-repeat !important;\n" % \
|
|
||||||
url_for('NODE-%s.static' % NODE_TYPE, filename='img/server.png')
|
|
||||||
css += "}\n"
|
|
||||||
|
|
||||||
return css
|
|
@@ -1,121 +0,0 @@
|
|||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# pgAdmin 4 - PostgreSQL Tools
|
|
||||||
#
|
|
||||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
|
||||||
# This software is released under the PostgreSQL Licence
|
|
||||||
#
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
"""Defines views for management of servers"""
|
|
||||||
|
|
||||||
from flask import Blueprint, request
|
|
||||||
from flask.ext.babel import gettext
|
|
||||||
from flask.ext.security import current_user, login_required
|
|
||||||
|
|
||||||
from . import NODE_TYPE, NODE_PATH
|
|
||||||
from pgadmin.utils.ajax import make_json_response
|
|
||||||
from pgadmin.settings.settings_model import db, Server
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
# Initialise the module
|
|
||||||
blueprint = Blueprint("NODE-" + NODE_TYPE, __name__,
|
|
||||||
static_folder='static',
|
|
||||||
static_url_path='',
|
|
||||||
template_folder='templates',
|
|
||||||
url_prefix=NODE_PATH)
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route('/add/', methods=['POST'])
|
|
||||||
@login_required
|
|
||||||
def add():
|
|
||||||
"""Add a server node to the settings database"""
|
|
||||||
success = 1
|
|
||||||
errormsg = ''
|
|
||||||
data = {}
|
|
||||||
|
|
||||||
success = False
|
|
||||||
errormsg = ''
|
|
||||||
if request.form['name'] != '':
|
|
||||||
server = Server(user_id=current_user.id, name=request.form['name'])
|
|
||||||
try:
|
|
||||||
db.session.add(server)
|
|
||||||
db.session.commit()
|
|
||||||
success = True
|
|
||||||
except Exception as e:
|
|
||||||
errormsg = e.message
|
|
||||||
else:
|
|
||||||
errormsg = gettext('No server name was specified')
|
|
||||||
|
|
||||||
if success:
|
|
||||||
data['id'] = server.id
|
|
||||||
data['name'] = server.name
|
|
||||||
|
|
||||||
return make_json_response(success=success,
|
|
||||||
errormsg=errormsg,
|
|
||||||
info=traceback.format_exc(),
|
|
||||||
result=request.form,
|
|
||||||
data=data)
|
|
||||||
|
|
||||||
@blueprint.route('/delete/', methods=['POST'])
|
|
||||||
@login_required
|
|
||||||
def delete():
|
|
||||||
"""Delete a server node in the settings database"""
|
|
||||||
success = 1
|
|
||||||
errormsg = ''
|
|
||||||
|
|
||||||
if request.form['id'] != '':
|
|
||||||
# There can be only one record at most
|
|
||||||
servergroup = Server.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
|
|
||||||
|
|
||||||
if server is None:
|
|
||||||
success = 0
|
|
||||||
errormsg = gettext('The specified server could not be found.')
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
db.session.delete(server)
|
|
||||||
db.session.commit()
|
|
||||||
except Exception as e:
|
|
||||||
success = 0
|
|
||||||
errormsg = e.message
|
|
||||||
|
|
||||||
else:
|
|
||||||
success = 0
|
|
||||||
errormsg = gettext('No server was specified.')
|
|
||||||
|
|
||||||
return make_json_response(success=success,
|
|
||||||
errormsg=errormsg,
|
|
||||||
info=traceback.format_exc(),
|
|
||||||
result=request.form)
|
|
||||||
|
|
||||||
@blueprint.route('/rename/', methods=['POST'])
|
|
||||||
@login_required
|
|
||||||
def rename():
|
|
||||||
"""Rename a server node in the settings database"""
|
|
||||||
success = 1
|
|
||||||
errormsg = ''
|
|
||||||
|
|
||||||
if request.form['id'] != '':
|
|
||||||
# There can be only one record at most
|
|
||||||
servergroup = Server.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
|
|
||||||
|
|
||||||
if server is None:
|
|
||||||
success = 0
|
|
||||||
errormsg = gettext('The specified server could not be found.')
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
server.name = request.form['name']
|
|
||||||
db.session.commit()
|
|
||||||
except Exception as e:
|
|
||||||
success = 0
|
|
||||||
errormsg = e.message
|
|
||||||
|
|
||||||
else:
|
|
||||||
success = 0
|
|
||||||
errormsg = gettext('No server was specified.')
|
|
||||||
|
|
||||||
return make_json_response(success=success,
|
|
||||||
errormsg=errormsg,
|
|
||||||
info=traceback.format_exc(),
|
|
||||||
result=request.form)
|
|
||||||
|
|
@@ -79,4 +79,4 @@ function rename_server_group(item) {
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -1,129 +0,0 @@
|
|||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# pgAdmin 4 - PostgreSQL Tools
|
|
||||||
#
|
|
||||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
|
||||||
# This software is released under the PostgreSQL Licence
|
|
||||||
#
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
"""Defines views for management of server groups"""
|
|
||||||
|
|
||||||
import traceback
|
|
||||||
from flask import Blueprint, Response, current_app, request
|
|
||||||
from flask.ext.babel import gettext
|
|
||||||
from flask.ext.security import current_user, login_required
|
|
||||||
|
|
||||||
from . import NODE_TYPE, NODE_PATH, sub_nodes
|
|
||||||
from pgadmin.utils.ajax import make_json_response
|
|
||||||
from pgadmin.settings.settings_model import db, ServerGroup
|
|
||||||
import config
|
|
||||||
|
|
||||||
# Initialise the module
|
|
||||||
blueprint = Blueprint("NODE-" + NODE_TYPE, __name__, static_folder='static', static_url_path='', template_folder='templates', url_prefix=NODE_PATH)
|
|
||||||
|
|
||||||
@blueprint.route("/<server_group>")
|
|
||||||
@login_required
|
|
||||||
def get_nodes(server_group):
|
|
||||||
"""Build a list of treeview nodes from the child nodes."""
|
|
||||||
nodes = []
|
|
||||||
for node in sub_nodes:
|
|
||||||
if hasattr(node, 'hooks') and hasattr(node.hooks, 'get_nodes'):
|
|
||||||
nodes.extend(node.hooks.get_nodes(server_group))
|
|
||||||
return make_json_response(data=nodes)
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route('/add/', methods=['POST'])
|
|
||||||
@login_required
|
|
||||||
def add():
|
|
||||||
"""Add a server group node to the settings database"""
|
|
||||||
success = 1
|
|
||||||
errormsg = ''
|
|
||||||
data = { }
|
|
||||||
|
|
||||||
if request.form['name'] != '':
|
|
||||||
servergroup = ServerGroup(user_id=current_user.id, name=request.form['name'])
|
|
||||||
|
|
||||||
try:
|
|
||||||
db.session.add(servergroup)
|
|
||||||
db.session.commit()
|
|
||||||
except Exception as e:
|
|
||||||
success = 0
|
|
||||||
errormsg = e.message
|
|
||||||
|
|
||||||
else:
|
|
||||||
success = 0
|
|
||||||
errormsg = gettext('No server group name was specified')
|
|
||||||
|
|
||||||
if success == 1:
|
|
||||||
data['id'] = servergroup.id
|
|
||||||
data['name'] = servergroup.name
|
|
||||||
|
|
||||||
return make_json_response(success=success,
|
|
||||||
errormsg=errormsg,
|
|
||||||
info=traceback.format_exc(),
|
|
||||||
result=request.form,
|
|
||||||
data=data)
|
|
||||||
|
|
||||||
@blueprint.route('/delete/', methods=['POST'])
|
|
||||||
@login_required
|
|
||||||
def delete():
|
|
||||||
"""Delete a server group node in the settings database"""
|
|
||||||
success = 1
|
|
||||||
errormsg = ''
|
|
||||||
|
|
||||||
if request.form['id'] != '':
|
|
||||||
# There can be only one record at most
|
|
||||||
servergroup = ServerGroup.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
|
|
||||||
|
|
||||||
if servergroup is None:
|
|
||||||
success = 0
|
|
||||||
errormsg = gettext('The specified server group could not be found.')
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
db.session.delete(servergroup)
|
|
||||||
db.session.commit()
|
|
||||||
except Exception as e:
|
|
||||||
success = 0
|
|
||||||
errormsg = e.message
|
|
||||||
|
|
||||||
else:
|
|
||||||
success = 0
|
|
||||||
errormsg = gettext('No server group was specified.')
|
|
||||||
|
|
||||||
return make_json_response(success=success,
|
|
||||||
errormsg=errormsg,
|
|
||||||
info=traceback.format_exc(),
|
|
||||||
result=request.form)
|
|
||||||
|
|
||||||
@blueprint.route('/rename/', methods=['POST'])
|
|
||||||
@login_required
|
|
||||||
def rename():
|
|
||||||
"""Rename a server group node in the settings database"""
|
|
||||||
success = 1
|
|
||||||
errormsg = ''
|
|
||||||
|
|
||||||
if request.form['id'] != '':
|
|
||||||
# There can be only one record at most
|
|
||||||
servergroup = ServerGroup.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
|
|
||||||
|
|
||||||
if servergroup is None:
|
|
||||||
success = 0
|
|
||||||
errormsg = gettext('The specified server group could not be found.')
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
servergroup.name = request.form['name']
|
|
||||||
db.session.commit()
|
|
||||||
except Exception as e:
|
|
||||||
success = 0
|
|
||||||
errormsg = e.message
|
|
||||||
|
|
||||||
else:
|
|
||||||
success = 0
|
|
||||||
errormsg = gettext('No server group was specified.')
|
|
||||||
|
|
||||||
return make_json_response(success=success,
|
|
||||||
errormsg=errormsg,
|
|
||||||
info=traceback.format_exc(),
|
|
||||||
result=request.form)
|
|
||||||
|
|
3
web/pgadmin/browser/templates/browser/css/browser.css
Normal file
3
web/pgadmin/browser/templates/browser/css/browser.css
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{% for snip in snippets %}
|
||||||
|
{{ snip }}
|
||||||
|
{% endfor %}
|
3
web/pgadmin/browser/templates/browser/css/node.css
Normal file
3
web/pgadmin/browser/templates/browser/css/node.css
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.icon-{{node_type}} {
|
||||||
|
background: url('{{ url_for('NODE-%s.static' % node_type, filename='img/%s.png' % node_type )}}') 0 0 no-repeat;
|
||||||
|
}
|
@@ -56,7 +56,7 @@
|
|||||||
<li><a id="{{ management_item.name }}" href="{{ management_item.url }}"{% if management_item.target %} target="{{ management_item.target }}"{% endif %}{% if management_item.onclick %} onclick="{{ management_item.onclick|safe }}"{% endif %}>{{ management_item.label }}</a></li>{% endfor %}
|
<li><a id="{{ management_item.name }}" href="{{ management_item.url }}"{% if management_item.target %} target="{{ management_item.target }}"{% endif %}{% if management_item.onclick %} onclick="{{ management_item.onclick|safe }}"{% endif %}>{{ management_item.label }}</a></li>{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</li>{% endif %}
|
</li>{% endif %}
|
||||||
|
|
||||||
{% if help_items is defined and help_items|count > 0 %}<li class="dropdown">
|
{% if help_items is defined and help_items|count > 0 %}<li class="dropdown">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ _('Help') }} <span class="caret"></span></a>
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ _('Help') }} <span class="caret"></span></a>
|
||||||
<ul class="dropdown-menu" role="menu">{% for help_item in help_items %}
|
<ul class="dropdown-menu" role="menu">{% for help_item in help_items %}
|
||||||
|
@@ -1,21 +1,21 @@
|
|||||||
// Page globals
|
// Page globals
|
||||||
var docker
|
var docker;
|
||||||
var editor
|
var editor;
|
||||||
var tree
|
var tree;
|
||||||
var dashboardPanel
|
var dashboardPanel;
|
||||||
var propertiesPanel
|
var propertiesPanel;
|
||||||
var statisticsPanel
|
var statisticsPanel;
|
||||||
var dependenciesPanel
|
var dependenciesPanel;
|
||||||
var dependentsPanel
|
var dependentsPanel;
|
||||||
var sqlPanel
|
var sqlPanel;
|
||||||
var browserPanel
|
var browserPanel;
|
||||||
|
|
||||||
// Store the main browser layout
|
// Store the main browser layout
|
||||||
$(window).bind('unload', function() {
|
$(window).bind('unload', function() {
|
||||||
state = docker.save();
|
state = docker.save();
|
||||||
settings = { setting: "Browser/Layout",
|
settings = { setting: "Browser/Layout",
|
||||||
value: state }
|
value: state }
|
||||||
|
|
||||||
$.post("{{ url_for('settings.store') }}", settings);
|
$.post("{{ url_for('settings.store') }}", settings);
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -28,8 +28,8 @@ function buildPanel(docker, name, title, width, height, showTitle, isCloseable,
|
|||||||
isPrivate: isPrivate,
|
isPrivate: isPrivate,
|
||||||
onCreate: function(myPanel) {
|
onCreate: function(myPanel) {
|
||||||
myPanel.initSize(width, height);
|
myPanel.initSize(width, height);
|
||||||
|
|
||||||
if (showTitle == false)
|
if (showTitle == false)
|
||||||
myPanel.title(false);
|
myPanel.title(false);
|
||||||
|
|
||||||
myPanel.closeable(isCloseable);
|
myPanel.closeable(isCloseable);
|
||||||
@@ -46,8 +46,8 @@ function buildIFramePanel(docker, name, title, width, height, showTitle, isClose
|
|||||||
isPrivate: isPrivate,
|
isPrivate: isPrivate,
|
||||||
onCreate: function(myPanel) {
|
onCreate: function(myPanel) {
|
||||||
myPanel.initSize(width, height);
|
myPanel.initSize(width, height);
|
||||||
|
|
||||||
if (showTitle == false)
|
if (showTitle == false)
|
||||||
myPanel.title(false);
|
myPanel.title(false);
|
||||||
|
|
||||||
myPanel.closeable(isCloseable);
|
myPanel.closeable(isCloseable);
|
||||||
@@ -87,7 +87,7 @@ function report_error(message, info) {
|
|||||||
<div class="panel-body" style="overflow: scroll;">' + message + '</div>\
|
<div class="panel-body" style="overflow: scroll;">' + message + '</div>\
|
||||||
</div>\
|
</div>\
|
||||||
</div>'
|
</div>'
|
||||||
|
|
||||||
if (info != null && info != '') {
|
if (info != null && info != '') {
|
||||||
text += '<div class="panel panel-default">\
|
text += '<div class="panel panel-default">\
|
||||||
<div class="panel-heading" role="tab" id="headingTwo">\
|
<div class="panel-heading" role="tab" id="headingTwo">\
|
||||||
@@ -103,9 +103,9 @@ function report_error(message, info) {
|
|||||||
</div>\
|
</div>\
|
||||||
</div>'
|
</div>'
|
||||||
}
|
}
|
||||||
|
|
||||||
text += '</div>'
|
text += '</div>'
|
||||||
|
|
||||||
alertify.alert(
|
alertify.alert(
|
||||||
'{{ _('An error has occurred') }}',
|
'{{ _('An error has occurred') }}',
|
||||||
text
|
text
|
||||||
@@ -115,35 +115,35 @@ function report_error(message, info) {
|
|||||||
|
|
||||||
// Enable/disable menu options
|
// Enable/disable menu options
|
||||||
function enable_disable_menus() {
|
function enable_disable_menus() {
|
||||||
|
|
||||||
// Disable everything first
|
// Disable everything first
|
||||||
$("#mnu_create").html('<li class="menu-item disabled"><a href="#">{{ _('No object selected') }}</a></li>\n');
|
$("#mnu_create").html('<li class="menu-item disabled"><a href="#">{{ _('No object selected') }}</a></li>\n');
|
||||||
$("#mnu_drop_object").addClass("mnu-disabled");
|
$("#mnu_drop_object").addClass("mnu-disabled");
|
||||||
$("#mnu_rename_object").addClass("mnu-disabled");
|
$("#mnu_rename_object").addClass("mnu-disabled");
|
||||||
node_type = get_selected_node_type()
|
node_type = get_selected_node_type()
|
||||||
|
|
||||||
// List the possible standard items, their types and actions
|
// List the possible standard items, their types and actions
|
||||||
var handlers = [{% if standard_items is defined %}{% for standard_item in standard_items %}
|
var handlers = [{% for standard_item in menu_items.standard_items %}
|
||||||
"{{ standard_item.type }}:{{ standard_item.action }}",{% endfor %}{% endif %}
|
"{{ standard_item.type }}:{{ standard_item.action }}",{% endfor %}
|
||||||
]
|
]
|
||||||
|
|
||||||
// Check if we have a matching action for the object type in the list, and
|
// Check if we have a matching action for the object type in the list, and
|
||||||
// if so, enable the menu item
|
// if so, enable the menu item
|
||||||
if ($.inArray(node_type + ":drop", handlers) >= 0)
|
if ($.inArray(node_type + ":drop", handlers) >= 0)
|
||||||
$("#mnu_drop_object").removeClass("mnu-disabled");
|
$("#mnu_drop_object").removeClass("mnu-disabled");
|
||||||
|
|
||||||
if ($.inArray(node_type + ":rename", handlers) >= 0)
|
if ($.inArray(node_type + ":rename", handlers) >= 0)
|
||||||
$("#mnu_rename_object").removeClass("mnu-disabled");
|
$("#mnu_rename_object").removeClass("mnu-disabled");
|
||||||
|
|
||||||
// List the possibe create items
|
// List the possibe create items
|
||||||
var creators = [{% if create_items is defined %}{% for create_item in create_items %}
|
var creators = [{% for create_item in menu_items.create_items %}
|
||||||
[{{ create_item.type }}, "{{ create_item.name }}", "{{ create_item.label }}", "{{ create_item.function }}"],{% endfor %}{% endif %}
|
[{{ create_item.types | tojson }}, "{{ create_item.name }}", "{{ create_item.label }}", "{{ create_item.function }}"],{% endfor %}
|
||||||
]
|
]
|
||||||
|
|
||||||
// Loop through the list of creators and add links for any that apply to this
|
// Loop through the list of creators and add links for any that apply to this
|
||||||
// node type to the Create menu's UL element
|
// node type to the Create menu's UL element
|
||||||
items = ''
|
items = ''
|
||||||
|
|
||||||
for (i = 0; i < creators.length; ++i) {
|
for (i = 0; i < creators.length; ++i) {
|
||||||
if ($.inArray(node_type, creators[i][0]) >= 0) {
|
if ($.inArray(node_type, creators[i][0]) >= 0) {
|
||||||
items = items + '<li class="menu-item"><a href="#" onclick="' + creators[i][3] + '()">' + creators[i][2] + '</a></li>\n'
|
items = items + '<li class="menu-item"><a href="#" onclick="' + creators[i][3] + '()">' + creators[i][2] + '</a></li>\n'
|
||||||
@@ -158,22 +158,22 @@ function get_selected_node_type() {
|
|||||||
item = tree.selected()
|
item = tree.selected()
|
||||||
if (!item || item.length != 1)
|
if (!item || item.length != 1)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
return tree.itemData(tree.selected())._type;
|
return tree.itemData(tree.selected())._type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new object of the type currently selected
|
// Create a new object of the type currently selected
|
||||||
function create_object() {
|
function create_object() {
|
||||||
node_type = get_selected_node_type()
|
node_type = get_selected_node_type()
|
||||||
if (node_type == "")
|
if (node_type == "")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch(node_type) {
|
switch(node_type) {
|
||||||
{% if standard_items is defined %}{% for standard_item in standard_items %}{% if standard_item.action == 'create' %}
|
{% for standard_item in menu_items.standard_items %}{% if standard_item.action == 'create' %}
|
||||||
case '{{ standard_item.type }}':
|
case '{{ standard_item.type }}':
|
||||||
{{ standard_item.function }}()
|
{{ standard_item.function }}()
|
||||||
break;
|
break;
|
||||||
{% endif %}{% endfor %}{% endif %}
|
{% endif %}{% endfor %}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,13 +182,13 @@ function drop_object() {
|
|||||||
node_type = get_selected_node_type()
|
node_type = get_selected_node_type()
|
||||||
if (node_type == "")
|
if (node_type == "")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch(node_type) {
|
switch(node_type) {
|
||||||
{% if standard_items is defined %}{% for standard_item in standard_items %}{% if standard_item.action == 'drop' %}
|
{% for standard_item in menu_items.standard_items %}{% if standard_item.action == 'drop' %}
|
||||||
case '{{ standard_item.type }}':
|
case '{{ standard_item.type }}':
|
||||||
{{ standard_item.function }}(tree.selected())
|
{{ standard_item.function }}(tree.selected())
|
||||||
break;
|
break;
|
||||||
{% endif %}{% endfor %}{% endif %}
|
{% endif %}{% endfor %}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,13 +197,13 @@ function rename_object() {
|
|||||||
node_type = get_selected_node_type()
|
node_type = get_selected_node_type()
|
||||||
if (node_type == "")
|
if (node_type == "")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch(node_type) {
|
switch(node_type) {
|
||||||
{% if standard_items is defined %}{% for standard_item in standard_items %}{% if standard_item.action == 'rename' %}
|
{% for standard_item in menu_items.standard_items %}{% if standard_item.action == 'rename' %}
|
||||||
case '{{ standard_item.type }}':
|
case '{{ standard_item.type }}':
|
||||||
{{ standard_item.function }}(tree.selected())
|
{{ standard_item.function }}(tree.selected())
|
||||||
break;
|
break;
|
||||||
{% endif %}{% endfor %}{% endif %}
|
{% endif %}{% endfor %}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,37 +237,37 @@ WITH ( \n\
|
|||||||
); \n\
|
); \n\
|
||||||
ALTER TABLE tickets_detail \n\
|
ALTER TABLE tickets_detail \n\
|
||||||
OWNER TO helpdesk;\n';
|
OWNER TO helpdesk;\n';
|
||||||
|
|
||||||
buildPanel(docker, 'pnl_browser', '{{ _('Browser') }}', 300, 600, false, false, true,
|
buildPanel(docker, 'pnl_browser', '{{ _('Browser') }}', 300, 600, false, false, true,
|
||||||
'<div id="tree" class="aciTree">')
|
'<div id="tree" class="aciTree">')
|
||||||
buildIFramePanel(docker, 'pnl_dashboard', '{{ _('Dashboard') }}', 500, 600, true, false, true,
|
buildIFramePanel(docker, 'pnl_dashboard', '{{ _('Dashboard') }}', 500, 600, true, false, true,
|
||||||
'http://www.pgadmin.org/')
|
'http://www.pgadmin.org/')
|
||||||
buildPanel(docker, 'pnl_properties', '{{ _('Properties') }}', 500, 600, true, false, true,
|
buildPanel(docker, 'pnl_properties', '{{ _('Properties') }}', 500, 600, true, false, true,
|
||||||
'<p>Properties pane</p>')
|
'<p>Properties pane</p>')
|
||||||
buildPanel(docker, 'pnl_sql', '{{ _('SQL') }}', 500, 600, true, false, true,
|
buildPanel(docker, 'pnl_sql', '{{ _('SQL') }}', 500, 600, true, false, true,
|
||||||
'<textarea id="sql-textarea" name="sql-textarea">' + demoSql + '</textarea>')
|
'<textarea id="sql-textarea" name="sql-textarea">' + demoSql + '</textarea>')
|
||||||
buildPanel(docker, 'pnl_statistics', '{{ _('Statistics') }}', 500, 600, true, false, true,
|
buildPanel(docker, 'pnl_statistics', '{{ _('Statistics') }}', 500, 600, true, false, true,
|
||||||
'<p>Statistics pane</p>')
|
'<p>Statistics pane</p>')
|
||||||
buildPanel(docker, 'pnl_dependencies', '{{ _('Dependencies') }}', 500, 600, true, false, true,
|
buildPanel(docker, 'pnl_dependencies', '{{ _('Dependencies') }}', 500, 600, true, false, true,
|
||||||
'<p>Depedencies pane</p>')
|
'<p>Depedencies pane</p>')
|
||||||
buildPanel(docker, 'pnl_dependents', '{{ _('Dependents') }}', 500, 600, true, false, true,
|
buildPanel(docker, 'pnl_dependents', '{{ _('Dependents') }}', 500, 600, true, false, true,
|
||||||
'<p>Dependents pane</p>')
|
'<p>Dependents pane</p>')
|
||||||
|
|
||||||
// Add hooked-in panels
|
// Add hooked-in panels
|
||||||
{% if panel_items is defined and panel_items|count > 0 %}{% for panel_item in panel_items %}{% if panel_item.isIframe %}
|
{% for panel_item in menu_items.panel_items %}{% if panel_item.isIframe %}
|
||||||
buildIFramePanel(docker, '{{ panel_item.name }}', '{{ panel_item.title }}',
|
buildIFramePanel(docker, '{{ panel_item.name }}', '{{ panel_item.title }}',
|
||||||
{{ panel_item.width }}, {{ panel_item.height }},
|
{{ panel_item.width }}, {{ panel_item.height }},
|
||||||
{{ panel_item.showTitle|lower }}, {{ panel_item.isCloseable|lower }},
|
{{ panel_item.showTitle|lower }}, {{ panel_item.isCloseable|lower }},
|
||||||
{{ panel_item.isPrivate|lower }}, '{{ panel_item.content }}')
|
{{ panel_item.isPrivate|lower }}, '{{ panel_item.content }}')
|
||||||
{% else %}
|
{% else %}
|
||||||
buildPanel(docker, '{{ panel_item.name }}', '{{ panel_item.title }}',
|
buildPanel(docker, '{{ panel_item.name }}', '{{ panel_item.title }}',
|
||||||
{{ panel_item.width }}, {{ panel_item.height }},
|
{{ panel_item.width }}, {{ panel_item.height }},
|
||||||
{{ panel_item.showTitle|lower }}, {{ panel_item.isCloseable|lower }},
|
{{ panel_item.showTitle|lower }}, {{ panel_item.isCloseable|lower }},
|
||||||
{{ panel_item.isPrivate|lower }}, '{{ panel_item.content }}')
|
{{ panel_item.isPrivate|lower }}, '{{ panel_item.content }}')
|
||||||
{% endif %}{% endfor %}{% endif %}
|
{% endif %}{% endfor %}
|
||||||
|
|
||||||
var layout = '{{ layout }}';
|
var layout = '{{ layout }}';
|
||||||
|
|
||||||
// Try to restore the layout if there is one
|
// Try to restore the layout if there is one
|
||||||
if (layout != '') {
|
if (layout != '') {
|
||||||
try {
|
try {
|
||||||
@@ -281,7 +281,7 @@ ALTER TABLE tickets_detail \n\
|
|||||||
buildDefaultLayout()
|
buildDefaultLayout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Syntax highlight the SQL Pane
|
// Syntax highlight the SQL Pane
|
||||||
editor = CodeMirror.fromTextArea(document.getElementById("sql-textarea"), {
|
editor = CodeMirror.fromTextArea(document.getElementById("sql-textarea"), {
|
||||||
lineNumbers: true,
|
lineNumbers: true,
|
||||||
@@ -298,7 +298,7 @@ ALTER TABLE tickets_detail \n\
|
|||||||
return $.parseJSON(payload).data;
|
return $.parseJSON(payload).data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
tree = $('#tree').aciTree('api');
|
tree = $('#tree').aciTree('api');
|
||||||
|
|
||||||
@@ -310,22 +310,20 @@ ALTER TABLE tickets_detail \n\
|
|||||||
var menu = { };
|
var menu = { };
|
||||||
var createMenu = { };
|
var createMenu = { };
|
||||||
|
|
||||||
{% if create_items is defined %}
|
{% for create_item in menu_items.create_items %}
|
||||||
{% for create_item in create_items %}
|
if ($.inArray(tree.itemData(item)._type, {{ create_item.types | tojson }}) >= 0) {
|
||||||
if ($.inArray(tree.itemData(item)._type, {{ create_item.type }}) >= 0) {
|
|
||||||
createMenu['{{ create_item.name }}'] = { name: '{{ create_item.label }}', callback: function() { {{ create_item.function }}() }};
|
createMenu['{{ create_item.name }}'] = { name: '{{ create_item.label }}', callback: function() { {{ create_item.function }}() }};
|
||||||
}
|
}
|
||||||
{% endfor %}{% endif %}
|
{% endfor %}
|
||||||
|
|
||||||
menu["create"] = { "name": "Create" }
|
menu["create"] = { "name": "Create" }
|
||||||
menu["create"]["items"] = createMenu
|
menu["create"]["items"] = createMenu
|
||||||
|
|
||||||
{% if context_items is defined %}
|
{% for context_item in menu_items.context_items %}
|
||||||
{% for context_item in context_items %}
|
|
||||||
if (tree.itemData(item)._type == '{{ context_item.type }}') {
|
if (tree.itemData(item)._type == '{{ context_item.type }}') {
|
||||||
menu['{{ context_item.name }}'] = { name: '{{ context_item.label }}', callback: function() { {{ context_item.onclick }} }};
|
menu['{{ context_item.name }}'] = { name: '{{ context_item.label }}', callback: function() { {{ context_item.onclick }} }};
|
||||||
}
|
}
|
||||||
{% endfor %}{% endif %}
|
{% endfor %}
|
||||||
return {
|
return {
|
||||||
autoHide: true,
|
autoHide: true,
|
||||||
items: menu,
|
items: menu,
|
||||||
@@ -333,7 +331,7 @@ ALTER TABLE tickets_detail \n\
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Treeview event handler
|
// Treeview event handler
|
||||||
$('#tree').on('acitree', function(event, api, item, eventName, options){
|
$('#tree').on('acitree', function(event, api, item, eventName, options){
|
||||||
switch (eventName){
|
switch (eventName){
|
||||||
@@ -343,9 +341,11 @@ ALTER TABLE tickets_detail \n\
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Setup the menus
|
// Setup the menus
|
||||||
enable_disable_menus()
|
enable_disable_menus()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
{% for snippet in jssnippets %}
|
||||||
|
{{ snippet }}
|
||||||
|
{% endfor %}
|
||||||
|
@@ -1,214 +0,0 @@
|
|||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# pgAdmin 4 - PostgreSQL Tools
|
|
||||||
#
|
|
||||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
|
||||||
# This software is released under the PostgreSQL Licence
|
|
||||||
#
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
"""A blueprint module implementing the core pgAdmin browser."""
|
|
||||||
MODULE_NAME = 'browser'
|
|
||||||
|
|
||||||
from flask import Blueprint, Response, current_app, render_template, url_for
|
|
||||||
from flaskext.gravatar import Gravatar
|
|
||||||
from flask.ext.security import login_required
|
|
||||||
from flask.ext.login import current_user
|
|
||||||
from inspect import getmoduleinfo, getmembers
|
|
||||||
|
|
||||||
from . import sub_nodes
|
|
||||||
from pgadmin.browser import all_nodes
|
|
||||||
from pgadmin import modules
|
|
||||||
from pgadmin.settings import get_setting
|
|
||||||
from pgadmin.utils.ajax import make_json_response
|
|
||||||
|
|
||||||
|
|
||||||
import config
|
|
||||||
|
|
||||||
# Initialise the module
|
|
||||||
blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static', template_folder='templates', url_prefix='/' + MODULE_NAME)
|
|
||||||
|
|
||||||
@blueprint.route("/")
|
|
||||||
@login_required
|
|
||||||
def index():
|
|
||||||
"""Render and process the main browser window."""
|
|
||||||
# Get the Gravatar
|
|
||||||
gravatar = Gravatar(current_app,
|
|
||||||
size=100,
|
|
||||||
rating='g',
|
|
||||||
default='retro',
|
|
||||||
force_default=False,
|
|
||||||
use_ssl=False,
|
|
||||||
base_url=None)
|
|
||||||
|
|
||||||
# Get the plugin elements from the module
|
|
||||||
file_items = [ ]
|
|
||||||
edit_items = [ ]
|
|
||||||
tools_items = [ ]
|
|
||||||
management_items = [ ]
|
|
||||||
help_items = [ ]
|
|
||||||
stylesheets = [ ]
|
|
||||||
scripts = [ ]
|
|
||||||
|
|
||||||
modules_and_nodes = modules + all_nodes
|
|
||||||
|
|
||||||
# Add browser stylesheets
|
|
||||||
stylesheets.append(url_for('static', filename='css/codemirror/codemirror.css'))
|
|
||||||
|
|
||||||
if config.DEBUG:
|
|
||||||
stylesheets.append(url_for('static', filename='css/wcDocker/wcDockerSkeleton.css'))
|
|
||||||
else:
|
|
||||||
stylesheets.append(url_for('static', filename='css/wcDocker/wcDockerSkeleton.min.css'))
|
|
||||||
|
|
||||||
stylesheets.append(url_for('static', filename='css/wcDocker/theme.css'))
|
|
||||||
stylesheets.append(url_for('static', filename='css/jQuery-contextMenu/jquery.contextMenu.css'))
|
|
||||||
stylesheets.append(url_for('browser.static', filename='css/browser.css'))
|
|
||||||
stylesheets.append(url_for('browser.static', filename='css/aciTree/css/aciTree.css'))
|
|
||||||
stylesheets.append(url_for('browser.browser_css'))
|
|
||||||
|
|
||||||
# Add browser scripts
|
|
||||||
scripts.append(url_for('static', filename='js/codemirror/codemirror.js'))
|
|
||||||
scripts.append(url_for('static', filename='js/codemirror/mode/sql.js'))
|
|
||||||
|
|
||||||
if config.DEBUG:
|
|
||||||
scripts.append(url_for('static', filename='js/wcDocker/wcDocker.js'))
|
|
||||||
else:
|
|
||||||
scripts.append(url_for('static', filename='js/wcDocker/wcDocker.min.js'))
|
|
||||||
|
|
||||||
scripts.append(url_for('static', filename='js/jQuery-contextMenu/jquery.ui.position.js'))
|
|
||||||
scripts.append(url_for('static', filename='js/jQuery-contextMenu/jquery.contextMenu.js'))
|
|
||||||
scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciPlugin.min.js'))
|
|
||||||
scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciTree.dom.js'))
|
|
||||||
scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciTree.min.js'))
|
|
||||||
scripts.append(url_for('browser.browser_js'))
|
|
||||||
|
|
||||||
for module in modules_and_nodes:
|
|
||||||
# Get the edit menu items
|
|
||||||
if 'hooks' in dir(module) and 'get_file_menu_items' in dir(module.hooks):
|
|
||||||
file_items.extend(module.hooks.get_file_menu_items())
|
|
||||||
|
|
||||||
# Get the edit menu items
|
|
||||||
if 'hooks' in dir(module) and 'get_edit_menu_items' in dir(module.hooks):
|
|
||||||
edit_items.extend(module.hooks.get_edit_menu_items())
|
|
||||||
|
|
||||||
# Get the tools menu items
|
|
||||||
if 'hooks' in dir(module) and 'get_tools_menu_items' in dir(module.hooks):
|
|
||||||
tools_items.extend(module.hooks.get_tools_menu_items())
|
|
||||||
|
|
||||||
# Get the management menu items
|
|
||||||
if 'hooks' in dir(module) and 'get_management_menu_items' in dir(module.hooks):
|
|
||||||
management_items.extend(module.hooks.get_management_menu_items())
|
|
||||||
|
|
||||||
# Get the help menu items
|
|
||||||
if 'hooks' in dir(module) and 'get_help_menu_items' in dir(module.hooks):
|
|
||||||
help_items.extend(module.hooks.get_help_menu_items())
|
|
||||||
|
|
||||||
# Get any stylesheets
|
|
||||||
if 'hooks' in dir(module) and 'get_stylesheets' in dir(module.hooks):
|
|
||||||
stylesheets += module.hooks.get_stylesheets()
|
|
||||||
|
|
||||||
# Get any scripts
|
|
||||||
if 'hooks' in dir(module) and 'get_scripts' in dir(module.hooks):
|
|
||||||
scripts += module.hooks.get_scripts()
|
|
||||||
|
|
||||||
file_items = sorted(file_items, key=lambda k: k['priority'])
|
|
||||||
edit_items = sorted(edit_items, key=lambda k: k['priority'])
|
|
||||||
tools_items = sorted(tools_items, key=lambda k: k['priority'])
|
|
||||||
management_items = sorted(management_items, key=lambda k: k['priority'])
|
|
||||||
help_items = sorted(help_items, key=lambda k: k['priority'])
|
|
||||||
|
|
||||||
return render_template(MODULE_NAME + '/index.html',
|
|
||||||
username=current_user.email,
|
|
||||||
file_items=file_items,
|
|
||||||
edit_items=edit_items,
|
|
||||||
tools_items=tools_items,
|
|
||||||
management_items=management_items,
|
|
||||||
help_items=help_items,
|
|
||||||
stylesheets = stylesheets,
|
|
||||||
scripts = scripts)
|
|
||||||
|
|
||||||
@blueprint.route("/browser.js")
|
|
||||||
@login_required
|
|
||||||
def browser_js():
|
|
||||||
"""Render and return JS snippets from the nodes and modules."""
|
|
||||||
snippets = ''
|
|
||||||
modules_and_nodes = modules + all_nodes
|
|
||||||
|
|
||||||
# Load the core browser code first
|
|
||||||
|
|
||||||
# Get the context menu items
|
|
||||||
standard_items = [ ]
|
|
||||||
create_items = [ ]
|
|
||||||
context_items = [ ]
|
|
||||||
panel_items = [ ]
|
|
||||||
|
|
||||||
for module in modules_and_nodes:
|
|
||||||
# Get any standard menu items
|
|
||||||
if 'hooks' in dir(module) and 'get_standard_menu_items' in dir(module.hooks):
|
|
||||||
standard_items.extend(module.hooks.get_standard_menu_items())
|
|
||||||
|
|
||||||
# Get any create menu items
|
|
||||||
if 'hooks' in dir(module) and 'get_create_menu_items' in dir(module.hooks):
|
|
||||||
create_items.extend(module.hooks.get_create_menu_items())
|
|
||||||
|
|
||||||
# Get any context menu items
|
|
||||||
if 'hooks' in dir(module) and 'get_context_menu_items' in dir(module.hooks):
|
|
||||||
context_items.extend(module.hooks.get_context_menu_items())
|
|
||||||
|
|
||||||
# Get any panels
|
|
||||||
if 'hooks' in dir(module) and 'get_panels' in dir(module.hooks):
|
|
||||||
panel_items += module.hooks.get_panels()
|
|
||||||
|
|
||||||
standard_items = sorted(standard_items, key=lambda k: k['priority'])
|
|
||||||
create_items = sorted(create_items, key=lambda k: k['priority'])
|
|
||||||
context_items = sorted(context_items, key=lambda k: k['priority'])
|
|
||||||
panel_items = sorted(panel_items, key=lambda k: k['priority'])
|
|
||||||
|
|
||||||
layout = get_setting('Browser/Layout', default='')
|
|
||||||
|
|
||||||
snippets += render_template('browser/js/browser.js',
|
|
||||||
layout = layout,
|
|
||||||
standard_items = standard_items,
|
|
||||||
create_items = create_items,
|
|
||||||
context_items = context_items,
|
|
||||||
panel_items = panel_items)
|
|
||||||
|
|
||||||
# Add module and node specific code
|
|
||||||
for module in modules_and_nodes:
|
|
||||||
if 'hooks' in dir(module) and 'get_script_snippets' in dir(module.hooks):
|
|
||||||
snippets += module.hooks.get_script_snippets()
|
|
||||||
|
|
||||||
resp = Response(response=snippets,
|
|
||||||
status=200,
|
|
||||||
mimetype="application/javascript")
|
|
||||||
|
|
||||||
return resp
|
|
||||||
|
|
||||||
@blueprint.route("/browser.css")
|
|
||||||
@login_required
|
|
||||||
def browser_css():
|
|
||||||
"""Render and return CSS snippets from the nodes and modules."""
|
|
||||||
snippets = ''
|
|
||||||
modules_and_nodes = modules + all_nodes
|
|
||||||
|
|
||||||
for module in modules_and_nodes:
|
|
||||||
if 'hooks' in dir(module) and 'get_css_snippets' in dir(module.hooks):
|
|
||||||
snippets += module.hooks.get_css_snippets()
|
|
||||||
|
|
||||||
resp = Response(response=snippets,
|
|
||||||
status=200,
|
|
||||||
mimetype="text/css")
|
|
||||||
|
|
||||||
return resp
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/nodes/")
|
|
||||||
@login_required
|
|
||||||
def get_nodes():
|
|
||||||
"""Build a list of treeview nodes from the child nodes."""
|
|
||||||
value = '['
|
|
||||||
nodes = []
|
|
||||||
for node in sub_nodes:
|
|
||||||
if hasattr(node, 'hooks') and hasattr(node.hooks, 'get_nodes'):
|
|
||||||
nodes.extend(node.hooks.get_nodes())
|
|
||||||
return make_json_response(data=nodes)
|
|
@@ -0,0 +1,25 @@
|
|||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
"""A blueprint module providing utility functions for the application."""
|
||||||
|
MODULE_NAME = 'misc'
|
||||||
|
|
||||||
|
from pgadmin.utils import PgAdminModule
|
||||||
|
|
||||||
|
# Initialise the module
|
||||||
|
blueprint = PgAdminModule(MODULE_NAME, __name__,
|
||||||
|
url_prefix='')
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# A special URL used to "ping" the server
|
||||||
|
##########################################################################
|
||||||
|
@blueprint.route("/ping")
|
||||||
|
def ping():
|
||||||
|
"""Generate a "PING" response to indicate that the server is alive."""
|
||||||
|
return "PING"
|
||||||
|
@@ -1,27 +0,0 @@
|
|||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# pgAdmin 4 - PostgreSQL Tools
|
|
||||||
#
|
|
||||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
|
||||||
# This software is released under the PostgreSQL Licence
|
|
||||||
#
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
"""A blueprint module providing utility functions for the application."""
|
|
||||||
MODULE_NAME = 'misc'
|
|
||||||
|
|
||||||
import config
|
|
||||||
from flask import Blueprint, render_template
|
|
||||||
from flask.ext.security import login_required
|
|
||||||
|
|
||||||
# Initialise the module
|
|
||||||
blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static', template_folder='templates', url_prefix='')
|
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
# A special URL used to "ping" the server
|
|
||||||
##########################################################################
|
|
||||||
@blueprint.route("/ping")
|
|
||||||
def ping():
|
|
||||||
"""Generate a "PING" response to indicate that the server is alive."""
|
|
||||||
return "PING"
|
|
||||||
|
|
@@ -0,0 +1,19 @@
|
|||||||
|
from pgadmin import PgAdminModule
|
||||||
|
from flask.ext.security import login_required
|
||||||
|
from flask import redirect, url_for
|
||||||
|
|
||||||
|
MODULE_NAME = 'redirects'
|
||||||
|
|
||||||
|
blueprint = PgAdminModule(MODULE_NAME, __name__,
|
||||||
|
url_prefix='/')
|
||||||
|
|
||||||
|
@blueprint.route('/')
|
||||||
|
@login_required
|
||||||
|
def index():
|
||||||
|
"""Redirect users hitting the root to the browser"""
|
||||||
|
return redirect(url_for('browser.index'))
|
||||||
|
|
||||||
|
@blueprint.route('/favicon.ico')
|
||||||
|
def favicon():
|
||||||
|
"""Redirect to the favicon"""
|
||||||
|
return redirect(url_for('static', filename='favicon.ico'))
|
||||||
|
@@ -1,29 +0,0 @@
|
|||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# pgAdmin 4 - PostgreSQL Tools
|
|
||||||
#
|
|
||||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
|
||||||
# This software is released under the PostgreSQL Licence
|
|
||||||
#
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
"""A blueprint module providing URL redirects."""
|
|
||||||
MODULE_NAME = 'redirects'
|
|
||||||
|
|
||||||
import config
|
|
||||||
from flask import Blueprint, redirect, url_for
|
|
||||||
from flask.ext.security import login_required
|
|
||||||
|
|
||||||
# Initialise the module
|
|
||||||
blueprint = Blueprint(MODULE_NAME, __name__)
|
|
||||||
|
|
||||||
@blueprint.route('/')
|
|
||||||
@login_required
|
|
||||||
def index():
|
|
||||||
"""Redirect users hitting the root to the browser"""
|
|
||||||
return redirect(url_for('browser.index'))
|
|
||||||
|
|
||||||
@blueprint.route('/favicon.ico')
|
|
||||||
def favicon():
|
|
||||||
"""Redirect to the favicon"""
|
|
||||||
return redirect(url_for('static', filename='favicon.ico'))
|
|
@@ -14,20 +14,95 @@ from flask.ext.login import current_user
|
|||||||
from flask.ext.sqlalchemy import SQLAlchemy
|
from flask.ext.sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
from settings_model import db, Setting
|
from settings_model import db, Setting
|
||||||
|
import traceback
|
||||||
|
from flask import Blueprint, Response, abort, request, render_template
|
||||||
|
from flask.ext.security import login_required
|
||||||
|
|
||||||
|
import config
|
||||||
|
from pgadmin.utils.ajax import make_json_response
|
||||||
|
from pgadmin.utils import PgAdminModule
|
||||||
|
|
||||||
|
MODULE_NAME = 'settings'
|
||||||
|
|
||||||
def store_setting(setting, value):
|
def store_setting(setting, value):
|
||||||
"""Set a configuration setting for the current user."""
|
"""Set a configuration setting for the current user."""
|
||||||
data = Setting(user_id=current_user.id, setting=setting, value=value)
|
data = Setting(user_id=current_user.id, setting=setting, value=value)
|
||||||
|
|
||||||
db.session.merge(data)
|
db.session.merge(data)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
def get_setting(setting, default=None):
|
def get_setting(setting, default=None):
|
||||||
"""Retrieve a configuration setting for the current user, or return the
|
"""Retrieve a configuration setting for the current user, or return the
|
||||||
default value specified by the caller."""
|
default value specified by the caller."""
|
||||||
data = Setting.query.filter_by(user_id=current_user.id, setting=setting).first()
|
data = Setting.query.filter_by(user_id=current_user.id, setting=setting).first()
|
||||||
|
|
||||||
if not data or data.value is None:
|
if not data or data.value is None:
|
||||||
return default
|
return default
|
||||||
else:
|
else:
|
||||||
return data.value
|
return data.value
|
||||||
|
|
||||||
|
# Initialise the module
|
||||||
|
blueprint = PgAdminModule(MODULE_NAME, __name__, template_folder='templates', url_prefix='/' + MODULE_NAME)
|
||||||
|
|
||||||
|
@blueprint.route("/settings.js")
|
||||||
|
@login_required
|
||||||
|
def script():
|
||||||
|
"""Render the required Javascript"""
|
||||||
|
return Response(response=render_template("settings/settings.js"),
|
||||||
|
status=200,
|
||||||
|
mimetype="application/javascript")
|
||||||
|
|
||||||
|
@blueprint.route("/store", methods=['POST'])
|
||||||
|
@blueprint.route("/store/<setting>/<value>", methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def store(setting=None, value=None):
|
||||||
|
"""Store a configuration setting, or if this is a POST request and a
|
||||||
|
count value is present, store multiple settings at once."""
|
||||||
|
success = 1
|
||||||
|
errorcode = 0
|
||||||
|
errormsg = ''
|
||||||
|
|
||||||
|
try:
|
||||||
|
if request.method == 'POST':
|
||||||
|
if 'count' in request.form:
|
||||||
|
for x in range(int(request.form['count'])):
|
||||||
|
store_setting(request.form['setting%d' % (x+1)], request.form['value%d' % (x+1)])
|
||||||
|
else:
|
||||||
|
store_setting(request.form['setting'], request.form['value'])
|
||||||
|
else:
|
||||||
|
store_setting(setting, value)
|
||||||
|
except Exception as e:
|
||||||
|
success = 0
|
||||||
|
errormsg = e.message
|
||||||
|
|
||||||
|
return make_json_response(success=success,
|
||||||
|
errormsg=errormsg,
|
||||||
|
info=traceback.format_exc(),
|
||||||
|
result=request.form)
|
||||||
|
|
||||||
|
@blueprint.route("/get", methods=['POST'])
|
||||||
|
@blueprint.route("/get/<setting>", methods=['GET'])
|
||||||
|
@blueprint.route("/get/<setting>/<default>", methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def get(setting=None, default=None):
|
||||||
|
"""Get a configuration setting."""
|
||||||
|
if request.method == 'POST':
|
||||||
|
setting = request.form['setting']
|
||||||
|
default = request.form['default']
|
||||||
|
|
||||||
|
success = 1
|
||||||
|
errorcode = 0
|
||||||
|
errormsg = ''
|
||||||
|
|
||||||
|
try:
|
||||||
|
value = get_setting(setting, default)
|
||||||
|
except Exception as e:
|
||||||
|
success = 0
|
||||||
|
errormsg = e.message
|
||||||
|
|
||||||
|
return make_json_response(success=success,
|
||||||
|
errormsg=errormsg,
|
||||||
|
info=traceback.format_exc(),
|
||||||
|
result=request.form)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,83 +0,0 @@
|
|||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# pgAdmin 4 - PostgreSQL Tools
|
|
||||||
#
|
|
||||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
|
||||||
# This software is released under the PostgreSQL Licence
|
|
||||||
#
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
"""Views for setting and storing configuration options."""
|
|
||||||
MODULE_NAME = 'settings'
|
|
||||||
|
|
||||||
import traceback
|
|
||||||
from flask import Blueprint, Response, abort, request, render_template
|
|
||||||
from flask.ext.security import login_required
|
|
||||||
|
|
||||||
import config
|
|
||||||
from pgadmin.utils.ajax import make_json_response
|
|
||||||
from . import get_setting, store_setting
|
|
||||||
|
|
||||||
# Initialise the module
|
|
||||||
blueprint = Blueprint(MODULE_NAME, __name__, template_folder='templates', url_prefix='/' + MODULE_NAME)
|
|
||||||
|
|
||||||
@blueprint.route("/settings.js")
|
|
||||||
@login_required
|
|
||||||
def script():
|
|
||||||
"""Render the required Javascript"""
|
|
||||||
return Response(response=render_template("settings/settings.js"),
|
|
||||||
status=200,
|
|
||||||
mimetype="application/javascript")
|
|
||||||
|
|
||||||
@blueprint.route("/store", methods=['POST'])
|
|
||||||
@blueprint.route("/store/<setting>/<value>", methods=['GET'])
|
|
||||||
@login_required
|
|
||||||
def store(setting=None, value=None):
|
|
||||||
"""Store a configuration setting, or if this is a POST request and a
|
|
||||||
count value is present, store multiple settings at once."""
|
|
||||||
success = 1
|
|
||||||
errorcode = 0
|
|
||||||
errormsg = ''
|
|
||||||
|
|
||||||
try:
|
|
||||||
if request.method == 'POST':
|
|
||||||
if 'count' in request.form:
|
|
||||||
for x in range(int(request.form['count'])):
|
|
||||||
store_setting(request.form['setting%d' % (x+1)], request.form['value%d' % (x+1)])
|
|
||||||
else:
|
|
||||||
store_setting(request.form['setting'], request.form['value'])
|
|
||||||
else:
|
|
||||||
store_setting(setting, value)
|
|
||||||
except Exception as e:
|
|
||||||
success = 0
|
|
||||||
errormsg = e.message
|
|
||||||
|
|
||||||
return make_json_response(success=success,
|
|
||||||
errormsg=errormsg,
|
|
||||||
info=traceback.format_exc(),
|
|
||||||
result=request.form)
|
|
||||||
|
|
||||||
@blueprint.route("/get", methods=['POST'])
|
|
||||||
@blueprint.route("/get/<setting>", methods=['GET'])
|
|
||||||
@blueprint.route("/get/<setting>/<default>", methods=['GET'])
|
|
||||||
@login_required
|
|
||||||
def get(setting=None, default=None):
|
|
||||||
"""Get a configuration setting."""
|
|
||||||
if request.method == 'POST':
|
|
||||||
setting = request.form['setting']
|
|
||||||
default = request.form['default']
|
|
||||||
|
|
||||||
success = 1
|
|
||||||
errorcode = 0
|
|
||||||
errormsg = ''
|
|
||||||
|
|
||||||
try:
|
|
||||||
value = get_setting(setting, default)
|
|
||||||
except Exception as e:
|
|
||||||
success = 0
|
|
||||||
errormsg = e.message
|
|
||||||
|
|
||||||
return make_json_response(success=success,
|
|
||||||
errormsg=errormsg,
|
|
||||||
info=traceback.format_exc(),
|
|
||||||
result=request.form)
|
|
@@ -20,23 +20,21 @@
|
|||||||
{% if config.DEBUG %}<link rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/themes/bootstrap.css') }}" />{% else %}<link rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/themes/bootstrap.min.css') }}" />{% endif %}
|
{% if config.DEBUG %}<link rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/themes/bootstrap.css') }}" />{% else %}<link rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/themes/bootstrap.min.css') }}" />{% endif %}
|
||||||
{% if config.DEBUG %}<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-theme.min.css') }}">{% else %}<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-theme.min.css') }}">{% endif %}
|
{% if config.DEBUG %}<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-theme.min.css') }}">{% else %}<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-theme.min.css') }}">{% endif %}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/overrides.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/overrides.css') }}">
|
||||||
{% if stylesheets is defined %}
|
|
||||||
<!-- View specified stylesheets -->
|
<!-- View specified stylesheets -->
|
||||||
{% for stylesheet in stylesheets %}
|
{% for stylesheet in current_blueprint.stylesheets %}
|
||||||
<link rel="stylesheet" href="{{ stylesheet }}">{% endfor %}
|
<link rel="stylesheet" href="{{ stylesheet }}">
|
||||||
{% endif %}
|
{% endfor %}
|
||||||
|
|
||||||
<!-- Base template scripts -->
|
<!-- Base template scripts -->
|
||||||
<script src="{{ url_for('static', filename='js/modernizr-2.6.2-respond-1.1.0.min.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/modernizr-2.6.2-respond-1.1.0.min.js') }}"></script>
|
||||||
{% if config.DEBUG %}<script src="{{ url_for('static', filename='js/jquery-1.11.2.js') }}">{% else %}<script src="{{ url_for('static', filename='js/jquery-1.11.2.min.js') }}">{% endif %}</script>
|
{% if config.DEBUG %}<script src="{{ url_for('static', filename='js/jquery-1.11.2.js') }}">{% else %}<script src="{{ url_for('static', filename='js/jquery-1.11.2.min.js') }}">{% endif %}</script>
|
||||||
{% if config.DEBUG %}<script src="{{ url_for('static', filename='js/bootstrap.js') }}">{% else %}<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}">{% endif %}</script>
|
{% if config.DEBUG %}<script src="{{ url_for('static', filename='js/bootstrap.js') }}">{% else %}<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}">{% endif %}</script>
|
||||||
{% if config.DEBUG %}<script src="{{ url_for('static', filename='js/alertifyjs/alertify.js') }}">{% else %}<script src="{{ url_for('static', filename='js/alertifyjs/alertify.min.js') }}">{% endif %}</script>
|
{% if config.DEBUG %}<script src="{{ url_for('static', filename='js/alertifyjs/alertify.js') }}">{% else %}<script src="{{ url_for('static', filename='js/alertifyjs/alertify.min.js') }}">{% endif %}</script>
|
||||||
<script src="{{ url_for('static', filename='js/alertifyjs/pgadmin.defaults.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/alertifyjs/pgadmin.defaults.js') }}"></script>
|
||||||
{% if scripts is defined %}
|
|
||||||
<!-- View specified scripts -->
|
<!-- View specified scripts -->
|
||||||
{% for script in scripts %}
|
|
||||||
<script src="{{ script }}"></script>{% endfor %}
|
{% for script in current_blueprint.javascripts %}
|
||||||
{% endif %}
|
<script src="{{ script }}"></script>
|
||||||
|
{% endfor %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!--[if lt IE 7]>
|
<!--[if lt IE 7]>
|
||||||
|
@@ -0,0 +1,80 @@
|
|||||||
|
from flask import Blueprint
|
||||||
|
from collections import defaultdict
|
||||||
|
from operator import attrgetter
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PgAdminModule(Blueprint):
|
||||||
|
"""
|
||||||
|
Base class for every PgAdmin Module.
|
||||||
|
|
||||||
|
This class defines a set of method and attributes that
|
||||||
|
every module should implement.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, import_name, **kwargs):
|
||||||
|
kwargs.setdefault('url_prefix', '/' + name)
|
||||||
|
kwargs.setdefault('template_folder', 'templates')
|
||||||
|
kwargs.setdefault('static_folder', 'static')
|
||||||
|
self.submodules = []
|
||||||
|
super(PgAdminModule, self).__init__(name, import_name, **kwargs)
|
||||||
|
|
||||||
|
def register(self, app, options, first_registration=False):
|
||||||
|
"""
|
||||||
|
Override the default register function to automagically register
|
||||||
|
sub-modules at once.
|
||||||
|
"""
|
||||||
|
if first_registration:
|
||||||
|
self.submodules = list(app.find_submodules(self.import_name))
|
||||||
|
super(PgAdminModule, self).register(app, options, first_registration)
|
||||||
|
for module in self.submodules:
|
||||||
|
app.register_blueprint(module)
|
||||||
|
|
||||||
|
def get_own_stylesheets(self):
|
||||||
|
"""
|
||||||
|
Returns:
|
||||||
|
list: the stylesheets used by this module, not including any
|
||||||
|
stylesheet needed by the submodules.
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_own_javascripts(self):
|
||||||
|
"""
|
||||||
|
Returns:
|
||||||
|
list: the javascripts used by this module, not including
|
||||||
|
any script needed by the submodules.
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_own_menuitems(self):
|
||||||
|
"""
|
||||||
|
Returns:
|
||||||
|
dict: the menuitems for this module, not including
|
||||||
|
any needed from the submodules.
|
||||||
|
"""
|
||||||
|
return defaultdict(list)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stylesheets(self):
|
||||||
|
stylesheets = self.get_own_stylesheets()
|
||||||
|
for module in self.submodules:
|
||||||
|
stylesheets.extend(module.stylesheets)
|
||||||
|
return stylesheets
|
||||||
|
|
||||||
|
@property
|
||||||
|
def javascripts(self):
|
||||||
|
javascripts = self.get_own_javascripts()
|
||||||
|
for module in self.submodules:
|
||||||
|
javascripts.extend(module.javascripts)
|
||||||
|
return javascripts
|
||||||
|
|
||||||
|
@property
|
||||||
|
def menu_items(self):
|
||||||
|
menu_items = self.get_own_menuitems()
|
||||||
|
for module in self.submodules:
|
||||||
|
for key, value in module.menu_items.items():
|
||||||
|
menu_items[key].extend(value)
|
||||||
|
menu_items = {key: sorted(values, key=attrgetter('priority'))
|
||||||
|
for key, values in menu_items.items()}
|
||||||
|
return menu_items
|
||||||
|
6
web/pgadmin/utils/menu.py
Normal file
6
web/pgadmin/utils/menu.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
class MenuItem(object):
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.__dict__.update(**kwargs)
|
Reference in New Issue
Block a user