diff --git a/.env-dev.template b/.env-dev.template index 37d355f..f34bb54 100644 --- a/.env-dev.template +++ b/.env-dev.template @@ -1,4 +1,4 @@ -DB_HOST=postgres +DB_HOST=${POSTGRES_DATABASE_HOST} DB_USER=postgres DB_PASSWORD=postgres DB_NAME=postgres diff --git a/alembic.ini b/alembic.ini new file mode 100644 index 0000000..c10d4ca --- /dev/null +++ b/alembic.ini @@ -0,0 +1,116 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +script_location = alembic + +# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s +# Uncomment the line below if you want the files to be prepended with date and time +# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file +# for all available tokens +# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s + +# sys.path path, will be prepended to sys.path if present. +# defaults to the current working directory. +prepend_sys_path = . + +# timezone to use when rendering the date within the migration file +# as well as the filename. +# If specified, requires the python>=3.9 or backports.zoneinfo library. +# Any required deps can installed by adding `alembic[tz]` to the pip requirements +# string value is passed to ZoneInfo() +# leave blank for localtime +# timezone = + +# max length of characters to apply to the +# "slug" field +# truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# version location specification; This defaults +# to alembic/versions. When using multiple version +# directories, initial revisions must be specified with --version-path. +# The path separator used here should be the separator specified by "version_path_separator" below. +# version_locations = %(here)s/bar:%(here)s/bat:alembic/versions + +# version path separator; As mentioned above, this is the character used to split +# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep. +# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas. +# Valid values for version_path_separator are: +# +# version_path_separator = : +# version_path_separator = ; +# version_path_separator = space +version_path_separator = os # Use os.pathsep. Default configuration used for new projects. + +# set to 'true' to search source files recursively +# in each "version_locations" directory +# new in Alembic version 1.10 +# recursive_version_locations = false + +# the output encoding used when revision files +# are written from script.py.mako +# output_encoding = utf-8 + +sqlalchemy.url = driver://user:pass@localhost/dbname + + +[post_write_hooks] +# post_write_hooks defines scripts or Python functions that are run +# on newly generated revision scripts. See the documentation for further +# detail and examples + +# format using "black" - use the console_scripts runner, against the "black" entrypoint +# hooks = black +# black.type = console_scripts +# black.entrypoint = black +# black.options = -l 79 REVISION_SCRIPT_FILENAME + +# lint with attempts to fix using "ruff" - use the exec runner, execute a binary +# hooks = ruff +# ruff.type = exec +# ruff.executable = %(here)s/.venv/bin/ruff +# ruff.options = --fix REVISION_SCRIPT_FILENAME + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/alembic/env.py b/alembic/env.py new file mode 100644 index 0000000..e3f3954 --- /dev/null +++ b/alembic/env.py @@ -0,0 +1,90 @@ +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool + +from alembic import context + +import os +from server.app.models import Base + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +if config.config_file_name is not None: + fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +target_metadata = Base.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + +db_name = os.getenv("DB_NAME") +db_user = os.getenv("DB_USER") +db_password = os.getenv("DB_PASSWORD") +db_host = os.getenv("DB_HOST") +db_port = os.getenv("DB_PORT") + +# Construct the SQLAlchemy connection URL using URL class +db_url = f"postgresql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}" +config.set_main_option('sqlalchemy.url', db_url) + +def run_migrations_offline() -> None: + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online() -> None: + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + connectable = engine_from_config( + config.get_section(config.config_ini_section, {}), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, target_metadata=target_metadata + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/alembic/script.py.mako b/alembic/script.py.mako new file mode 100644 index 0000000..fbc4b07 --- /dev/null +++ b/alembic/script.py.mako @@ -0,0 +1,26 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision: str = ${repr(up_revision)} +down_revision: Union[str, None] = ${repr(down_revision)} +branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)} +depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)} + + +def upgrade() -> None: + ${upgrades if upgrades else "pass"} + + +def downgrade() -> None: + ${downgrades if downgrades else "pass"} diff --git a/alembic/versions/3e403863733c_initial_revision.py b/alembic/versions/3e403863733c_initial_revision.py new file mode 100644 index 0000000..f25da7f --- /dev/null +++ b/alembic/versions/3e403863733c_initial_revision.py @@ -0,0 +1,276 @@ +"""Initial Revision + +Revision ID: 3e403863733c +Revises: +Create Date: 2024-06-13 17:52:24.176257 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '3e403863733c' +down_revision: Union[str, None] = None +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('plugins', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('pypi_url', sa.String(), nullable=True), + sa.Column('dsl', sa.String(), nullable=True), + sa.Column('doc', sa.String(), nullable=True), + sa.Column('icon', sa.String(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_plugins_id'), 'plugins', ['id'], unique=False) + op.create_index(op.f('ix_plugins_name'), 'plugins', ['name'], unique=False) + op.create_table('projects', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('project_class', sa.String(), nullable=True), + sa.Column('parent_id', sa.Integer(), nullable=True), + sa.Column('output_url', sa.String(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('is_template', sa.Boolean(), nullable=True), + sa.Column('is_deleted', sa.Boolean(), nullable=True), + sa.Column('engine_url', sa.Boolean(), nullable=True), + sa.Column('file_upload', sa.Boolean(), nullable=True), + sa.Column('audio_upload', sa.Boolean(), nullable=True), + sa.Column('has_credentials', sa.Boolean(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_projects_id'), 'projects', ['id'], unique=False) + op.create_index(op.f('ix_projects_name'), 'projects', ['name'], unique=False) + op.create_table('tags', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_tags_id'), 'tags', ['id'], unique=False) + op.create_index(op.f('ix_tags_name'), 'tags', ['name'], unique=False) + op.create_table('templates', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('project_class', sa.String(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('engine_url', sa.Boolean(), nullable=True), + sa.Column('file_upload', sa.Boolean(), nullable=True), + sa.Column('audio_upload', sa.Boolean(), nullable=True), + sa.Column('has_credentials', sa.Boolean(), nullable=True), + sa.Column('verified', sa.Boolean(), nullable=True), + sa.Column('sort', sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_templates_id'), 'templates', ['id'], unique=False) + op.create_index(op.f('ix_templates_name'), 'templates', ['name'], unique=False) + op.create_table('users', + sa.Column('oid', sa.String(), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('email', sa.String(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('oid') + ) + op.create_index(op.f('ix_users_oid'), 'users', ['oid'], unique=False) + op.create_table('analytics_logs', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('project_id', sa.Integer(), nullable=True), + sa.Column('user_id', sa.String(), nullable=True), + sa.Column('representation_name', sa.String(), nullable=True), + sa.Column('data', sa.JSON(), nullable=True), + sa.Column('timestamp', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['users.oid'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_analytics_logs_id'), 'analytics_logs', ['id'], unique=False) + op.create_index(op.f('ix_analytics_logs_name'), 'analytics_logs', ['name'], unique=False) + op.create_index(op.f('ix_analytics_logs_project_id'), 'analytics_logs', ['project_id'], unique=False) + op.create_index(op.f('ix_analytics_logs_user_id'), 'analytics_logs', ['user_id'], unique=False) + op.create_table('dev_chat_messages', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('session_id', sa.String(), nullable=True), + sa.Column('project_id', sa.Integer(), nullable=True), + sa.Column('sender_id', sa.String(), nullable=True), + sa.Column('sender', sa.Enum('user', 'bot', name='chat_user_type'), nullable=True), + sa.Column('type', sa.Enum('instruction', 'feedback', 'thought', 'output', 'start', 'dsl_state', 'end', 'error', 'representation_edit', 'files', name='chat_message_type'), nullable=True), + sa.Column('message', sa.String(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('special_link', sa.String(), nullable=True), + sa.Column('pbyc_comments', sa.String(), nullable=True), + sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_dev_chat_messages_id'), 'dev_chat_messages', ['id'], unique=False) + op.create_index(op.f('ix_dev_chat_messages_project_id'), 'dev_chat_messages', ['project_id'], unique=False) + op.create_table('exports', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('project_id', sa.Integer(), nullable=True), + sa.Column('sandbox_responsecode', sa.Integer(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_exports_id'), 'exports', ['id'], unique=False) + op.create_index(op.f('ix_exports_project_id'), 'exports', ['project_id'], unique=False) + op.create_table('output_chat_messages', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('session_id', sa.String(), nullable=True), + sa.Column('sender_id', sa.String(), nullable=True), + sa.Column('project_id', sa.Integer(), nullable=True), + sa.Column('sender', sa.Enum('user', 'bot', name='output_user_type'), nullable=True), + sa.Column('type', sa.Enum('instruction', 'feedback', 'thought', 'output', 'callback', 'debug', 'start', 'end', 'error', name='output_message_type'), nullable=True), + sa.Column('message', sa.String(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('special_link', sa.String(), nullable=True), + sa.Column('pbyc_comments', sa.String(), nullable=True), + sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_output_chat_messages_id'), 'output_chat_messages', ['id'], unique=False) + op.create_index(op.f('ix_output_chat_messages_project_id'), 'output_chat_messages', ['project_id'], unique=False) + op.create_table('project_has_credentials', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('project_id', sa.Integer(), nullable=True), + sa.Column('name', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('mandatory', sa.Boolean(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_project_has_credentials_id'), 'project_has_credentials', ['id'], unique=False) + op.create_index(op.f('ix_project_has_credentials_project_id'), 'project_has_credentials', ['project_id'], unique=False) + op.create_table('representation', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('type', sa.String(), nullable=True), + sa.Column('text', sa.String(), nullable=True), + sa.Column('project_id', sa.Integer(), nullable=True), + sa.Column('is_editable', sa.Boolean(), nullable=True), + sa.Column('sort_order', sa.Integer(), nullable=True), + sa.Column('is_pbyc_viewable', sa.Boolean(), nullable=True), + sa.Column('is_user_viewable', sa.Boolean(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_representation_id'), 'representation', ['id'], unique=False) + op.create_index(op.f('ix_representation_name'), 'representation', ['name'], unique=False) + op.create_index(op.f('ix_representation_project_id'), 'representation', ['project_id'], unique=False) + op.create_table('template_has_credentials', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('template_id', sa.Integer(), nullable=True), + sa.Column('name', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('mandatory', sa.Boolean(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['template_id'], ['templates.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_template_has_credentials_id'), 'template_has_credentials', ['id'], unique=False) + op.create_index(op.f('ix_template_has_credentials_template_id'), 'template_has_credentials', ['template_id'], unique=False) + op.create_table('template_has_plugins', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('template_id', sa.Integer(), nullable=True), + sa.Column('plugin_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['plugin_id'], ['plugins.id'], ), + sa.ForeignKeyConstraint(['template_id'], ['templates.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_template_has_plugins_id'), 'template_has_plugins', ['id'], unique=False) + op.create_index(op.f('ix_template_has_plugins_plugin_id'), 'template_has_plugins', ['plugin_id'], unique=False) + op.create_index(op.f('ix_template_has_plugins_template_id'), 'template_has_plugins', ['template_id'], unique=False) + op.create_table('template_has_tags', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('template_id', sa.Integer(), nullable=True), + sa.Column('tag_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['tag_id'], ['tags.id'], ), + sa.ForeignKeyConstraint(['template_id'], ['templates.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_template_has_tags_id'), 'template_has_tags', ['id'], unique=False) + op.create_index(op.f('ix_template_has_tags_tag_id'), 'template_has_tags', ['tag_id'], unique=False) + op.create_index(op.f('ix_template_has_tags_template_id'), 'template_has_tags', ['template_id'], unique=False) + op.create_table('users_has_projects', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('oid', sa.String(), nullable=True), + sa.Column('project_id', sa.Integer(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['oid'], ['users.oid'], ), + sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_users_has_projects_id'), 'users_has_projects', ['id'], unique=False) + op.create_index(op.f('ix_users_has_projects_oid'), 'users_has_projects', ['oid'], unique=False) + op.create_index(op.f('ix_users_has_projects_project_id'), 'users_has_projects', ['project_id'], unique=False) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('ix_users_has_projects_project_id'), table_name='users_has_projects') + op.drop_index(op.f('ix_users_has_projects_oid'), table_name='users_has_projects') + op.drop_index(op.f('ix_users_has_projects_id'), table_name='users_has_projects') + op.drop_table('users_has_projects') + op.drop_index(op.f('ix_template_has_tags_template_id'), table_name='template_has_tags') + op.drop_index(op.f('ix_template_has_tags_tag_id'), table_name='template_has_tags') + op.drop_index(op.f('ix_template_has_tags_id'), table_name='template_has_tags') + op.drop_table('template_has_tags') + op.drop_index(op.f('ix_template_has_plugins_template_id'), table_name='template_has_plugins') + op.drop_index(op.f('ix_template_has_plugins_plugin_id'), table_name='template_has_plugins') + op.drop_index(op.f('ix_template_has_plugins_id'), table_name='template_has_plugins') + op.drop_table('template_has_plugins') + op.drop_index(op.f('ix_template_has_credentials_template_id'), table_name='template_has_credentials') + op.drop_index(op.f('ix_template_has_credentials_id'), table_name='template_has_credentials') + op.drop_table('template_has_credentials') + op.drop_index(op.f('ix_representation_project_id'), table_name='representation') + op.drop_index(op.f('ix_representation_name'), table_name='representation') + op.drop_index(op.f('ix_representation_id'), table_name='representation') + op.drop_table('representation') + op.drop_index(op.f('ix_project_has_credentials_project_id'), table_name='project_has_credentials') + op.drop_index(op.f('ix_project_has_credentials_id'), table_name='project_has_credentials') + op.drop_table('project_has_credentials') + op.drop_index(op.f('ix_output_chat_messages_project_id'), table_name='output_chat_messages') + op.drop_index(op.f('ix_output_chat_messages_id'), table_name='output_chat_messages') + op.drop_table('output_chat_messages') + op.drop_index(op.f('ix_exports_project_id'), table_name='exports') + op.drop_index(op.f('ix_exports_id'), table_name='exports') + op.drop_table('exports') + op.drop_index(op.f('ix_dev_chat_messages_project_id'), table_name='dev_chat_messages') + op.drop_index(op.f('ix_dev_chat_messages_id'), table_name='dev_chat_messages') + op.drop_table('dev_chat_messages') + op.drop_index(op.f('ix_analytics_logs_user_id'), table_name='analytics_logs') + op.drop_index(op.f('ix_analytics_logs_project_id'), table_name='analytics_logs') + op.drop_index(op.f('ix_analytics_logs_name'), table_name='analytics_logs') + op.drop_index(op.f('ix_analytics_logs_id'), table_name='analytics_logs') + op.drop_table('analytics_logs') + op.drop_index(op.f('ix_users_oid'), table_name='users') + op.drop_table('users') + op.drop_index(op.f('ix_templates_name'), table_name='templates') + op.drop_index(op.f('ix_templates_id'), table_name='templates') + op.drop_table('templates') + op.drop_index(op.f('ix_tags_name'), table_name='tags') + op.drop_index(op.f('ix_tags_id'), table_name='tags') + op.drop_table('tags') + op.drop_index(op.f('ix_projects_name'), table_name='projects') + op.drop_index(op.f('ix_projects_id'), table_name='projects') + op.drop_table('projects') + op.drop_index(op.f('ix_plugins_name'), table_name='plugins') + op.drop_index(op.f('ix_plugins_id'), table_name='plugins') + op.drop_table('plugins') + # ### end Alembic commands ### diff --git a/docker-compose.yml b/docker-compose.yml index b99f652..ac4cfb6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,10 @@ services: - ./server/app:/code/server/app environment: - DB_CONNECTION_STRING=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME} + - DB_USER=${DB_USER} + - DB_PASSWORD=${DB_PASSWORD} + - DB_HOST=${DB_HOST} + - DB_PORT=${DB_PORT} - KAFKA_BROKER=${KAFKA_BROKER} - KAFKA_USE_SASL=${KAFKA_USE_SASL} - KAFKA_PRODUCER_USERNAME=${KAFKA_PRODUCER_USERNAME} diff --git a/scripts/backup.sql b/scripts/backup.sql index 361f7fe..0d8f0a2 100644 --- a/scripts/backup.sql +++ b/scripts/backup.sql @@ -1327,4 +1327,3 @@ ALTER TABLE ONLY public.users_has_projects -- -- PostgreSQL database dump complete -- - diff --git a/scripts/base_queries.sql b/scripts/base_queries.sql deleted file mode 100644 index bf170aa..0000000 --- a/scripts/base_queries.sql +++ /dev/null @@ -1,14 +0,0 @@ -INSERT INTO public.templates(id, name, description, project_class, created_at, updated_at, engine_url, file_upload, audio_upload, has_credentials, verified, sort) VALUES (1, 'Custom Template', 'Use this to create your own template. You can see an example here: https://dev.azure.com/pbyc/PbyC/_git/Examples','custom', '2023-05-10 07:32:03.987439', '2023-05-04 13:47:56.492011', true, true, true, false, false, -1); - -INSERT INTO public.templates(id, name, description, project_class, created_at, updated_at, engine_url, file_upload, audio_upload, has_credentials, verified, sort) VALUES (2, 'JB App','Use this to create apps using JugalBandi','jb_app', '2023-05-10 07:32:03.987439', '2023-05-04 13:47:56.492011', false, false, false, false, true, 0); - -INSERT INTO public.plugins(id, name, description, pypi_url, dsl, doc, icon, created_at, updated_at) VALUES (1, 'Knowledge Base', 'Fetch data from a trusted or validated knowledgebase', 'https://pwrplugins.z29.web.core.windows.net/plugins/knowledgebase/rag.dsl', '', '', 'data:image/png;base64,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', '2023-11-24 09:05:53.86371', '2023-11-24 09:05:53.86371'); - -INSERT INTO public.plugins(id, name, description, pypi_url, dsl, doc, icon, created_at, updated_at) VALUES (2, 'Reasoning Engine', 'Using advanced capabilities of AI models (LLMs) to reason over knowledge based on a task', 'https://pwrplugins.z29.web.core.windows.net/plugins/reason_engine/llm.dsl' , '', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAAAXNSR0IArs4c6QAAIABJREFUeF7t3QmYJVV5//H3rdvTzAz8ZVNHoZlbVd2KGY0b/yguRCSuQcCVqIlGTVQif+OumGAWzYZGY9zilkhEg0LEBdS4ggsKKlGJ6WSgu6ruMIygDELEGabpW+dP6RCGEWZO9T33Vp06334en+R55tR7zvm8h57fdNetUuELAQQQQAABBIIT0OB2zIYRQAABBBBAQAgAHAIEEEAAAQQCFCAABNh0towAAggggAABgDOAAAIIIIBAgAIEgACbzpYRQAABBBAgAHAGEEAAAQQQCFCAABBg09kyAggggAACBADOAAIIIIAAAgEKEAACbDpbRgABBBBAgADAGUAAAQQQQCBAAQJAgE1nywgggAACCBAAOAMIIIAAAggEKEAACLDpbBkBBBBAAAECAGcAAQQQQACBAAUIAAE2nS0jgAACCCBAAOAMIIAAAgggEKAAASDAprNlBBBAAAEECACcAQQQQAABBAIUIAAE2HS2jAACCCCAAAGAM4AAAggggECAAgSAAJvOlhFAAAEEECAAcAYQQAABBBAIUIAAEGDT2TICCCCAAAIEAM4AAggggAACAQoQAAJsOltGAAEEEECAAMAZQAABBBBAIEABAkCATWfLCCCAAAIIEAA4AwgggAACCAQoQAAIsOlsGQEEEEAAAQIAZwABBBBAAIEABQgAATadLSOAAAIIIEAA4AwggAACCCAQoAABIMCms2UEEEAAAQQIAJwBBBBAAAEEAhQgAATYdLaMAAIIIIAAAYAzgAACCCCAQIACBIAAm86WEUAAAQQQIABwBhBAAAEEEAhQgAAQYNPZMgIIIIAAAgQAzgACCCCAAAIBChAAAmw6W0YAAQQQQIAAwBlAAAEEEEAgQAECQIBNZ8sIIIAAAggQADgDCCCAAAIIBChAAAiw6WwZAQQQQAABAgBnAAEEEEAAgQAFCAABNp0tI4AAAgggQADgDCCAAAIIIBCgAAEgwKazZQQQQAABBAgAnAEEEEAAAQQCFCAABNh0towAAggggAABgDOAAAIIIIBAgAIEgACbzpYRQAABBBAgAHAGEEAAAQQQCFCAABBg09kyAggggAACBADOAAIIIIAAAgEKEAACbDpbRgABBBBAgADAGUAAAQQQQCBA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','2023-11-24 09:05:53.86371' , '2023-11-24 09:05:53.86371'); - - -INSERT INTO public.template_has_plugins( - id, template_id, plugin_id) - VALUES (1, 2, 1); - -INSERT INTO public.template_has_plugins(id, template_id, plugin_id) VALUES (1, 2, 2); \ No newline at end of file diff --git a/scripts/create-migration.sh b/scripts/create-migration.sh new file mode 100644 index 0000000..25886db --- /dev/null +++ b/scripts/create-migration.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +msg=$1 + +python3 -m venv .venv +source .venv/bin/activate +pip3 install alembic psycopg2-binary + + +if grep -qi microsoft /proc/version && grep -q WSL2 /proc/version; then + PWRHOST=$(hostname -I | awk '{print $1}') + export PWR_KAFKA_BROKER=${PWRHOST}:9092 + export POSTGRES_DATABASE_HOST=${PWRHOST} + echo "Setting Kakfa & Postgres host by WSL2 IP: ${PWRHOST}" +else + export PWR_KAFKA_BROKER=kafka:9092 + export POSTGRES_DATABASE_HOST=postgres + echo "Setting Kakfa & Postgres host by docker-compose service name: kafka, postgres" +fi + + +set -a +source .env-dev +set +a + +alembic revision --autogenerate -m "$msg" \ No newline at end of file diff --git a/scripts/upgrade-db.sh b/scripts/upgrade-db.sh index d78343b..3d61df0 100644 --- a/scripts/upgrade-db.sh +++ b/scripts/upgrade-db.sh @@ -4,16 +4,15 @@ python3 -m venv .venv source .venv/bin/activate pip3 install alembic psycopg2-binary -# source ./set_jbhost.sh if grep -qi microsoft /proc/version && grep -q WSL2 /proc/version; then - JBHOST=$(hostname -I | awk '{print $1}') - export JB_KAFKA_BROKER=${JBHOST}:9092 - export JB_POSTGRES_DATABASE_HOST=${JBHOST} - echo "Setting Kakfa & Postgres host by WSL2 IP: ${JBHOST}" + PWRHOST=$(hostname -I | awk '{print $1}') + export PWR_KAFKA_BROKER=${PWRHOST}:9092 + export POSTGRES_DATABASE_HOST=${PWRHOST} + echo "Setting Kakfa & Postgres host by WSL2 IP: ${PWRHOST}" else - export JB_KAFKA_BROKER=kafka:9092 - export JB_POSTGRES_DATABASE_HOST=localhost + export PWR_KAFKA_BROKER=kafka:9092 + export POSTGRES_DATABASE_HOST=localhost echo "Setting Kakfa & Postgres host by docker-compose service name: kafka, postgres" fi diff --git a/server/app/alembic/env.py b/server/app/alembic/env.py index 180c60b..740fed2 100644 --- a/server/app/alembic/env.py +++ b/server/app/alembic/env.py @@ -18,7 +18,16 @@ # this is the Alembic Config object, which provides # access to the values within the .ini file in use. config = context.config -connection_string=os.environ['DB_CONNECTION_STRING'] +if os.environ.get("DB_CONNECTION_STRING"): + connection_string=os.environ['DB_CONNECTION_STRING'] +else: + # construct the postgres connection string from environment variables + db_user = os.getenv("DB_USER") + db_password = os.getenv("DB_PASSWORD") + db_host = os.getenv("DB_HOST") + db_port = os.getenv("DB_PORT") + db_name = os.getenv("DB_NAME") + connection_string = f"postgresql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}" config.set_main_option('sqlalchemy.url', connection_string) # Interpret the config file for Python logging. diff --git a/server/app/database.py b/server/app/database.py index 1d04a6c..6286002 100644 --- a/server/app/database.py +++ b/server/app/database.py @@ -6,11 +6,17 @@ load_dotenv() -SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db" +SQLALCHEMY_DATABASE_URL = "" if os.environ.get("DB_CONNECTION_STRING"): SQLALCHEMY_DATABASE_URL = os.environ["DB_CONNECTION_STRING"] else: - print("DB_CONNECTION_STRING not set. Using default sqlite database.") + # construct the postgres connection string from environment variables + db_user = os.getenv("DB_USER") + db_password = os.getenv("DB_PASSWORD") + db_host = os.getenv("DB_HOST") + db_port = os.getenv("DB_PORT") + db_name = os.getenv("DB_NAME") + SQLALCHEMY_DATABASE_URL = f"postgresql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}" connect_args = {} if SQLALCHEMY_DATABASE_URL.startswith("sqlite"): diff --git a/server/app/main.py b/server/app/main.py index 7fcb80b..d5ebc2e 100644 --- a/server/app/main.py +++ b/server/app/main.py @@ -42,7 +42,7 @@ # import sys # print(os.environ.get('DB_CONNECTION_STRING'), file=sys.stderr) -models.Base.metadata.create_all(bind=engine) +# models.Base.metadata.create_all(bind=engine) logger = logging.getLogger(__name__) logger.setLevel(level=logging.INFO)