import typer import enum import pathlib import getpass import json import os import uvicorn from assets import * default_config = pathlib.Path("config.json") default_users_db = pathlib.Path("users.json") default_db = pathlib.Path("database.db") config_help = "This is configuration file of the app to use." users_db_help = "This is location of the users json database." db_help = "This is location of SQLite3 database file." description = "This is core reservationer package. It could be used to host " description = description + "app, or manage configuration or database." app = typer.Typer(help = description) class user_command(str, enum.Enum): """ That commands could be used in the user subcommand. """ add = "register" delete = "delete" password = "password-change" logout = "full-logout" def password_prompt() -> str: while True: first = getpass.getpass("Password: ") second = getpass.getpass("Repeat password: ") if first == second: return first print("Passwords do not match.") @app.command() def server( port: int = typer.Option(8080, help = "Port to listen on."), address: str = typer.Option("0.0.0.0", help = "Address to listen on."), config: pathlib.Path = typer.Option(default_config, help = config_help) ) -> None: """ Start app on selected port and interfaces. """ os.environ["config_file"] = str(config) server_config = uvicorn.Config( "assets.server:instance", port = port, host = address, log_level = "info", proxy_headers = True, forwarded_allow_ips = "*" ) app = uvicorn.Server(server_config) try: app.run() except json.JSONDecodeError as error: print("Can not parse config and user database.") print(str(error)) @app.command() def user( command: user_command = typer.Argument(help = "Command to run on users."), nick: str = typer.Argument(help = "Nick of the user to work on."), config: pathlib.Path = typer.Option(default_config, help = config_help) ) -> None: """ Modify user database. """ try: loader = config_loader(app_config).load(config) collection = loader.resources.users # User adding if command == user_command.add: # Check that user exists if collection.exists(nick): raise Exception("User with that nick already exists.") # Create new user creator = user_factory() creator.nick = nick creator.password = password_prompt() # Add it collection.add(creator.result) print("Adding \"" + nick + "\" to the database.") # User remove elif command == user_command.delete: # Load from database target = collection.get_by_nick(nick) # Check that user exists if target is None: raise Exception("User with given nick not exists.") # When exists remove it collection.remove(target) # Change user password elif command == user_command.password: # Load user by nick target = collection.get_by_nick(nick) # Check that user exists if target is None: raise Exception("User not exists, can not change password.") # Change password handler = user_factory(target) handler.password = password_prompt() modified = handler.result # Store it in collection collection.remove(target).add(modified) # Logout user from all devices elif command == user_command.logout: # Load user from database target = collection.get_by_nick(nick) # Check that exists if target is None: raise Exception("User not exists, can not logout.") # Refresh apikey modified = user_factory(target) \ .refresh_apikey() \ .result # Store result collection.remove(target).add(modified) # Save collection to file users_saver(collection) \ .drop(loader.result.users_path) \ .save() print("Users database saved success.") except validator_exception as error: print("Password is not correct, too easy to break.") except json.JSONDecodeError as error: print("User JSON has syntax exception.") print(str(error)) except Exception as error: print("Can not done work.") print(str(error)) @app.command() def initialize( config: pathlib.Path = typer.Option(default_config, help = config_help), users: pathlib.Path = typer.Option(default_users_db, help = users_db_help), database: pathlib.Path = typer.Option(default_db, help = db_help) ) -> None: """ Initialize app configuration. """ try: # Generating config file config_generator(app_config) \ .modify("users_file", str(users)) \ .modify("database_uri", "sqlite:///" + str(database)) \ .save(config) # Generating new blank users database users_saver(users_collection()).save(users) print("Config file is being created.") except Exception as error: print("Config initialization failed.") print(str(error)) if __name__ == "__main__": app()