From 844f69c50a12c48533e4459a479c27f67bd10cf7 Mon Sep 17 00:00:00 2001 From: Tigran Saluev Date: Fri, 5 Jan 2024 17:33:05 +0400 Subject: [PATCH] Add usage docs --- docs/features/mongodb_integration.md | 28 ++++++++++++++++++ docs/features/sql_integration.md | 39 ++++++++++++++++++++++++++ docs/usage/all_in_one_cli.md | 8 +++++- mkdocs.yml | 3 ++ suppgram/__main__.py | 7 +++++ suppgram/cli/all_in_one.py | 37 ++++++++++++++++++++++-- suppgram/storages/sqlalchemy/models.py | 2 +- 7 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 docs/features/mongodb_integration.md create mode 100644 docs/features/sql_integration.md create mode 100644 suppgram/__main__.py diff --git a/docs/features/mongodb_integration.md b/docs/features/mongodb_integration.md new file mode 100644 index 0000000..28bca54 --- /dev/null +++ b/docs/features/mongodb_integration.md @@ -0,0 +1,28 @@ +# MongoDB integration + +To run Suppgram with MongoDB, you'll have to install optional dependencies: +```shell +python -m pip install "suppgram[mongodb]" +``` + +Then you can configure the integration by database URI. Examples: + +```shell +# All-in-one CLI + MongoDB (insecure) +python -m suppgram.cli.all_in_one \ + --mongodb-uri mongodb://user:password@host:27017/database \ + ... + +# All-in-one CLI + MongoDB (secret in environment variable) +export MONGODB_URI=mongodb://user:password@host:27017/database +python -m suppgram.cli.all_in_one ... + +# All-in-one CLI + MongoDB (secret in file) +echo "mongodb://user:password@host:27017/database" > /secrets/mongodb_uri +python -m suppgram.cli.all_in_one \ + --mongodb-uri-file /secrets/mongodb_uri \ + ... +``` + +Suppgram will create collections with names starting with `suppgram_`, so you may use +a preexisting database instead of creating a separate one. diff --git a/docs/features/sql_integration.md b/docs/features/sql_integration.md new file mode 100644 index 0000000..3896b0f --- /dev/null +++ b/docs/features/sql_integration.md @@ -0,0 +1,39 @@ +# PostgreSQL/SQLite integration + +Suppgram ships with support for arbitrary persistent storage supported by SQLAlchemy, +including PostgreSQL, SQLite and [numerous other databases](https://docs.sqlalchemy.org/en/20/dialects/). +However, note that unit tests are only run for PostgreSQL (latest) and SQLite. + +To run Suppgram with SQLAlchemy, you'll have to install optional dependencies: +```shell +python -m pip install "suppgram[sqlalchemy]" +``` +This pack of dependencies includes asynchronous drivers for PostgreSQL and SQLite. +For other databases, additional packages may be required. + +Then you can configure the integration the same way SQLAlchemy is normally configured — +by database URI. Examples: +```shell +# All-in-one CLI + SQLite +python -m suppgram.cli.all_in_one \ + --sqlalchemy-uri sqlite+aiosqlite:///path/to/file.db \ + ... + +# All-in-one CLI + PostgreSQL (insecure) +python -m suppgram.cli.all_in_one \ + --sqlalchemy-uri postgresql+asyncpg://user:password@host:5432/database \ + ... + +# All-in-one CLI + PostgreSQL (secret in environment variable) +export SQLALCHEMY_URI=postgresql+asyncpg://user:password@host:5432/database +python -m suppgram.cli.all_in_one ... + +# All-in-one CLI + PostgreSQL (secret in file) +echo "postgresql+asyncpg://user:password@host:5432/database" > /secrets/postgres_uri +python -m suppgram.cli.all_in_one \ + --sqlalchemy-uri-file /secrets/postgres_uri \ + ... +``` + +Suppgram will create tables with names starting with `suppgram_`, so you may use +a preexisting database instead of creating a separate one. diff --git a/docs/usage/all_in_one_cli.md b/docs/usage/all_in_one_cli.md index 2b3e687..fe4b293 100644 --- a/docs/usage/all_in_one_cli.md +++ b/docs/usage/all_in_one_cli.md @@ -17,8 +17,14 @@ Options: --sqlalchemy-uri TEXT SQLAlchemy connection URI. Alternatively, environment variable SQLALCHEMY_URI may be used + --sqlalchemy-uri-file FILE Path to file storing SQLAlchemy connection + URI. Alternatively, environment variable + SQLALCHEMY_URI may be used --mongodb-uri TEXT MongoDB connection URI. Alternatively, environment variable MONGODB_URI may be used + --mongodb-uri-file FILE Path to file storing MongoDB connection URI. + Alternatively, environment variable + MONGODB_URI may be used --mongodb-database TEXT MongoDB database name. If not specified, will connect to the default database specified in the URI @@ -53,7 +59,7 @@ Options: essageConverter] --help Show this message and exit. ``` -It is recommended to prefer environment variables over command line arguments +It is recommended to prefer environment variables or files over command line arguments for sensitive data, e.g. for SQLAlchemy URI if it contains username and/or password. Details on particular integrations (SQLAlchemy, MongoDB, Telegram, PubNub, ...) are diff --git a/mkdocs.yml b/mkdocs.yml index 5a00341..7bb013b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -10,6 +10,9 @@ nav: - 'All-in-one CLI': usage/all_in_one_cli.md - Builder: usage/builder.md - 'Customizing texts': usage/customizing_texts.md + - Features: + - 'PostgreSQL/SQLite integration': features/sql_integration.md + - 'MongoDB integration': features/mongodb_integration.md - Development: - 'Contribution guide': development/contribution_guide.md - 'Architecture overview': development/architecture_overview.md diff --git a/suppgram/__main__.py b/suppgram/__main__.py new file mode 100644 index 0000000..4a3d0b3 --- /dev/null +++ b/suppgram/__main__.py @@ -0,0 +1,7 @@ +import sys + +print( + "Error: 'suppgram' package is not directly runnable. Did you mean 'suppgram.cli.all_in_one'?", + file=sys.stderr, +) +sys.exit(1) diff --git a/suppgram/cli/all_in_one.py b/suppgram/cli/all_in_one.py index f35101b..e6a0f69 100644 --- a/suppgram/cli/all_in_one.py +++ b/suppgram/cli/all_in_one.py @@ -25,12 +25,25 @@ default=None, help="SQLAlchemy connection URI. Alternatively, environment variable SQLALCHEMY_URI may be used", ) +@click.option( + "--sqlalchemy-uri-file", + default=None, + type=click.Path(exists=True, dir_okay=False), + help="Path to file storing SQLAlchemy connection URI. " + "Alternatively, environment variable SQLALCHEMY_URI may be used", +) @click.option( "--mongodb-uri", envvar="MONGODB_URI", default=None, help="MongoDB connection URI. Alternatively, environment variable MONGODB_URI may be used", ) +@click.option( + "--mongodb-uri-file", + default=None, + type=click.Path(exists=True, dir_okay=False), + help="Path to file storing MongoDB connection URI. Alternatively, environment variable MONGODB_URI may be used", +) @click.option( "--mongodb-database", "mongodb_database_name", @@ -99,7 +112,9 @@ def run_all_in_one( loglevel: str, sqlalchemy_uri: Optional[str], + sqlalchemy_uri_file: Optional[str], mongodb_uri: Optional[str], + mongodb_uri_file: Optional[str], mongodb_database_name: Optional[str], texts_class_path: str, telegram_customer_bot_token_file: Optional[str], @@ -140,6 +155,15 @@ def run_all_in_one( builder = Builder() + if sqlalchemy_uri_file: + if sqlalchemy_uri: + raise UsageError( + "both --sqlalchemy-uri (or SQLALCHEMY_URI environment variable) " + "and --sqlalchemy-uri-file are specified; unclear which URI to use." + ) + + sqlalchemy_uri = _read_secret_from_file(sqlalchemy_uri_file) + try: if sqlalchemy_uri: builder = builder.with_sqlalchemy_storage(sqlalchemy_uri) @@ -149,6 +173,15 @@ def run_all_in_one( "Make sure that necessary dependencies are installed:\n\n pip install suppgram[sqlalchemy]\n" ) from exc + if mongodb_uri_file: + if mongodb_uri: + raise UsageError( + "both --mongodb-uri (or MONGODB_URI environment variable) " + "and --mongodb-uri-file are specified; unclear which URI to use." + ) + + mongodb_uri = _read_secret_from_file(mongodb_uri_file) + try: if mongodb_uri is not None: builder = builder.with_mongodb_storage(mongodb_uri, mongodb_database_name) @@ -209,11 +242,11 @@ def run_all_in_one( builder.build() except NoStorageSpecified as exc: raise UsageError( - "No storage specified. Consider specifying --sqlalchemy-uri or --mongodb-uri parameters." + "no storage specified. Consider specifying --sqlalchemy-uri or --mongodb-uri parameters." ) from exc except NoFrontendSpecified as exc: raise UsageError( - "No frontend specified. In this configuration the application is not going to do anything.\n" + "no frontend specified. In this configuration the application is not going to do anything.\n" "Consider specifying --telegram-*, --pubnub-* or --customer-shell parameters." ) from exc diff --git a/suppgram/storages/sqlalchemy/models.py b/suppgram/storages/sqlalchemy/models.py index dbda193..98480b2 100644 --- a/suppgram/storages/sqlalchemy/models.py +++ b/suppgram/storages/sqlalchemy/models.py @@ -356,7 +356,7 @@ def make_workplace_filter(self, identification: WorkplaceIdentification) -> Colu if identification.telegram_user_id is not None: return ( (workplace_model.telegram_bot_id == identification.telegram_bot_id) - & (workplace_model.agent_id == self.agent_model.id) + & (workplace_model.agent_id == agent_model.id) & (agent_model.telegram_user_id == identification.telegram_user_id) ) raise WorkplaceEmptyIdentification(identification)