diff --git a/web/pgadmin/browser/server_groups/servers/roles/__init__.py b/web/pgadmin/browser/server_groups/servers/roles/__init__.py new file mode 100644 index 0000000..9557d6c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/__init__.py @@ -0,0 +1,901 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +from flask import render_template, request, current_app, jsonify +from flask.ext.babel import gettext as _ +from pgadmin.utils.ajax import make_json_response, \ + make_response as ajax_response, precondition_required, \ + internal_server_error, forbidden, \ + not_implemented, success_return +from pgadmin.browser.utils import NodeView +from pgadmin.browser.collection import CollectionNodeModule +import pgadmin.browser.server_groups as sg +from pgadmin.utils.driver import get_driver +from config import PG_DEFAULT_DRIVER +import re +import datetime +from functools import wraps +import simplejson as json + + +class RoleModule(CollectionNodeModule): + NODE_TYPE = 'role' + COLLECTION_LABEL = _("Login/Group Roles") + + def __init__(self, *args, **kwargs): + self.min_ver = None + self.max_ver = None + + super(RoleModule, self).__init__(*args, **kwargs) + + def get_nodes(self, gid, sid): + """ + Generate the collection node + """ + + yield self.generate_browser_collection_node(sid) + + @property + def script_load(self): + """ + Load the module script for server, when any of the server-group node is + initialized. + """ + return sg.ServerGroupModule.NODE_TYPE + + @property + def csssnippets(self): + """ + Returns a snippet of css to include in the page + """ + snippets = [ + render_template( + "browser/css/collection.css", + node_type=self.node_type + ), + render_template("role/css/role.css")] + + for submodule in self.submodules: + snippets.extend(submodule.csssnippets) + + return snippets + + +blueprint = RoleModule(__name__) + + +class RoleView(NodeView): + node_type = 'role' + + parent_ids = [ + {'type': 'int', 'id': 'gid'}, + {'type': 'int', 'id': 'sid'} + ] + ids = [ + {'type': 'int', 'id': 'rid'} + ] + + operations = dict({ + 'obj': [ + {'get': 'properties', 'delete': 'drop', 'put': 'update'}, + {'get': 'list', 'post': 'create'} + ], + 'nodes': [{'get': 'node'}, {'get': 'nodes'}], + 'sql': [{'get': 'sql'}], + 'msql': [{'get': 'msql'}, {'get': 'msql'}], + 'dependency': [{'get': 'dependencies'}], + 'dependent': [{'get': 'dependents'}], + 'children': [{'get': 'children'}], + 'module.js': [{}, {}, {'get': 'module_js'}], + 'vopts': [{}, {'get': 'voptions'}], + 'variables': [{'get': 'variables'}], + }) + + def validate_request(f): + @wraps(f) + def wrap(self, **kwargs): + + data = None + if request.data: + data = json.loads(request.data) + else: + data = dict() + req = request.args or request.form + + for key in req: + + val = req[key] + if key in [ + u'rolcanlogin', u'rolsuper', u'rolcreatedb', + u'rolcreaterole', u'rolinherit', u'rolreplication', + u'rolcatupdate', u'variables', u'rolmembership', + u'seclabels' + ]: + data[key] = json.loads(val) + else: + data[key] = val + + if u'rid' not in kwargs or kwargs['rid'] == -1: + if u'rolname' not in data: + return precondition_required( + _("Name is not provided!") + ) + + if u'rolconnlimit' in data: + if data[u'rolconnlimit'] is not None: + data[u'rolconnlimit'] = int(data[u'rolconnlimit']) + if type(data[u'rolconnlimit']) != int or data[u'rolconnlimit'] < -1: + return precondition_required( + _("Connection limit must be an integer value or equals to -1!") + ) + + if u'rolmembership' in data: + if u'rid' not in kwargs or kwargs['rid'] == -1: + msg = _(""" +Role membership information must be passed as an array of JSON object in the +following format: + +rolmembership:[{ + role: [rolename], + admin: True/False + }, + ... +]""") + if type(data[u'rolmembership']) != list: + return precondition_required(msg) + + data[u'members'] = [] + data[u'admins'] = [] + + for r in data[u'rolmembership']: + if type(r) != dict or u'role' not in r or u'admin' not in r: + return precondition_required(msg) + else: + if r[u'admin']: + data[u'admins'].append(r[u'role']) + else: + data[u'members'].append(r[u'role']) + else: + msg = _(""" +Role membership information must be passed a string representing an array of +JSON object in the following format: +rolmembership:{ + 'added': [{ + role: [rolename], + admin: True/False + }, + ... + ], + 'deleted': [{ + role: [rolename], + admin: True/False + }, + ... + ], + 'updated': [{ + role: [rolename], + admin: True/False + }, + ... + ] +""") + if type(data[u'rolmembership']) != dict: + return precondition_required(msg) + + data[u'members'] = [] + data[u'admins'] = [] + data[u'revoked_admins'] = [] + data[u'revoked'] = [] + + if u'added' in data[u'rolmembership']: + roles = (data[u'rolmembership'])[u'added'] + + if type(roles) != list: + return precondition_required(msg) + + for r in roles: + if (type(r) != dict or u'role' not in r or + u'admin' not in r): + return precondition_required(msg) + + if r[u'admin']: + data[u'admins'].append(r[u'role']) + else: + data[u'members'].append(r[u'role']) + + if u'deleted' in data[u'rolmembership']: + roles = (data[u'rolmembership'])[u'deleted'] + + if type(roles) != list: + return precondition_required(msg) + + for r in roles: + if type(r) != dict or u'role' not in r: + return precondition_required(msg) + + data[u'revoked'].append(r[u'role']) + + if u'changed' in data[u'rolmembership']: + roles = (data[u'rolmembership'])[u'changed'] + + if type(roles) != list: + return precondition_required(msg) + + for r in roles: + if (type(r) != dict or u'role' not in r or + u'admin' not in r): + return precondition_required(msg) + + if not r[u'admin']: + data[u'revoked_admins'].append(r[u'role']) + else: + data[u'admins'].append(r[u'role']) + + if self.manager.version >= 90200: + if u'seclabels' in data: + if u'rid' not in kwargs or kwargs['rid'] == -1: + msg = _(""" +Security Label must be passed as an array of JSON object in the following +format: +seclabels:[{ + provider: , + label: