Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
setup.py641 linesDownload Raw Back to web
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"""Perform the initial setup of the application, by creating the auth11and settings database."""12 13import os14import sys15import typer16from rich.console import Console17from rich.table import Table18from rich import box, print19import json as jsonlib20from functools import wraps21 22console = Console()23app = typer.Typer()24 25# We need to include the root directory in sys.path to ensure that we can26# find everything we need when running in the standalone runtime.27root = os.path.dirname(os.path.realpath(__file__))28if sys.path[0] != root:29    sys.path.insert(0, root)30 31import builtins32import config33 34# Grab the SERVER_MODE if it's been set by the runtime35if 'SERVER_MODE' in globals():36    builtins.SERVER_MODE = globals()['SERVER_MODE']37else:38    builtins.SERVER_MODE = None39 40from pgadmin.model import db, Version, User, \41    SCHEMA_VERSION as CURRENT_SCHEMA_VERSION42from pgadmin import create_app43from pgadmin.utils import clear_database_servers, dump_database_servers, \44    load_database_servers, _handle_error45from pgadmin.setup import db_upgrade, create_app_data_directory46from typing import Optional, List47from typing_extensions import Annotated48from pgadmin.utils.constants import INTERNAL, LDAP, OAUTH2, \49    KERBEROS, WEBSERVER50from pgadmin.tools.user_management import create_user, delete_user, \51    update_user as user_management_update_user52from enum import Enum53from flask_babel import gettext54 55 56app = typer.Typer(pretty_exceptions_show_locals=False)57 58 59def update_sqlite_path(f):60    """61    This function will behave as a decorator which will check if62    sqlite path is provided and will update it in config63    """64 65    @wraps(f)66    def wrap(*args, **kwargs):67        if kwargs and kwargs.get('sqlite_path') is not None:68            # update the sqlite path69            config.SQLITE_PATH = kwargs['sqlite_path']70        return f(*args, **kwargs)71 72    return wrap73 74 75class ManageServers:76 77    @app.command()78    @update_sqlite_path79    def dump_servers(output_file: str, user: Optional[str] = None,80                     auth_source: Optional[str] = INTERNAL,81                     sqlite_path: Optional[str] = None,82                     server: List[int] = None):83        """Dump the server groups and servers. """84 85        # What user?86        dump_user = user if user is not None else config.DESKTOP_USER87 88        print('----------')89        print('Dumping servers with:')90        print('User:', dump_user)91        print('SQLite pgAdmin config:', config.SQLITE_PATH)92        print('----------')93 94        try:95            app = create_app(config.APP_NAME + '-cli')96            with app.test_request_context():97                dump_database_servers(output_file, server, dump_user, True,98                                      auth_source)99        except Exception as e:100            print(str(e))101 102    @app.command()103    @update_sqlite_path104    def load_servers(input_file: str, user: Optional[str] = None,105                     auth_source: Optional[str] = INTERNAL,106                     sqlite_path: Optional[str] = None,107                     replace: Optional[bool] = False108                     ):109 110        """Load server groups and servers."""111 112        # What user?113        load_user = user if user is not None else config.DESKTOP_USER114 115        print('----------')116        print('Loading servers with:')117        print('User:', load_user)118        print('SQLite pgAdmin config:', config.SQLITE_PATH)119        print('----------')120 121        try:122            app = create_app(config.APP_NAME + '-cli')123            with app.test_request_context():124                if replace:125                    clear_database_servers(load_user, True, auth_source)126                load_database_servers(input_file, None, load_user, True,127                                      auth_source)128        except Exception as e:129            print(str(e))130 131 132class AuthExtTypes(str, Enum):133    oauth2 = OAUTH2134    ldap = LDAP135    kerberos = KERBEROS136    webserver = WEBSERVER137 138 139# Enum class can not be extended140class AuthType(str, Enum):141    oauth2 = OAUTH2142    ldap = LDAP143    kerberos = KERBEROS144    webserver = WEBSERVER145    internal = INTERNAL146 147 148class ManageUsers:149 150    @app.command()151    @update_sqlite_path152    def add_user(email: str, password: str,153                 role: Annotated[Optional[bool], typer.Option(154                     "--admin/--nonadmin")] = False,155                 active: Annotated[Optional[bool],156                                   typer.Option("--active/--inactive")] = True,157                 console: Optional[bool] = True,158                 json: Optional[bool] = False,159                 sqlite_path: Optional[str] = None,160                 ):161        """Add Internal user. """162 163        data = {164            'email': email,165            'role': 1 if role else 2,166            'active': active,167            'auth_source': INTERNAL,168            'newPassword': password,169            'confirmPassword': password,170        }171        ManageUsers.create_user(data, console, json)172 173    @app.command()174    @update_sqlite_path175    def add_external_user(username: str,176                          auth_source: AuthExtTypes = AuthExtTypes.oauth2,177                          email: Optional[str] = None,178                          role: Annotated[Optional[bool],179                                          typer.Option(180                                              "--admin/--nonadmin")] = False,181                          active: Annotated[Optional[bool],182                                            typer.Option(183                                                "--active/--inactive")] = True,184                          console: Optional[bool] = True,185                          json: Optional[bool] = False,186                          sqlite_path: Optional[str] = None,187                          ):188        """Add external user, other than Internal like189        Ldap, Ouath2, Kerberos, Webserver. """190 191        data = {192            'username': username,193            'email': email,194            'role': 1 if role else 2,195            'active': active,196            'auth_source': auth_source197        }198        ManageUsers.create_user(data, console, json)199 200    @app.command()201    @update_sqlite_path202    def delete_user(username: str,203                    auth_source: AuthType = AuthType.internal,204                    auto_confirm: Annotated[Optional[bool],205                                            typer.Option(206                                                "--yes")] = False,207                    sqlite_path: Optional[str] = None,208                    ):209        """Delete the user. """210 211        confirm_msg = "Are you sure you want to delete it?"212 213        if auto_confirm or typer.confirm(confirm_msg):214            app = create_app(config.APP_NAME + '-cli')215            with app.test_request_context():216                uid = ManageUsers.get_user(username=username,217                                           auth_source=auth_source)218                if not uid:219                    print("User not found")220                else:221                    status, msg = delete_user(uid)222                    if status:223                        print('User deleted successfully.')224                    else:225                        print('Something went wrong. ' + str(msg))226 227    @app.command()228    @update_sqlite_path229    def update_user(email: str,230                    password: Optional[str] = None,231                    role: Annotated[Optional[bool],232                                    typer.Option("--admin/--nonadmin"233                                                 )] = None,234                    active: Annotated[Optional[bool],235                                      typer.Option("--active/--inactive"236                                                   )] = None,237                    console: Optional[bool] = True,238                    json: Optional[bool] = False,239                    sqlite_path: Optional[str] = None,240                    ):241        """Update internal user."""242 243        data = dict()244        if password:245            if len(password) < 6:246                print("Password must be at least 6 characters long.")247                exit()248            # validate_password relies on the new password being present as249            # `newPassword` and `confirmPassword` in the data250            data['newPassword'] = password251            data['confirmPassword'] = password252 253        if role is not None:254            data['role'] = 1 if role else 2255        if active is not None:256            data['active'] = active257 258        app = create_app(config.APP_NAME + '-cli')259        with app.test_request_context():260            uid = ManageUsers.get_user(username=email,261                                       auth_source=INTERNAL)262            if not uid:263                print("User not found")264            else:265                status, msg = user_management_update_user(uid, data)266                if status:267                    _user = ManageUsers.get_users_from_db(username=email,268                                                          auth_source=INTERNAL,269                                                          console=False)270                    ManageUsers.display_user(_user[0], console, json)271                else:272                    print('Something went wrong. ' + str(msg))273 274    @app.command()275    @update_sqlite_path276    def get_users(username: Optional[str] = None,277                  auth_source: AuthType = None,278                  json: Optional[bool] = False,279                  sqlite_path: Optional[str] = None,280                  ):281 282        ManageUsers.get_users_from_db(username, auth_source, True, json)283 284    def get_users_from_db(username: Optional[str] = None,285                          auth_source: AuthType = None,286                          console: Optional[bool] = True,287                          json: Optional[bool] = False,288                          ):289        """Get user(s) details."""290 291        app = create_app(config.APP_NAME + '-cli')292        with app.test_request_context():293            if username and auth_source:294                users = User.query.filter_by(username=username,295                                             auth_source=auth_source)296            elif not username and auth_source:297                users = User.query.filter_by(auth_source=auth_source)298            elif username and not auth_source:299                users = User.query.filter_by(username=username)300            else:301                users = User.query.all()302            users_data = []303            for u in users:304                _data = {'id': u.id,305                         'username': u.username,306                         'email': u.email,307                         'active': u.active,308                         'role': u.roles[0].id,309                         'auth_source': u.auth_source,310                         'locked': u.locked311                         }312                users_data.append(_data)313            if console:314                ManageUsers.display_user(users_data, console, json)315            else:316                return users_data317 318    @app.command()319    @update_sqlite_path320    def update_external_user(username: str,321                             auth_source: AuthExtTypes = AuthExtTypes.oauth2,322                             email: Optional[str] = None,323                             role: Annotated[Optional[bool],324                                             typer.Option("--admin/--nonadmin"325                                                          )] = None,326                             active: Annotated[327                                 Optional[bool],328                                 typer.Option("--active/--inactive")] = None,329                             console: Optional[bool] = True,330                             json: Optional[bool] = False,331                             sqlite_path: Optional[str] = None,332                             ):333        """Update external users other than Internal like334         Ldap, Ouath2, Kerberos, Webserver."""335 336        data = dict()337        if email:338            data['email'] = email339        if role is not None:340            data['role'] = 1 if role else 2341        if active is not None:342            data['active'] = active343 344        app = create_app(config.APP_NAME + '-cli')345        with app.test_request_context():346            uid = ManageUsers.get_user(username=username,347                                       auth_source=auth_source)348            if not uid:349                print("User not found")350            else:351                status, msg = user_management_update_user(uid, data)352                if status:353                    _user = ManageUsers.get_users_from_db(354                        username=username,355                        auth_source=auth_source,356                        console=False357                    )358                    ManageUsers.display_user(_user[0], console, json)359                else:360                    print('Something went wrong. ' + str(msg))361 362    def create_user(data, console, json):363        app = create_app(config.APP_NAME + '-cli')364        with app.test_request_context():365            username = data['username'] if 'username' in data else \366                data['email']367            uid = ManageUsers.get_user(username=username,368                                       auth_source=data['auth_source'])369            if uid:370                print("User already exists.")371                exit()372 373            if 'newPassword' in data and len(data['newPassword']) < 6:374                print("Password must be at least 6 characters long.")375                exit()376 377            status, msg = create_user(data)378            if status:379                ManageUsers.display_user(data, console, json)380            else:381                print('Something went wrong. ' + str(msg))382 383    def get_user(username=None, auth_source=INTERNAL):384        app = create_app(config.APP_NAME + '-cli')385        usr = None386        with app.test_request_context():387            usr = User.query.filter_by(username=username,388                                       auth_source=auth_source).first()389 390            if not usr:391                return None392            return usr.id393 394    def display_user(data, _console, _json):395        if _console:396            if _json:397                json_formatted_str = jsonlib.dumps(data, indent=0)398                console.print(json_formatted_str)399            else:400                if isinstance(data, dict):401                    data = [data]402                for _data in data:403                    table = Table(title="User Details", box=box.ASCII)404                    table.add_column("Field", style="green")405                    table.add_column("Value", style="green")406 407                    if 'username' in _data:408                        table.add_row("Username", _data['username'])409                    if 'email' in _data:410                        table.add_row("Email", _data['email'])411                    table.add_row("auth_source", _data['auth_source'])412                    table.add_row("role",413                                  "Admin" if _data['role'] and414                                  _data['role'] != 2 else415                                  "Non-admin")416                    table.add_row("active",417                                  'True' if _data['active'] else 'False')418                    console.print(table)419 420 421class ManagePreferences:422 423    def get_user(username=None, auth_source=INTERNAL):424        app = create_app(config.APP_NAME + '-cli')425        usr = None426        with app.test_request_context():427            usr = User.query.filter_by(username=username,428                                       auth_source=auth_source).first()429            if not usr:430                return None431            return usr.id432 433    @app.command()434    @update_sqlite_path435    def get_prefs(json: Optional[bool] = False,436                  sqlite_path: Optional[str] = None,437                  ):438 439        return ManagePreferences.fetch_prefs()440 441    def fetch_prefs(id: Optional[bool] = None, json: Optional[bool] = False):442        """Get Preferences List."""443        app = create_app(config.APP_NAME + '-cli')444        table = Table(title="Pref Details", box=box.ASCII)445        table.add_column("Preference", style="green")446        with app.app_context():447            from pgadmin.model import Preferences as PrefTable, \448                ModulePreference as ModulePrefTable, \449                PreferenceCategory as PrefCategoryTbl450 451            module_prefs = ModulePrefTable.query.all()452            cat_prefs = PrefCategoryTbl.query.all()453            prefs = PrefTable.query.all()454            if id:455                all_preferences = {}456            else:457                all_preferences = []458            for i in module_prefs:459                for j in cat_prefs:460                    if i.id == j.mid:461                        for k in prefs:462                            if k.cid == j.id:463                                if id:464                                    all_preferences["{0}:{1}:{2}".format(465                                        i.name, j.name, k.name)466                                    ] = "{0}:{1}:{2}".format(i.id, j.id, k.id)467                                else:468                                    table.add_row("{0}:{1}:{2}".format(469                                        i.name, j.name, k.name))470                                    all_preferences.append(471                                        "{0}:{1}:{2}".format(472                                            i.name, j.name, k.name)473                                    )474            if id:475                return all_preferences476            else:477                if json:478                    json_formatted_str = jsonlib.dumps(479                        {"Preferences": all_preferences},480                        indent=0)481                    print(json_formatted_str)482                else:483                    print(table)484 485    @app.command()486    @update_sqlite_path487    def set_prefs(username,488                  pref_options: Annotated[Optional[List[str]],489                                          typer.Argument()] = None,490                  auth_source: AuthType = AuthType.internal,491                  console: Optional[bool] = True,492                  json: Optional[bool] = False,493                  input_file: Optional[str] = None,494                  sqlite_path: Optional[str] = None,495                  ):496        """Set User preferences."""497 498        if input_file:499            from urllib.parse import unquote500            # generate full path of file501            try:502                file_path = unquote(input_file)503            except Exception as e:504                print(str(e))505                return _handle_error(str(e), True)506            import json as json_utility507            try:508                with open(file_path) as f:509                    data = json_utility.load(f)510            except json_utility.decoder.JSONDecodeError as e:511                return _handle_error(gettext("Error parsing input file %s: %s"512                                             % (file_path, e)), True)513            except Exception as e:514                return _handle_error(515                    gettext("Error reading input file %s: [%d] %s" %516                            (file_path, e.errno, e.strerror)), True)517 518            pref_data = data['preferences']519 520            for k, v in pref_data.items():521                pref_options.append(k + "=" + str(v))522 523        user_id = ManagePreferences.get_user(username, auth_source)524        table = Table(title="Updated Pref Details", box=box.ASCII)525        table.add_column("Preference", style="green")526        if not user_id:527            print("User not found.")528            return529 530        prefs = ManagePreferences.fetch_prefs(True)531        app = create_app(config.APP_NAME + '-cli')532        invalid_prefs = []533        valid_prefs = []534        with app.app_context():535            from pgadmin.preferences import save_pref536            for opt in pref_options:537                val = opt.split("=")538                if len(val) <= 1:539                    print('Preference key=value is required, example: '540                          '[green]sqleditor:editor:comma_first=true[/green]')541                    return542                final_opt = val[0].split(":")543                val = val[1]544                f = ":".join(final_opt)545                if f in prefs:546                    ids = prefs[f].split(":")547                    _row = {548                        'mid': ids[0],549                        'category_id': ids[1],550                        'id': ids[2],551                        'name': final_opt[2],552                        'user_id': user_id,553                        'value': val}554                    save_pref(_row)555                    valid_prefs.append(_row)556 557                    if not json:558                        table.add_row(jsonlib.dumps(_row))559                else:560                    invalid_prefs.append(f)561 562            if len(invalid_prefs) >= 1:563                print("Preference(s) [red]{0}[/red] not found.".format(564                    (', ').join(565                        invalid_prefs)))566 567            if not json and console:568                print(table)569            elif json and console:570                print(jsonlib.dumps(valid_prefs, indent=2))571 572 573@app.command()574def setup_db(app: Annotated[str, typer.Argument(575        help="This argument doesn't require in CLI mode.")] = None):576    """Setup the configuration database."""577 578    app = app or create_app()579    create_app_data_directory(config)580 581    print("pgAdmin 4 - Application Initialisation")582    print("======================================\n")583 584    def run_migration_for_sqlite():585        with app.app_context():586            # Run migration for the first time i.e. create database587            from config import SQLITE_PATH588            if not os.path.exists(SQLITE_PATH):589                db_upgrade(app)590            else:591                version = Version.query.filter_by(name='ConfigDB').first()592                schema_version = version.value593 594                # Run migration if current schema version is greater than the595                # schema version stored in version table596                if CURRENT_SCHEMA_VERSION >= schema_version:597                    db_upgrade(app)598 599                # Update schema version to the latest600                if CURRENT_SCHEMA_VERSION > schema_version:601                    version = Version.query.filter_by(name='ConfigDB').first()602                    version.value = CURRENT_SCHEMA_VERSION603                    db.session.commit()604 605            if os.name != 'nt':606                os.chmod(config.SQLITE_PATH, 0o600)607 608    def run_migration_for_others():609        with app.app_context():610            version = Version.query.filter_by(name='ConfigDB').first()611            if version == -1:612                db_upgrade(app)613            else:614                schema_version = version.value615 616                # Run migration if current schema version is greater than the617                # schema version stored in version table618                if CURRENT_SCHEMA_VERSION >= schema_version:619                    db_upgrade(app)620 621                # Update schema version to the latest622                if CURRENT_SCHEMA_VERSION > schema_version:623                    version = Version.query.filter_by(name='ConfigDB').first()624                    version.value = CURRENT_SCHEMA_VERSION625                    db.session.commit()626 627    # Run the migration as per specified by the user.628    if config.CONFIG_DATABASE_URI is not None and \629            len(config.CONFIG_DATABASE_URI) > 0:630        run_migration_for_others()631    else:632        run_migration_for_sqlite()633 634 635def main():636    app()637 638 639if __name__ == "__main__":640    main()641 
codekingpro/portable-devtools · Team Ai