Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
__init__.py636 linesDownload Raw Back to grant_wizard
1##########################################################################2#3# pgAdmin 4 - PostgreSQL Tools4#5# Copyright (C) 2013 - 2024, The pgAdmin Development Team6# This software is released under the PostgreSQL Licence7#8##########################################################################9 10"""Implements Grant Wizard"""11 12import json13from flask import Response, url_for14from flask import render_template, request, current_app15from flask_babel import gettext16from pgadmin.user_login_check import pga_login_required17from urllib.parse import unquote18 19from pgadmin.browser.server_groups.servers.utils import parse_priv_to_db20from pgadmin.utils import PgAdminModule21from pgadmin.utils.ajax import make_response as ajax_response, \22    make_json_response, internal_server_error, bad_request23from pgadmin.utils.driver import get_driver24 25from config import PG_DEFAULT_DRIVER26from pgadmin.utils.ajax import precondition_required27from functools import wraps28from pgadmin.utils.preferences import Preferences29from pgadmin.utils.constants import MIMETYPE_APP_JS30 31# set template path for sql scripts32MODULE_NAME = 'grant_wizard'33server_info = {}34 35 36class GrantWizardModule(PgAdminModule):37    """38    class GrantWizardModule():39 40        It is a wizard which inherits PgAdminModule41        class and define methods to load its own42        javascript file.43    """44 45    def show_system_objects(self):46        """47        return system preference objects48        """49        return self.pref_show_system_objects50 51    def register_preferences(self):52        """53        Get show_system_objects preference54        """55        self.browser_preference = Preferences.module('browser')56        self.pref_show_system_objects = self.browser_preference.preference(57            'show_system_objects'58        )59 60    def get_exposed_url_endpoints(self):61        """62        Returns:63            list: URL endpoints for grant-wizard module64        """65        return [66            'grant_wizard.acl', 'grant_wizard.objects', 'grant_wizard.apply',67            'grant_wizard.modified_sql'68        ]69 70 71# Create blueprint for GrantWizardModule class72blueprint = GrantWizardModule(73    MODULE_NAME, __name__, static_url_path='')74 75 76def check_precondition(f):77    """78    This function will behave as a decorator which will checks79    database connection before running view, it will also attaches80    manager,conn & template_path properties to instance of the method.81 82    Assumptions:83        This function will always be used as decorator of a class method.84    """85 86    @wraps(f)87    def wrap(*args, **kwargs):88        # Here args[0] will hold self & kwargs will hold sid,did89 90        server_info.clear()91        server_info['manager'] = get_driver(PG_DEFAULT_DRIVER)\92            .connection_manager(kwargs['sid'])93        server_info['conn'] = server_info['manager'].connection(94            did=kwargs['did']95        )96        # If DB not connected then return error to browser97        if not server_info['conn'].connected():98            return precondition_required(99                gettext("Connection to the server has been lost.")100            )101 102        # Set template path for sql scripts103        server_info['server_type'] = server_info['manager'].server_type104        server_info['version'] = server_info['manager'].version105        if server_info['server_type'] == 'pg':106            server_info['template_path'] = 'grant_wizard/pg/#{0}#'.format(107                server_info['version'])108        elif server_info['server_type'] == 'ppas':109            server_info['template_path'] = 'grant_wizard/ppas/#{0}#'.format(110                server_info['version'])111 112        return f(*args, **kwargs)113 114    return wrap115 116 117@blueprint.route("/")118@pga_login_required119def index():120    return bad_request(121        errormsg=gettext("This URL cannot be called directly.")122    )123 124 125@blueprint.route("/grant_wizard.js")126@pga_login_required127def script():128    """render own javascript"""129    return Response(response=render_template(130        "grant_wizard/js/grant_wizard.js", _=gettext),131        status=200,132        mimetype=MIMETYPE_APP_JS)133 134 135@blueprint.route(136    '/acl/<int:sid>/<int:did>/', methods=['GET'], endpoint='acl'137)138@pga_login_required139@check_precondition140def acl_list(sid, did):141    """render list of acls"""142    server_prop = server_info143    return Response(response=render_template(144        server_prop['template_path'] + "/acl.json", _=gettext),145        status=200,146        mimetype="application/json")147 148 149def _get_rows_for_type(conn, ntype, server_prop, node_id):150    """151    Used internally by properties to get rows for an object type152    :param conn: connection object153    :param ntype: object type154    :param server_prop: server properties155    :param node_id: oid156    :return: status, execute response157    """158    function_sql_url = '/sql/function.sql'159    status, res = True, []160 161    if ntype in ['function']:162        sql = render_template("/".join(163            [server_prop['template_path'], function_sql_url]),164            node_id=node_id, type='function')165 166        status, res = conn.execute_dict(sql)167    # Fetch procedures only if server type is EPAS or PG >= 11168    elif len(server_prop) > 0 and (169        server_prop['server_type'] == 'ppas' or (170            server_prop['server_type'] == 'pg' and171            server_prop['version'] >= 11000172        )173    ) and ntype in ['procedure']:174        sql = render_template("/".join(175            [server_prop['template_path'], function_sql_url]),176            node_id=node_id, type='procedure')177 178        status, res = conn.execute_dict(sql)179 180    # Fetch trigger functions181    elif ntype in ['trigger_function']:182        sql = render_template("/".join(183            [server_prop['template_path'], function_sql_url]),184            node_id=node_id, type='trigger_function')185        status, res = conn.execute_dict(sql)186 187    # Fetch Sequences against schema188    elif ntype in ['sequence']:189        sql = render_template("/".join(190            [server_prop['template_path'], '/sql/sequence.sql']),191            node_id=node_id)192 193        status, res = conn.execute_dict(sql)194 195    # Fetch Tables against schema196    elif ntype in ['table']:197        sql = render_template("/".join(198            [server_prop['template_path'], '/sql/table.sql']),199            node_id=node_id)200 201        status, res = conn.execute_dict(sql)202 203    # Fetch Views against schema204    elif ntype in ['view']:205        sql = render_template("/".join(206            [server_prop['template_path'], '/sql/view.sql']),207            node_id=node_id, node_type='v')208 209        status, res = conn.execute_dict(sql)210 211    # Fetch Materialzed Views against schema212    elif ntype in ['mview']:213        sql = render_template("/".join(214            [server_prop['template_path'], '/sql/view.sql']),215            node_id=node_id, node_type='m')216 217        status, res = conn.execute_dict(sql)218    # Fetch Foreign tables.219    elif ntype in ['foreign_table']:220        sql = render_template("/".join(221            [server_prop['template_path'], '/sql/foreign_table.sql']),222            node_id=node_id, node_type='m')223 224        status, res = conn.execute_dict(sql)225 226    # Logic for generating privileges sql only for ppas227    # Fetch Packages.228    if server_prop['server_type'] == 'ppas' and ntype in ['package']:229        sql = render_template("/".join(230            [server_prop['template_path'], '/sql/package.sql']),231            node_id=node_id)232 233        status, res = conn.execute_dict(sql)234 235    return status, res236 237 238def get_node_sql_with_type(node_id, node_type, server_prop,239                           get_schema_sql_url, show_sysobj):240    if node_type == 'database':241        sql = render_template("/".join(242            [server_prop['template_path'], get_schema_sql_url]),243            show_sysobj=show_sysobj)244        ntype = 'schema'245    else:246        sql = render_template("/".join(247            [server_prop['template_path'], get_schema_sql_url]),248            show_sysobj=show_sysobj, nspid=node_id)249        ntype = node_type250 251    return sql, ntype252 253 254@blueprint.route(255    '/<int:sid>/<int:did>/<int:node_id>/<node_type>/',256    methods=['GET'], endpoint='objects'257)258@pga_login_required259@check_precondition260def properties(sid, did, node_id, node_type):261    """It fetches the properties of object types262       and render into selection page of wizard263    """264 265    res_data, msg = get_data(sid, did, node_id, node_type, server_info)266 267    if res_data is None and isinstance(msg, Response):268        return msg269 270    return make_json_response(271        result=res_data,272        info=msg,273        status=200274    )275 276 277def get_data(sid, did, node_id, node_type, server_data,278             return_emtpy_schema=False):279    get_schema_sql_url = '/sql/get_schemas.sql'280 281    # unquote encoded url parameter282    node_type = unquote(node_type)283 284    server_prop = server_data285 286    res_data = []287    failed_objects = []288    manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)289    conn = manager.connection(did=did)290 291    show_sysobj = blueprint.show_system_objects().get()292 293    sql, ntype = get_node_sql_with_type(node_id, node_type, server_prop,294                                        get_schema_sql_url, show_sysobj)295 296    status, res = conn.execute_dict(sql)297 298    if not status:299        return None, internal_server_error(errormsg=res)300    node_types = res['rows']301 302    def _append_rows(status, res, disp_type):303        if not status:304            current_app.logger.error(res)305            failed_objects.append(disp_type)306        else:307            if len(res) > 0:308                res_data.extend(res['rows'])309 310    empty_schema_list = []311    for row in node_types:312        is_empty_schema = True313        if 'oid' in row:314            node_id = row['oid']315 316        if ntype == 'schema':317            status, res = _get_rows_for_type(318                conn, 'function', server_prop, node_id)319 320            _append_rows(status, res, 'function')321 322            status, res = _get_rows_for_type(323                conn, 'procedure', server_prop, node_id)324 325            _append_rows(status, res, 'procedure')326 327            status, res = _get_rows_for_type(328                conn, 'trigger_function', server_prop, node_id)329 330            _append_rows(status, res, 'trigger function')331 332            status, res = _get_rows_for_type(333                conn, 'sequence', server_prop, node_id)334 335            if len(res['rows']):336                is_empty_schema = False337 338            _append_rows(status, res, 'sequence')339 340            status, res = _get_rows_for_type(341                conn, 'table', server_prop, node_id)342 343            if len(res['rows']):344                is_empty_schema = False345 346            _append_rows(status, res, 'table')347 348            status, res = _get_rows_for_type(349                conn, 'view', server_prop, node_id)350 351            if len(res['rows']):352                is_empty_schema = False353 354            _append_rows(status, res, 'view')355 356            status, res = _get_rows_for_type(357                conn, 'mview', server_prop, node_id)358 359            if len(res['rows']):360                is_empty_schema = False361 362            _append_rows(status, res, 'materialized view')363 364            status, res = _get_rows_for_type(365                conn, 'foreign_table', server_prop, node_id)366 367            if len(res['rows']):368                is_empty_schema = False369 370            _append_rows(status, res, 'foreign table')371 372            status, res = _get_rows_for_type(373                conn, 'package', server_prop, node_id)374 375            if (type(res) is list and len(res) > 0) or (376                    'rows' in res and len(res['rows']) > 0):377                is_empty_schema = False378 379            _append_rows(status, res, 'package')380 381            if is_empty_schema and row['name'] not in empty_schema_list:382                empty_schema_list.append(row['name'])383 384        else:385            status, res = _get_rows_for_type(conn, ntype, server_prop, node_id)386            _append_rows(status, res, 'function')387 388    msg = None389    if len(failed_objects) > 0:390        msg = gettext('Unable to fetch the {} objects'.format(391            ", ".join(failed_objects))392        )393    if return_emtpy_schema:394        return res_data, msg, empty_schema_list395 396    return res_data, msg397 398 399def get_req_data():400    return request.form if request.form else json.loads(request.data.decode())401 402 403def set_priv_for_package(server_prop, data, acls):404    if server_prop['server_type'] == 'ppas':405        data['priv']['package'] = parse_priv_to_db(406            data['acl'],407            acls['package']['acl'])408 409 410@blueprint.route(411    '/sql/<int:sid>/<int:did>/',412    methods=['POST'], endpoint='modified_sql'413)414@pga_login_required415@check_precondition416def msql(sid, did):417    """418    This function will return modified SQL419    """420    server_prop = server_info421    data = get_req_data()422    # Form db connection423    manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)424    conn = manager.connection(did=did)425 426    acls = []427    try:428        acls = render_template(429            "/".join([server_prop['template_path'], '/acl.json'])430        )431        acls = json.loads(acls)432    except Exception as e:433        current_app.logger.exception(e)434 435    try:436        # Parse privileges437        data['priv'] = {}438        if 'acl' in data:439            # Get function acls440            data['priv']['function'] = parse_priv_to_db(441                data['acl'],442                acls['function']['acl'])443 444            data['priv']['sequence'] = parse_priv_to_db(445                data['acl'],446                acls['sequence']['acl'])447 448            data['priv']['table'] = parse_priv_to_db(449                data['acl'],450                acls['table']['acl'])451 452            data['priv']['foreign_table'] = parse_priv_to_db(453                data['acl'],454                acls['foreign_table']['acl'])455 456            # Logic for setting privileges only for ppas457            set_priv_for_package(server_prop, data, acls)458 459        # Pass database objects and get SQL for privileges460        sql_data = ''461        data_func = {'objects': data['objects'],462                     'priv': data['priv']['function']}463        sql = render_template(464            "/".join([server_prop['template_path'],465                      '/sql/grant_function.sql']),466            data=data_func, conn=conn)467        if sql and sql.strip('\n') != '':468            sql_data += sql469 470        data_seq = {'objects': data['objects'],471                    'priv': data['priv']['sequence']}472        sql = render_template(473            "/".join([server_prop['template_path'],474                      '/sql/grant_sequence.sql']),475            data=data_seq, conn=conn)476        if sql and sql.strip('\n') != '':477            sql_data += sql478 479        data_table = {'objects': data['objects'],480                      'priv': data['priv']['table']}481        sql = render_template(482            "/".join([server_prop['template_path'], '/sql/grant_table.sql']),483            data=data_table, conn=conn)484        if sql and sql.strip('\n') != '':485            sql_data += sql486 487        data_table = {'objects': data['objects'],488                      'priv': data['priv']['foreign_table']}489        sql = render_template(490            "/".join([server_prop['template_path'],491                      '/sql/grant_foreign_table.sql']),492            data=data_table, conn=conn)493        if sql and sql.strip('\n') != '':494            sql_data += sql495 496        # Logic for generating privileges sql only for ppas497        if server_prop['server_type'] == 'ppas':498            data_package = {'objects': data['objects'],499                            'priv': data['priv']['package']}500            sql = render_template(501                "/".join([server_prop['template_path'],502                          '/sql/grant_package.sql']),503                data=data_package, conn=conn)504            if sql and sql.strip('\n') != '':505                sql_data += sql506 507        res = {'data': sql_data}508 509        return ajax_response(510            response=res,511            status=200512        )513 514    except Exception as e:515        return make_json_response(516            status=410,517            success=0,518            errormsg=e.message519        )520 521 522def parse_priv(data, acls, server_prop):523    if 'acl' in data:524        # Get function acls525        data['priv']['function'] = parse_priv_to_db(526            data['acl'],527            acls['function']['acl'])528 529        data['priv']['sequence'] = parse_priv_to_db(530            data['acl'],531            acls['sequence']['acl'])532 533        data['priv']['table'] = parse_priv_to_db(534            data['acl'],535            acls['table']['acl'])536 537        data['priv']['foreign_table'] = parse_priv_to_db(538            data['acl'],539            acls['foreign_table']['acl'])540 541        # Logic for setting privileges only for ppas542        set_priv_for_package(server_prop, data, acls)543 544 545@blueprint.route(546    '/<int:sid>/<int:did>/', methods=['POST'], endpoint='apply'547)548@pga_login_required549@check_precondition550def save(sid, did):551    """552    This function will apply the privileges to the selected553    Database Objects554    """555    server_prop = server_info556    data = get_req_data()557 558    # Form db connection and we use conn to execute sql559    manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)560    conn = manager.connection(did=did)561 562    acls = []563    try:564        acls = render_template(565            "/".join([server_prop['template_path'], 'acl.json']),566        )567        acls = json.loads(acls)568    except Exception as e:569        current_app.logger.exception(e)570 571    try:572 573        # Parse privileges574        data['priv'] = {}575        parse_priv(data, acls, server_prop)576        # Pass database objects and get SQL for privileges577        # Pass database objects and get SQL for privileges578        sql_data = ''579        data_func = {'objects': data['objects'],580                     'priv': data['priv']['function']}581        sql = render_template(582            "/".join([server_prop['template_path'],583                      '/sql/grant_function.sql']),584            data=data_func, conn=conn)585        if sql and sql.strip('\n') != '':586            sql_data += sql587 588        data_seq = {'objects': data['objects'],589                    'priv': data['priv']['sequence']}590        sql = render_template(591            "/".join([server_prop['template_path'],592                      '/sql/grant_sequence.sql']),593            data=data_seq, conn=conn)594        if sql and sql.strip('\n') != '':595            sql_data += sql596 597        data_table = {'objects': data['objects'],598                      'priv': data['priv']['table']}599        sql = render_template(600            "/".join([server_prop['template_path'], '/sql/grant_table.sql']),601            data=data_table, conn=conn)602        if sql and sql.strip('\n') != '':603            sql_data += sql604 605        data_table = {'objects': data['objects'],606                      'priv': data['priv']['foreign_table']}607        sql = render_template(608            "/".join([server_prop['template_path'],609                      '/sql/grant_foreign_table.sql']),610            data=data_table, conn=conn)611        if sql and sql.strip('\n') != '':612            sql_data += sql613 614        # Logic for generating privileges sql only for ppas615        if server_prop['server_type'] == 'ppas':616            data_package = {'objects': data['objects'],617                            'priv': data['priv']['package']}618            sql = render_template(619                "/".join([server_prop['template_path'],620                          '/sql/grant_package.sql']),621                data=data_package, conn=conn)622            if sql and sql.strip('\n') != '':623                sql_data += sql624 625        status, res = conn.execute_dict(sql_data)626        if not status:627            return internal_server_error(errormsg=res)628 629        return make_json_response(630            success=1,631            info="Privileges applied"632        )633 634    except Exception as e:635        return internal_server_error(errormsg=e.message)636 
codekingpro/portable-devtools · Team Ai