From ffc4ac762b718ca0066dbb7f871b0e815ca4befc Mon Sep 17 00:00:00 2001 From: kurokobo <2920259+kurokobo@users.noreply.github.com> Date: Sun, 25 Aug 2024 05:52:54 +0000 Subject: [PATCH] feat: store created_by and updated_by for apps, modelconfigs, and sites --- api/controllers/console/app/model_config.py | 2 + api/controllers/console/app/site.py | 6 +++ .../create_site_record_when_app_created.py | 2 + api/fields/app_fields.py | 24 +++++++++ api/fields/workflow_fields.py | 8 +++ ...d_add_created_by_and_updated_by_to_app_.py | 52 +++++++++++++++++++ api/models/model.py | 7 ++- api/services/app_dsl_service.py | 4 ++ api/services/app_service.py | 9 ++++ api/services/workflow/workflow_converter.py | 2 + 10 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 api/migrations/versions/2024_08_25_0441-d0187d6a88dd_add_created_by_and_updated_by_to_app_.py diff --git a/api/controllers/console/app/model_config.py b/api/controllers/console/app/model_config.py index 702afe98645e75..f5068a4cd8fcab 100644 --- a/api/controllers/console/app/model_config.py +++ b/api/controllers/console/app/model_config.py @@ -32,6 +32,8 @@ def post(self, app_model): new_app_model_config = AppModelConfig( app_id=app_model.id, + created_by=current_user.id, + updated_by=current_user.id, ) new_app_model_config = new_app_model_config.from_model_config_dict(model_configuration) diff --git a/api/controllers/console/app/site.py b/api/controllers/console/app/site.py index d903a2609f94f6..f936642acd1d4e 100644 --- a/api/controllers/console/app/site.py +++ b/api/controllers/console/app/site.py @@ -1,3 +1,5 @@ +from datetime import datetime, timezone + from flask_login import current_user from flask_restful import Resource, marshal_with, reqparse from werkzeug.exceptions import Forbidden, NotFound @@ -71,6 +73,8 @@ def post(self, app_model): if value is not None: setattr(site, attr_name, value) + site.updated_by = current_user.id + site.updated_at = datetime.now(timezone.utc).replace(tzinfo=None) db.session.commit() return site @@ -93,6 +97,8 @@ def post(self, app_model): raise NotFound site.code = Site.generate_code(16) + site.updated_by = current_user.id + site.updated_at = datetime.now(timezone.utc).replace(tzinfo=None) db.session.commit() return site diff --git a/api/events/event_handlers/create_site_record_when_app_created.py b/api/events/event_handlers/create_site_record_when_app_created.py index ab07c5d366c342..1515661b2d45b8 100644 --- a/api/events/event_handlers/create_site_record_when_app_created.py +++ b/api/events/event_handlers/create_site_record_when_app_created.py @@ -17,6 +17,8 @@ def handle(sender, **kwargs): default_language=account.interface_language, customize_token_strategy="not_allow", code=Site.generate_code(16), + created_by=app.created_by, + updated_by=app.updated_by, ) db.session.add(site) diff --git a/api/fields/app_fields.py b/api/fields/app_fields.py index 26ed686783a0ca..45fcb128ceecb7 100644 --- a/api/fields/app_fields.py +++ b/api/fields/app_fields.py @@ -1,5 +1,6 @@ from flask_restful import fields +from fields.workflow_fields import workflow_partial_fields from libs.helper import AppIconUrlField, TimestampField app_detail_kernel_fields = { @@ -39,7 +40,10 @@ "completion_prompt_config": fields.Raw(attribute="completion_prompt_config_dict"), "dataset_configs": fields.Raw(attribute="dataset_configs_dict"), "file_upload": fields.Raw(attribute="file_upload_dict"), + "created_by": fields.String, "created_at": TimestampField, + "updated_by": fields.String, + "updated_at": TimestampField, } app_detail_fields = { @@ -52,8 +56,12 @@ "enable_site": fields.Boolean, "enable_api": fields.Boolean, "model_config": fields.Nested(model_config_fields, attribute="app_model_config", allow_null=True), + "workflow": fields.Nested(workflow_partial_fields, allow_null=True), "tracing": fields.Raw, + "created_by": fields.String, "created_at": TimestampField, + "updated_by": fields.String, + "updated_at": TimestampField, } prompt_config_fields = { @@ -63,6 +71,10 @@ model_config_partial_fields = { "model": fields.Raw(attribute="model_dict"), "pre_prompt": fields.String, + "created_by": fields.String, + "created_at": TimestampField, + "updated_by": fields.String, + "updated_at": TimestampField, } tag_fields = {"id": fields.String, "name": fields.String, "type": fields.String} @@ -78,7 +90,11 @@ "icon_background": fields.String, "icon_url": AppIconUrlField, "model_config": fields.Nested(model_config_partial_fields, attribute="app_model_config", allow_null=True), + "workflow": fields.Nested(workflow_partial_fields, allow_null=True), + "created_by": fields.String, "created_at": TimestampField, + "updated_by": fields.String, + "updated_at": TimestampField, "tags": fields.List(fields.Nested(tag_fields)), } @@ -124,6 +140,10 @@ "prompt_public": fields.Boolean, "app_base_url": fields.String, "show_workflow_steps": fields.Boolean, + "created_by": fields.String, + "created_at": TimestampField, + "updated_by": fields.String, + "updated_at": TimestampField, } app_detail_fields_with_site = { @@ -138,9 +158,13 @@ "enable_site": fields.Boolean, "enable_api": fields.Boolean, "model_config": fields.Nested(model_config_fields, attribute="app_model_config", allow_null=True), + "workflow": fields.Nested(workflow_partial_fields, allow_null=True), "site": fields.Nested(site_fields), "api_base_url": fields.String, + "created_by": fields.String, "created_at": TimestampField, + "updated_by": fields.String, + "updated_at": TimestampField, "deleted_tools": fields.List(fields.String), } diff --git a/api/fields/workflow_fields.py b/api/fields/workflow_fields.py index 240b8f2eb03e79..2adef63ada6fb9 100644 --- a/api/fields/workflow_fields.py +++ b/api/fields/workflow_fields.py @@ -53,3 +53,11 @@ def format(self, value): "environment_variables": fields.List(EnvironmentVariableField()), "conversation_variables": fields.List(fields.Nested(conversation_variable_fields)), } + +workflow_partial_fields = { + "id": fields.String, + "created_by": fields.String, + "created_at": TimestampField, + "updated_by": fields.String, + "updated_at": TimestampField, +} diff --git a/api/migrations/versions/2024_08_25_0441-d0187d6a88dd_add_created_by_and_updated_by_to_app_.py b/api/migrations/versions/2024_08_25_0441-d0187d6a88dd_add_created_by_and_updated_by_to_app_.py new file mode 100644 index 00000000000000..e0066a302cd5a2 --- /dev/null +++ b/api/migrations/versions/2024_08_25_0441-d0187d6a88dd_add_created_by_and_updated_by_to_app_.py @@ -0,0 +1,52 @@ +"""add created_by and updated_by to app, modelconfig, and site + +Revision ID: d0187d6a88dd +Revises: 2dbe42621d96 +Create Date: 2024-08-25 04:41:18.157397 + +""" + +import sqlalchemy as sa +from alembic import op + +import models as models + +# revision identifiers, used by Alembic. +revision = "d0187d6a88dd" +down_revision = "2dbe42621d96" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("app_model_configs", schema=None) as batch_op: + batch_op.add_column(sa.Column("created_by", models.types.StringUUID(), nullable=True)) + batch_op.add_column(sa.Column("updated_by", models.types.StringUUID(), nullable=True)) + + with op.batch_alter_table("apps", schema=None) as batch_op: + batch_op.add_column(sa.Column("created_by", models.types.StringUUID(), nullable=True)) + batch_op.add_column(sa.Column("updated_by", models.types.StringUUID(), nullable=True)) + + with op.batch_alter_table("sites", schema=None) as batch_op: + batch_op.add_column(sa.Column("created_by", models.types.StringUUID(), nullable=True)) + batch_op.add_column(sa.Column("updated_by", models.types.StringUUID(), nullable=True)) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("sites", schema=None) as batch_op: + batch_op.drop_column("updated_by") + batch_op.drop_column("created_by") + + with op.batch_alter_table("apps", schema=None) as batch_op: + batch_op.drop_column("updated_by") + batch_op.drop_column("created_by") + + with op.batch_alter_table("app_model_configs", schema=None) as batch_op: + batch_op.drop_column("updated_by") + batch_op.drop_column("created_by") + + # ### end Alembic commands ### diff --git a/api/models/model.py b/api/models/model.py index 73016297713caf..cbb220457768c2 100644 --- a/api/models/model.py +++ b/api/models/model.py @@ -82,7 +82,9 @@ class App(db.Model): is_universal = db.Column(db.Boolean, nullable=False, server_default=db.text('false')) tracing = db.Column(db.Text, nullable=True) max_active_requests = db.Column(db.Integer, nullable=True) + created_by = db.Column(StringUUID, nullable=True) created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)')) + updated_by = db.Column(StringUUID, nullable=True) updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)')) @property @@ -221,7 +223,9 @@ class AppModelConfig(db.Model): provider = db.Column(db.String(255), nullable=True) model_id = db.Column(db.String(255), nullable=True) configs = db.Column(db.JSON, nullable=True) + created_by = db.Column(StringUUID, nullable=True) created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)')) + updated_by = db.Column(StringUUID, nullable=True) updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)')) opening_statement = db.Column(db.Text) suggested_questions = db.Column(db.Text) @@ -490,7 +494,6 @@ def tenant(self): return tenant - class Conversation(db.Model): __tablename__ = 'conversations' __table_args__ = ( @@ -1107,7 +1110,9 @@ class Site(db.Model): customize_token_strategy = db.Column(db.String(255), nullable=False) prompt_public = db.Column(db.Boolean, nullable=False, server_default=db.text('false')) status = db.Column(db.String(255), nullable=False, server_default=db.text("'normal'::character varying")) + created_by = db.Column(StringUUID, nullable=True) created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)')) + updated_by = db.Column(StringUUID, nullable=True) updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)')) code = db.Column(db.String(255)) diff --git a/api/services/app_dsl_service.py b/api/services/app_dsl_service.py index a938b4f93bfb30..a2aa15ed4bd8b2 100644 --- a/api/services/app_dsl_service.py +++ b/api/services/app_dsl_service.py @@ -346,6 +346,8 @@ def _import_and_create_new_model_config_based_app( app_model_config = AppModelConfig() app_model_config = app_model_config.from_model_config_dict(model_config_data) app_model_config.app_id = app.id + app_model_config.created_by = account.id + app_model_config.updated_by = account.id db.session.add(app_model_config) db.session.commit() @@ -390,6 +392,8 @@ def _create_app( icon_background=icon_background, enable_site=True, enable_api=True, + created_by=account.id, + updated_by=account.id, ) db.session.add(app) diff --git a/api/services/app_service.py b/api/services/app_service.py index 8a2f8c05355c40..462613fb7d17ba 100644 --- a/api/services/app_service.py +++ b/api/services/app_service.py @@ -127,6 +127,8 @@ def create_app(self, tenant_id: str, args: dict, account: Account) -> App: app.tenant_id = tenant_id app.api_rph = args.get("api_rph", 0) app.api_rpm = args.get("api_rpm", 0) + app.created_by = account.id + app.updated_by = account.id db.session.add(app) db.session.flush() @@ -134,6 +136,8 @@ def create_app(self, tenant_id: str, args: dict, account: Account) -> App: if default_model_config: app_model_config = AppModelConfig(**default_model_config) app_model_config.app_id = app.id + app_model_config.created_by = account.id + app_model_config.updated_by = account.id db.session.add(app_model_config) db.session.flush() @@ -217,6 +221,7 @@ def update_app(self, app: App, args: dict) -> App: app.icon_type = args.get("icon_type", "emoji") app.icon = args.get("icon") app.icon_background = args.get("icon_background") + app.updated_by = current_user.id app.updated_at = datetime.now(timezone.utc).replace(tzinfo=None) db.session.commit() @@ -233,6 +238,7 @@ def update_app_name(self, app: App, name: str) -> App: :return: App instance """ app.name = name + app.updated_by = current_user.id app.updated_at = datetime.now(timezone.utc).replace(tzinfo=None) db.session.commit() @@ -248,6 +254,7 @@ def update_app_icon(self, app: App, icon: str, icon_background: str) -> App: """ app.icon = icon app.icon_background = icon_background + app.updated_by = current_user.id app.updated_at = datetime.now(timezone.utc).replace(tzinfo=None) db.session.commit() @@ -264,6 +271,7 @@ def update_app_site_status(self, app: App, enable_site: bool) -> App: return app app.enable_site = enable_site + app.updated_by = current_user.id app.updated_at = datetime.now(timezone.utc).replace(tzinfo=None) db.session.commit() @@ -280,6 +288,7 @@ def update_app_api_status(self, app: App, enable_api: bool) -> App: return app app.enable_api = enable_api + app.updated_by = current_user.id app.updated_at = datetime.now(timezone.utc).replace(tzinfo=None) db.session.commit() diff --git a/api/services/workflow/workflow_converter.py b/api/services/workflow/workflow_converter.py index c9057bd0e5920a..4b845be2f4d01f 100644 --- a/api/services/workflow/workflow_converter.py +++ b/api/services/workflow/workflow_converter.py @@ -74,6 +74,8 @@ def convert_to_workflow( new_app.api_rph = app_model.api_rph new_app.is_demo = False new_app.is_public = app_model.is_public + new_app.created_by = account.id + new_app.updated_by = account.id db.session.add(new_app) db.session.flush() db.session.commit()