From 52ba4076f5ad55fdf3239a33a2a376eaa0e0dea5 Mon Sep 17 00:00:00 2001
From: zhaoqingang <zhaoqg0118@163.com>
Date: 星期一, 09 十二月 2024 17:53:01 +0800
Subject: [PATCH] m

---
 app/service/bisheng.py                           |    5 
 app/models/session_model.py                      |    8 
 alembic/versions/d4c8f204280f_user_app_add.py    |   67 ++++
 alembic/versions/abc6bb9129ed_user_app_update.py |   44 +++
 app/service/difyService.py                       |  116 +++++++-
 app/api/auth.py                                  |   47 ++-
 app/service/auth.py                              |  102 +++++++
 app/models/__init__.py                           |    3 
 /dev/null                                        |  223 ---------------
 app/models/user_model.py                         |   53 ++-
 app/config/const.py                              |    8 
 app/task/fetch_agent.py                          |    3 
 alembic/versions/4b3a7c69ceac_init_table.py      |   79 +++++
 main.py                                          |    2 
 alembic/versions/07b5185945e0_token_table.py     |   30 ++
 15 files changed, 509 insertions(+), 281 deletions(-)

diff --git a/alembic/versions/07b5185945e0_token_table.py b/alembic/versions/07b5185945e0_token_table.py
new file mode 100644
index 0000000..06fbf7e
--- /dev/null
+++ b/alembic/versions/07b5185945e0_token_table.py
@@ -0,0 +1,30 @@
+"""token table
+
+Revision ID: 07b5185945e0
+Revises: 4b3a7c69ceac
+Create Date: 2024-12-06 16:27:30.329519
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision: str = '07b5185945e0'
+down_revision: Union[str, None] = '4b3a7c69ceac'
+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! ###
+    pass
+    # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+    # ### commands auto generated by Alembic - please adjust! ###
+    pass
+    # ### end Alembic commands ###
diff --git a/alembic/versions/4b3a7c69ceac_init_table.py b/alembic/versions/4b3a7c69ceac_init_table.py
new file mode 100644
index 0000000..9deba7e
--- /dev/null
+++ b/alembic/versions/4b3a7c69ceac_init_table.py
@@ -0,0 +1,79 @@
+"""init table
+
+Revision ID: 4b3a7c69ceac
+Revises: 
+Create Date: 2024-12-06 16:12:04.760402
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects import mysql
+
+# revision identifiers, used by Alembic.
+revision: str = '4b3a7c69ceac'
+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.drop_index('ix_user_test_id', table_name='user_test')
+    op.drop_index('ix_user_test_username', table_name='user_test')
+    op.drop_table('user_test')
+    op.alter_column('user', 'ragflow_id',
+               existing_type=mysql.VARCHAR(length=32),
+               nullable=True)
+    op.alter_column('user', 'bisheng_id',
+               existing_type=mysql.INTEGER(),
+               nullable=True)
+    op.alter_column('user', 'status',
+               existing_type=mysql.VARCHAR(length=10),
+               nullable=True,
+               existing_server_default=sa.text("'1'"))
+    op.alter_column('user', 'permission',
+               existing_type=mysql.VARCHAR(length=16),
+               nullable=True,
+               existing_server_default=sa.text("'general'"))
+    op.drop_column('user', 'updated_at11')
+    # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.add_column('user', sa.Column('updated_at11', mysql.INTEGER(), autoincrement=False, nullable=True))
+    op.alter_column('user', 'permission',
+               existing_type=mysql.VARCHAR(length=16),
+               nullable=False,
+               existing_server_default=sa.text("'general'"))
+    op.alter_column('user', 'status',
+               existing_type=mysql.VARCHAR(length=10),
+               nullable=False,
+               existing_server_default=sa.text("'1'"))
+    op.alter_column('user', 'bisheng_id',
+               existing_type=mysql.INTEGER(),
+               nullable=False)
+    op.alter_column('user', 'ragflow_id',
+               existing_type=mysql.VARCHAR(length=32),
+               nullable=False)
+    op.create_table('user_test',
+    sa.Column('id', mysql.INTEGER(), autoincrement=True, nullable=False),
+    sa.Column('username', mysql.VARCHAR(length=255), nullable=True),
+    sa.Column('hashed_password', mysql.VARCHAR(length=255), nullable=True),
+    sa.Column('password', mysql.VARCHAR(length=255), nullable=True),
+    sa.Column('compellation', mysql.VARCHAR(length=255), nullable=False),
+    sa.Column('phone', mysql.VARCHAR(length=255), nullable=False),
+    sa.Column('email', mysql.VARCHAR(length=255), nullable=False),
+    sa.Column('description', mysql.VARCHAR(length=255), nullable=False),
+    sa.Column('ragflow_id', mysql.VARCHAR(length=32), nullable=True),
+    sa.Column('bisheng_id', mysql.INTEGER(), autoincrement=False, nullable=True),
+    sa.PrimaryKeyConstraint('id'),
+    mysql_collate='utf8mb4_0900_ai_ci',
+    mysql_default_charset='utf8mb4',
+    mysql_engine='InnoDB'
+    )
+    op.create_index('ix_user_test_username', 'user_test', ['username'], unique=True)
+    op.create_index('ix_user_test_id', 'user_test', ['id'], unique=False)
+    # ### end Alembic commands ###
diff --git a/alembic/versions/580e984b9882_initial_migration.py b/alembic/versions/580e984b9882_initial_migration.py
deleted file mode 100644
index 0cc6eff..0000000
--- a/alembic/versions/580e984b9882_initial_migration.py
+++ /dev/null
@@ -1,223 +0,0 @@
-"""Initial migration
-
-Revision ID: 580e984b9882
-Revises: 
-Create Date: 2024-12-06 10:54:42.146182
-
-"""
-from typing import Sequence, Union
-
-from alembic import op
-import sqlalchemy as sa
-from sqlalchemy.dialects import mysql
-
-# revision identifiers, used by Alembic.
-revision: str = '580e984b9882'
-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('user_test',
-    sa.Column('id', sa.Integer(), nullable=False),
-    sa.Column('username', sa.String(length=255), nullable=True),
-    sa.Column('hashed_password', sa.String(length=255), nullable=True),
-    sa.Column('password', sa.String(length=255), nullable=True),
-    sa.Column('compellation', sa.String(length=255), nullable=False),
-    sa.Column('phone', sa.String(length=255), nullable=False),
-    sa.Column('email', sa.String(length=255), nullable=False),
-    sa.Column('description', sa.String(length=255), nullable=False),
-    sa.Column('ragflow_id', sa.String(length=32), nullable=True),
-    sa.Column('bisheng_id', sa.Integer(), nullable=True),
-    sa.PrimaryKeyConstraint('id')
-    )
-    op.create_index(op.f('ix_user_test_id'), 'user_test', ['id'], unique=False)
-    op.create_index(op.f('ix_user_test_username'), 'user_test', ['username'], unique=True)
-    op.drop_table('df_api_token')
-    op.drop_table('sessions')
-    op.drop_table('flow_test')
-    op.drop_table('app_register')
-    op.drop_table('user_canvas')
-    op.drop_table('flow')
-    op.drop_index('ix_group_info_group_id', table_name='group_info')
-    op.drop_index('ix_group_info_group_name', table_name='group_info')
-    op.drop_table('group_info')
-    op.drop_table('group_agent')
-    op.drop_table('organization_group')
-    op.drop_table('token')
-    op.drop_table('dialog')
-    op.drop_index('ix_agent_id', table_name='agent')
-    op.add_column('user', sa.Column('updated_at11', sa.Integer(), nullable=True))
-    op.alter_column('user', 'compellation',
-               existing_type=mysql.VARCHAR(length=255),
-               nullable=False)
-    op.alter_column('user', 'phone',
-               existing_type=mysql.VARCHAR(length=255),
-               nullable=False)
-    op.alter_column('user', 'email',
-               existing_type=mysql.VARCHAR(length=255),
-               nullable=False)
-    op.alter_column('user', 'description',
-               existing_type=mysql.VARCHAR(length=255),
-               nullable=False)
-    op.alter_column('user', 'ragflow_id',
-               existing_type=mysql.VARCHAR(length=32),
-               nullable=True)
-    op.alter_column('user', 'bisheng_id',
-               existing_type=mysql.INTEGER(),
-               nullable=True)
-    # ### end Alembic commands ###
-
-
-def downgrade() -> None:
-    # ### commands auto generated by Alembic - please adjust! ###
-    op.alter_column('user', 'bisheng_id',
-               existing_type=mysql.INTEGER(),
-               nullable=False)
-    op.alter_column('user', 'ragflow_id',
-               existing_type=mysql.VARCHAR(length=32),
-               nullable=False)
-    op.alter_column('user', 'description',
-               existing_type=mysql.VARCHAR(length=255),
-               nullable=True)
-    op.alter_column('user', 'email',
-               existing_type=mysql.VARCHAR(length=255),
-               nullable=True)
-    op.alter_column('user', 'phone',
-               existing_type=mysql.VARCHAR(length=255),
-               nullable=True)
-    op.alter_column('user', 'compellation',
-               existing_type=mysql.VARCHAR(length=255),
-               nullable=True)
-    op.drop_column('user', 'updated_at11')
-    op.create_index('ix_agent_id', 'agent', ['id'], unique=False)
-    op.create_table('dialog',
-    sa.Column('id', mysql.VARCHAR(length=255), nullable=False),
-    sa.Column('name', mysql.VARCHAR(length=255), nullable=False),
-    sa.Column('llm_id', mysql.VARCHAR(length=255), nullable=False),
-    sa.Column('status', mysql.VARCHAR(length=1), nullable=False),
-    sa.PrimaryKeyConstraint('id'),
-    mysql_collate='utf8mb4_0900_ai_ci',
-    mysql_default_charset='utf8mb4',
-    mysql_engine='InnoDB'
-    )
-    op.create_table('token',
-    sa.Column('id', mysql.INTEGER(), autoincrement=True, nullable=False),
-    sa.Column('user_id', mysql.INTEGER(), autoincrement=False, nullable=True),
-    sa.Column('token', mysql.TEXT(), nullable=True),
-    sa.Column('bisheng_token', mysql.TEXT(), nullable=True),
-    sa.Column('ragflow_token', mysql.TEXT(), nullable=True),
-    sa.Column('created_at', mysql.DATETIME(), nullable=True),
-    sa.PrimaryKeyConstraint('id'),
-    mysql_collate='utf8mb4_0900_ai_ci',
-    mysql_default_charset='utf8mb4',
-    mysql_engine='InnoDB'
-    )
-    op.create_table('organization_group',
-    sa.Column('group_id', mysql.INTEGER(), autoincrement=False, nullable=True),
-    sa.Column('organization_id', mysql.VARCHAR(length=36), nullable=True),
-    sa.ForeignKeyConstraint(['group_id'], ['group.id'], name='organization_group_ibfk_1'),
-    sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], name='organization_group_ibfk_2'),
-    mysql_collate='utf8mb4_0900_ai_ci',
-    mysql_default_charset='utf8mb4',
-    mysql_engine='InnoDB'
-    )
-    op.create_table('group_agent',
-    sa.Column('group_id', mysql.INTEGER(), autoincrement=False, nullable=True),
-    sa.Column('agent_id', mysql.VARCHAR(length=36), nullable=True),
-    sa.ForeignKeyConstraint(['agent_id'], ['canvas.id'], name='group_agent_ibfk_2', ondelete='CASCADE'),
-    sa.ForeignKeyConstraint(['group_id'], ['group.id'], name='group_agent_ibfk_1', ondelete='CASCADE'),
-    mysql_collate='utf8mb4_0900_ai_ci',
-    mysql_default_charset='utf8mb4',
-    mysql_engine='InnoDB'
-    )
-    op.create_table('group_info',
-    sa.Column('group_id', mysql.INTEGER(), autoincrement=True, nullable=False),
-    sa.Column('group_name', mysql.VARCHAR(length=255), nullable=False),
-    sa.Column('group_description', mysql.VARCHAR(length=255), nullable=True),
-    sa.Column('group_status', mysql.INTEGER(), autoincrement=False, nullable=False),
-    sa.Column('created_at', mysql.DATETIME(), nullable=True),
-    sa.Column('updated_at', mysql.DATETIME(), nullable=True),
-    sa.PrimaryKeyConstraint('group_id'),
-    mysql_collate='utf8mb4_0900_ai_ci',
-    mysql_default_charset='utf8mb4',
-    mysql_engine='InnoDB'
-    )
-    op.create_index('ix_group_info_group_name', 'group_info', ['group_name'], unique=True)
-    op.create_index('ix_group_info_group_id', 'group_info', ['group_id'], unique=False)
-    op.create_table('flow',
-    sa.Column('id', mysql.VARCHAR(length=255), nullable=False),
-    sa.Column('name', mysql.VARCHAR(length=255), nullable=False),
-    sa.Column('status', mysql.INTEGER(), autoincrement=False, nullable=False),
-    sa.PrimaryKeyConstraint('id'),
-    mysql_collate='utf8mb4_0900_ai_ci',
-    mysql_default_charset='utf8mb4',
-    mysql_engine='InnoDB'
-    )
-    op.create_table('user_canvas',
-    sa.Column('id', mysql.VARCHAR(length=32), nullable=False),
-    sa.Column('create_date', mysql.DATETIME(), nullable=True),
-    sa.Column('update_date', mysql.DATETIME(), nullable=True),
-    sa.Column('avatar', mysql.TEXT(), nullable=True),
-    sa.Column('user_id', mysql.VARCHAR(length=255), nullable=True),
-    sa.Column('title', mysql.VARCHAR(length=255), nullable=True),
-    sa.Column('description', mysql.TEXT(), nullable=True),
-    sa.Column('canvas_type', mysql.VARCHAR(length=32), nullable=True),
-    sa.Column('dsl', mysql.TEXT(), nullable=True),
-    sa.Column('agent_type', mysql.VARCHAR(length=2), nullable=True),
-    sa.PrimaryKeyConstraint('id'),
-    mysql_collate='utf8mb4_0900_ai_ci',
-    mysql_default_charset='utf8mb4',
-    mysql_engine='InnoDB'
-    )
-    op.create_table('app_register',
-    sa.Column('id', mysql.VARCHAR(length=36), nullable=False),
-    sa.Column('name', mysql.VARCHAR(length=255), nullable=True),
-    sa.Column('status', mysql.INTEGER(), autoincrement=False, nullable=False),
-    sa.Column('created_at', mysql.DATETIME(), nullable=True),
-    sa.Column('updated_at', mysql.DATETIME(), nullable=True),
-    sa.PrimaryKeyConstraint('id'),
-    mysql_collate='utf8mb4_0900_ai_ci',
-    mysql_default_charset='utf8mb4',
-    mysql_engine='InnoDB'
-    )
-    op.create_table('flow_test',
-    sa.Column('id', mysql.VARCHAR(length=255), nullable=False),
-    sa.Column('name', mysql.VARCHAR(length=255), nullable=False),
-    sa.Column('status', mysql.INTEGER(), autoincrement=False, nullable=False),
-    sa.PrimaryKeyConstraint('id'),
-    mysql_collate='utf8mb4_0900_ai_ci',
-    mysql_default_charset='utf8mb4',
-    mysql_engine='InnoDB'
-    )
-    op.create_table('sessions',
-    sa.Column('id', mysql.VARCHAR(length=255), nullable=False),
-    sa.Column('name', mysql.VARCHAR(length=255), nullable=True),
-    sa.Column('agent_id', mysql.VARCHAR(length=255), nullable=True),
-    sa.Column('agent_type', mysql.ENUM('RAGFLOW', 'BISHENG', 'BASIC', 'DIFY'), nullable=False),
-    sa.Column('create_date', mysql.DATETIME(), nullable=True),
-    sa.Column('update_date', mysql.DATETIME(), nullable=True),
-    sa.Column('tenant_id', mysql.INTEGER(), autoincrement=False, nullable=True),
-    sa.Column('message', mysql.TEXT(), nullable=True),
-    sa.Column('conversation_id', mysql.VARCHAR(length=64), nullable=True),
-    sa.PrimaryKeyConstraint('id'),
-    mysql_collate='utf8mb4_0900_ai_ci',
-    mysql_default_charset='utf8mb4',
-    mysql_engine='InnoDB'
-    )
-    op.create_table('df_api_token',
-    sa.Column('id', mysql.VARCHAR(length=36), nullable=False),
-    sa.Column('token', mysql.VARCHAR(length=36), nullable=True),
-    sa.Column('created_at', mysql.DATETIME(), nullable=True),
-    sa.Column('updated_at', mysql.DATETIME(), nullable=True),
-    sa.PrimaryKeyConstraint('id'),
-    mysql_collate='utf8mb4_0900_ai_ci',
-    mysql_default_charset='utf8mb4',
-    mysql_engine='InnoDB'
-    )
-    op.drop_index(op.f('ix_user_test_username'), table_name='user_test')
-    op.drop_index(op.f('ix_user_test_id'), table_name='user_test')
-    op.drop_table('user_test')
-    # ### end Alembic commands ###
diff --git a/alembic/versions/abc6bb9129ed_user_app_update.py b/alembic/versions/abc6bb9129ed_user_app_update.py
new file mode 100644
index 0000000..9ea28aa
--- /dev/null
+++ b/alembic/versions/abc6bb9129ed_user_app_update.py
@@ -0,0 +1,44 @@
+"""user app update
+
+Revision ID: abc6bb9129ed
+Revises: d4c8f204280f
+Create Date: 2024-12-09 16:57:06.559644
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects import mysql
+
+# revision identifiers, used by Alembic.
+revision: str = 'abc6bb9129ed'
+down_revision: Union[str, None] = 'd4c8f204280f'
+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.add_column('user_app', sa.Column('access_token', sa.String(length=1000), nullable=True))
+    op.add_column('user_app', sa.Column('refresh_token', sa.String(length=1000), nullable=True))
+    op.add_column('user_app', sa.Column('token_at', sa.DateTime(), nullable=True))
+    op.alter_column('user_app', 'app_type',
+               existing_type=mysql.INTEGER(),
+               type_=sa.String(length=16),
+               existing_nullable=True)
+    op.drop_index('ix_user_app_username', table_name='user_app')
+    # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.create_index('ix_user_app_username', 'user_app', ['username'], unique=True)
+    op.alter_column('user_app', 'app_type',
+               existing_type=sa.String(length=16),
+               type_=mysql.INTEGER(),
+               existing_nullable=True)
+    op.drop_column('user_app', 'token_at')
+    op.drop_column('user_app', 'refresh_token')
+    op.drop_column('user_app', 'access_token')
+    # ### end Alembic commands ###
diff --git a/alembic/versions/d4c8f204280f_user_app_add.py b/alembic/versions/d4c8f204280f_user_app_add.py
new file mode 100644
index 0000000..6d78333
--- /dev/null
+++ b/alembic/versions/d4c8f204280f_user_app_add.py
@@ -0,0 +1,67 @@
+"""user app add
+
+Revision ID: d4c8f204280f
+Revises: 07b5185945e0
+Create Date: 2024-12-09 15:43:14.470291
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects import mysql
+
+# revision identifiers, used by Alembic.
+revision: str = 'd4c8f204280f'
+down_revision: Union[str, None] = '07b5185945e0'
+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('user_app',
+    sa.Column('id', sa.Integer(), nullable=False),
+    sa.Column('username', sa.String(length=255), nullable=True),
+    sa.Column('password', sa.String(length=255), nullable=True),
+    sa.Column('email', sa.String(length=255), nullable=True),
+    sa.Column('user_id', sa.Integer(), nullable=True),
+    sa.Column('app_id', sa.String(length=36), nullable=True),
+    sa.Column('app_type', sa.Integer(), nullable=True),
+    sa.Column('status', sa.String(length=10), nullable=True),
+    sa.Column('created_at', sa.DateTime(), nullable=True),
+    sa.Column('updated_at', sa.DateTime(), nullable=True),
+    sa.PrimaryKeyConstraint('id'),
+    sa.UniqueConstraint('user_id', 'app_type', name='user_app_id_ix')
+    )
+    op.create_index(op.f('ix_user_app_id'), 'user_app', ['id'], unique=False)
+    op.create_index(op.f('ix_user_app_username'), 'user_app', ['username'], unique=True)
+    op.drop_table('dialog')
+    op.drop_table('flow')
+    # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.create_table('flow',
+    sa.Column('id', mysql.VARCHAR(length=255), nullable=False),
+    sa.Column('name', mysql.VARCHAR(length=255), nullable=False),
+    sa.Column('status', mysql.INTEGER(), autoincrement=False, nullable=False),
+    sa.PrimaryKeyConstraint('id'),
+    mysql_collate='utf8mb4_0900_ai_ci',
+    mysql_default_charset='utf8mb4',
+    mysql_engine='InnoDB'
+    )
+    op.create_table('dialog',
+    sa.Column('id', mysql.VARCHAR(length=255), nullable=False),
+    sa.Column('name', mysql.VARCHAR(length=255), nullable=False),
+    sa.Column('status', mysql.VARCHAR(length=1), nullable=False),
+    sa.PrimaryKeyConstraint('id'),
+    mysql_collate='utf8mb4_0900_ai_ci',
+    mysql_default_charset='utf8mb4',
+    mysql_engine='InnoDB'
+    )
+    op.drop_index(op.f('ix_user_app_username'), table_name='user_app')
+    op.drop_index(op.f('ix_user_app_id'), table_name='user_app')
+    op.drop_table('user_app')
+    # ### end Alembic commands ###
diff --git a/app/api/auth.py b/app/api/auth.py
index 2fc3ea7..a4d96a3 100644
--- a/app/api/auth.py
+++ b/app/api/auth.py
@@ -1,4 +1,5 @@
 import json
+import time
 
 from fastapi import APIRouter, Depends
 from sqlalchemy.orm import Session
@@ -14,9 +15,11 @@
 from app.models.token_model import upsert_token, get_token, update_token
 from app.models.user import UserCreate, LoginData
 from app.models.user_model import UserModel
-from app.service.auth import authenticate_user, create_access_token
+from app.service.auth import authenticate_user, create_access_token, is_valid_password, save_register_user, \
+    update_user_token, UserAppDao
 from app.service.bisheng import BishengService
 from app.service.common.app_register import AppRegisterDao
+from app.service.difyService import DifyService
 from app.service.ragflow import RagflowService
 from sqlalchemy.future import select
 
@@ -103,7 +106,7 @@
 
 
 @router.post("/v2/login", response_model=Response)
-async def login_test(login_data: LoginData, db: Session = Depends(get_db), pdb: AsyncSession = Depends(get_pdb)):
+async def login_v2(login_data: LoginData, db: Session = Depends(get_db), pdb: AsyncSession = Depends(get_pdb)):
     user = authenticate_user(db, login_data.username, login_data.password)
     if not user:
         return Response(code=400, msg="Incorrect username or password")
@@ -120,7 +123,10 @@
             logger.error("鏈煡娉ㄥ唽搴旂敤---")
             continue
         try:
-            token = await service.login(login_data.username, login_data.password)
+            user_app = UserAppDao(db).get_data_by_id(user.id, app["id"])
+            if user_app:
+                name  = user_app.username
+            token = await service.login(name, login_data.password)
             token_dict[app["id"]] = token
         except Exception as e:
             return Response(code=500, msg=f"Failed to login with {app['id']}: {str(e)}")
@@ -129,6 +135,7 @@
     access_token = create_access_token(data={"sub": user.username, "user_id": user.id})
 
     await update_token(db, user.id, access_token, token_dict)
+    await update_user_token(db, user.id, token_dict)
     result = await pdb.execute(select(AppToken).where(AppToken.id == user.id))
     db_app_token = result.scalars().first()
     if isinstance(access_token, bytes):
@@ -156,7 +163,9 @@
 
 
 @router.post("/v2/register", response_model=Response)
-async def register_test(user: UserCreate, db=Depends(get_db)):
+async def register_v2(user: UserCreate, db=Depends(get_db)):
+    if not is_valid_password(user.password):
+        return Response(code=400, msg="The password must be at least 8 and contain both numbers and letters")
     db_user = db.query(UserModel).filter(UserModel.username == user.username).first()
     if db_user:
         return Response(code=200, msg="Username already registered")
@@ -168,23 +177,29 @@
         elif app["id"] == BISHENG:
             service = BishengService(settings.sgb_base_url)
         elif app["id"] == DIFY:
-            continue
+            service = DifyService(settings.dify_base_url)
         else:
             logger.error("鏈煡娉ㄥ唽搴旂敤---")
             continue
         try:
-            register_info = await service.register(user.username, user.password)
-            register_dict[app['id']] = register_info.get("id") if app['id'] == RAGFLOW else register_info.get("user_id") if app['id'] == BISHENG else ""
+            name = app["id"] + str(int(time.time()))
+            register_info = await service.register(name, user.password)
+            print(register_info)
+            register_dict[app['id']] = {"id":register_info.get("id"), "name": name, "email": register_info.get("email")}
         except Exception as e:
             return Response(code=500, msg=f"Failed to register with {app['id']}: {str(e)}")
 
     # 瀛樺偍鐢ㄦ埛淇℃伅
-    hashed_password = pwd_context.hash(user.password)
-    db_user = UserModel(username=user.username, hashed_password=hashed_password, email=user.email)
-    db_user.password = db_user.encrypted_password(user.password)
-    for k, v in register_dict.items():
-        setattr(db_user, k.replace("app", "id"), v)
-    db.add(db_user)
-    db.commit()
-    db.refresh(db_user)
-    return Response(code=200, msg="User registered successfully",data={"username": db_user.username})
\ No newline at end of file
+    # hashed_password = pwd_context.hash(user.password)
+    # db_user = UserModel(username=user.username, hashed_password=hashed_password, email=user.email)
+    # db_user.password = db_user.encrypted_password(user.password)
+    # for k, v in register_dict.items():
+    #     setattr(db_user, k.replace("app", "id"), v)
+    # db.add(db_user)
+    # db.commit()
+    # db.refresh(db_user)
+
+    is_sava = await save_register_user(db, user.username, user.password, user.email, register_dict)
+    if not is_sava:
+        return Response(code=500, msg=f"Failed to register with app")
+    return Response(code=200, msg="User registered successfully",data={"username": user.username})
\ No newline at end of file
diff --git a/app/config/const.py b/app/config/const.py
index 007e8e4..f4fb7a9 100644
--- a/app/config/const.py
+++ b/app/config/const.py
@@ -8,4 +8,10 @@
 ### -----------app register --------------
 RAGFLOW = "ragflow_app"
 BISHENG = "bisheng_app"
-DIFY = "dify_app"
\ No newline at end of file
+DIFY = "dify_app"
+
+### ---------------app type-----------------
+BASIC_ID = 3
+RAGFLOW_ID = 1
+BISHENG_ID = 2
+DIFY_ID = 4
\ No newline at end of file
diff --git a/app/models/__init__.py b/app/models/__init__.py
index 008613d..97f96bd 100644
--- a/app/models/__init__.py
+++ b/app/models/__init__.py
@@ -11,6 +11,9 @@
 from .resource_model import *
 from .role_model import *
 from .user_model import *
+from .token_model import *
+from .session_model import SessionModel
+from .public_api_model import *
 
 
 # 鑾峰彇褰撳墠鏃跺尯鐨勬椂闂�
diff --git a/app/models/session_model.py b/app/models/session_model.py
index fd513d2..b7fae97 100644
--- a/app/models/session_model.py
+++ b/app/models/session_model.py
@@ -1,11 +1,17 @@
 import json
 from datetime import datetime
 from enum import IntEnum
+
+import pytz
 from sqlalchemy import Column, String, Enum as SQLAlchemyEnum, Integer, DateTime, JSON, TEXT
 
-from app.models import AgentType, current_time
+from app.models.agent_model import AgentType
+# from app.models import current_time
 from app.models.base_model import Base
 
+def current_time():
+    tz = pytz.timezone('Asia/Shanghai')
+    return datetime.now(tz)
 
 class SessionModel(Base):
     __tablename__ = "sessions"
diff --git a/app/models/user_model.py b/app/models/user_model.py
index 0cf9fd5..a1d61dd 100644
--- a/app/models/user_model.py
+++ b/app/models/user_model.py
@@ -1,7 +1,7 @@
 from datetime import datetime
 
 from cryptography.fernet import Fernet
-from sqlalchemy import Column, Integer, String, Table, ForeignKey, DateTime
+from sqlalchemy import Column, Integer, String, Table, ForeignKey, DateTime, UniqueConstraint
 from sqlalchemy.orm import relationship, backref
 
 from app.config.config import settings
@@ -27,21 +27,20 @@
     username = Column(String(255), unique=True, index=True)
     hashed_password = Column(String(255))
     password = Column(String(255))
-    compellation = Column(String(255), nullable=False, default="")
-    phone = Column(String(255), nullable=False, default="")
-    email = Column(String(255), nullable=False, default="")
-    description = Column(String(255), nullable=False, default="")
+    compellation = Column(String(255), default="")
+    phone = Column(String(255),  default="")
+    email = Column(String(255),  default="")
+    description = Column(String(255), default="")
     ragflow_id = Column(String(32))
     bisheng_id = Column(Integer)
     login_name = Column(String(100))
-    status = Column(String(10), nullable=False, default="1")
+    status = Column(String(10),  default="1")
     creator = Column(String(36))
     sex = Column(String(1))
-    permission = Column(String(16), nullable=False, default="general")
+    permission = Column(String(16), default="general")
     age = Column(Integer)
     created_at = Column(DateTime, default=datetime.now())
     updated_at = Column(DateTime, default=datetime.now(), onupdate=datetime.now())
-    updated_at11 = Column(Integer)
 
 
 
@@ -181,15 +180,33 @@
 
 
 
-class UserModel(Base):
-    __tablename__ = "user_test"
+class UserAppModel(Base):
+    __tablename__ = "user_app"
+    __table_args__ = (UniqueConstraint('user_id', 'app_type', name='user_app_id_ix'),)
     id = Column(Integer, primary_key=True, index=True)
-    username = Column(String(255), unique=True, index=True)
-    hashed_password = Column(String(255))
+    username = Column(String(255))
     password = Column(String(255))
-    compellation = Column(String(255), nullable=False, default="")
-    phone = Column(String(255), nullable=False, default="")
-    email = Column(String(255), nullable=False, default="")
-    description = Column(String(255), nullable=False, default="")
-    ragflow_id = Column(String(32))
-    bisheng_id = Column(Integer)
\ No newline at end of file
+    email = Column(String(255),  default="")
+    user_id = Column(Integer)
+    app_id = Column(String(36))
+    app_type = Column(String(16))
+    status = Column(String(10),  default="1")
+    access_token = Column(String(1000))
+    refresh_token = Column(String(1000))
+    token_at = Column(DateTime, default=datetime.now())
+    created_at = Column(DateTime, default=datetime.now())
+    updated_at = Column(DateTime, default=datetime.now(), onupdate=datetime.now())
+
+    def to_json(self):
+        return {
+            'id': self.id,
+            'userName': self.username,
+            'createTime': self.created_at.strftime('%Y-%m-%d %H:%M:%S') if self.created_at else "",
+            'updateTime': self.updated_at.strftime('%Y-%m-%d %H:%M:%S') if self.created_at else "",
+            'password': self.password,
+            'email': self.email,
+            'user_id': self.user_id,
+            'app_id': self.app_id,
+            "app_type": self.app_type,
+            'status': self.status,
+        }
diff --git a/app/service/auth.py b/app/service/auth.py
index 896b8d9..d843adb 100644
--- a/app/service/auth.py
+++ b/app/service/auth.py
@@ -1,10 +1,15 @@
+import re
 from datetime import datetime, timedelta
+from typing import Type
+
 from jwt import encode, decode, exceptions
 from passlib.context import CryptContext
 from fastapi import HTTPException, status
+from sqlalchemy.orm import Session
 
+from Log import logger
 from app.config.config import settings
-from app.models.user_model import UserModel
+from app.models.user_model import UserModel, UserAppModel
 
 SECRET_KEY = settings.secret_key
 ALGORITHM = "HS256"
@@ -47,3 +52,98 @@
         return payload
     except exceptions.DecodeError:
         raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials")
+
+
+def is_valid_password(password: str) -> bool:
+    if len(password) <= 8:
+        return False
+    has_digit = re.search(r'[0-9]', password)
+    has_letter = re.search(r'[A-Za-z]', password)
+
+    # 濡傛灉瀵嗙爜鍖呭惈鏁板瓧鍜屽瓧姣嶏紝鍒欒繑鍥濼rue锛屽惁鍒欒繑鍥濶one
+    return has_digit is not None and has_letter is not None
+
+
+async def save_register_user(db, username, password, email, register_dict):
+    user_id = ""
+    try:
+        hashed_password = pwd_context.hash(password)
+        db_user = UserModel(username=username, hashed_password=hashed_password, email=email)
+        pwd = db_user.encrypted_password(password)
+        db_user.password = pwd
+        db.add(db_user)
+        db.add(db_user)
+        db.commit()
+        db.refresh(db_user)
+        user_id = db_user.id
+        for k, v in register_dict.items():
+            UserAppDao(db).update_and_insert_token(v.get("name"), pwd, v.get("email"), user_id, str(v.get("id")), k)
+
+    except Exception as e:
+        logger.error(e)
+        # db.roolback()
+        if user_id:
+            db.query(UserModel).filter(UserModel.id == user_id).delete()
+        return False
+    return True
+
+
+async def update_user_token(db, user_id, token_dict):
+
+    try:
+        for k, v in token_dict.items():
+            UserAppDao(db).update_user_app_data({"user_id": user_id, "app_type": k},
+                                                {"access_token": v, "token_at": datetime.now()})
+
+    except Exception as e:
+        logger.error(e)
+        return False
+    return True
+
+
+class UserAppDao:
+    def __init__(self, db: Session):
+        self.db = db
+
+    def get_data_by_id(self, user_id: int, app_type: int) -> Type[UserAppModel] | None:
+        session = self.db.query(UserAppModel).filter_by(user_id=user_id, app_type=app_type).first()
+        return session
+
+    def update_user_app_data(self, query: int, update_data: str):
+
+        logger.error("鏇存柊鏁版嵁df update_app_data---------------------------")
+        try:
+            self.db.query(UserAppModel).filter_by(**query).update(update_data)
+            self.db.commit()
+        except Exception as e:
+            logger.error(e)
+            self.db.rollback()
+            raise Exception("鏇存柊澶辫触锛�")
+
+    def insert_user_app_data(self, username: str, password: str, email: str, user_id: int, app_id: str, app_type: int):
+        logger.error("鏂板鏁版嵁df insert_user_app_data---------------------------")
+        new_session = UserAppModel(
+            username=username,
+            password=password,
+            email=email,
+            user_id=user_id,
+            app_id=app_id,
+            app_type=app_type,
+        )
+        self.db.add(new_session)
+        self.db.commit()
+        self.db.refresh(new_session)
+        return new_session
+
+    def update_and_insert_token(self, username: str, password: str, email: str, user_id: int, app_id: str,
+                                app_type: int):
+
+        logger.error("鏇存柊鎴栬�呮坊鍔犳暟鎹� update_and_insert_token---------------------------")
+        token_boj = self.get_data_by_id(user_id, app_type)
+        if token_boj:
+            self.update_user_app_data({"id": token_boj.id}, {"username": username,
+                                                             "password": password, "email": email, "username": username,
+                                                             "updated_at": datetime.now(),
+                                                             })
+        else:
+            self.insert_user_app_data(username, password, email, user_id, app_id, app_type)
diff --git a/app/service/bisheng.py b/app/service/bisheng.py
index d4ff068..ff1accc 100644
--- a/app/service/bisheng.py
+++ b/app/service/bisheng.py
@@ -35,7 +35,10 @@
                 json={"user_name": username, "password": password},
                 headers={'Content-Type': 'application/json'}
             )
-            return self._check_response(response)
+            res = self._check_response(response)
+            if isinstance(res, dict):
+                res["id"] = res.get("user_id")
+            return res
 
     async def login(self, username: str, password: str) -> str:
         public_key = await self.get_public_key_api()
diff --git a/app/service/difyService.py b/app/service/difyService.py
index 93bc62b..7329640 100644
--- a/app/service/difyService.py
+++ b/app/service/difyService.py
@@ -1,11 +1,13 @@
 import json
 from datetime import datetime
+from urllib.parse import urlparse, parse_qs
 
 import httpx
 from typing import Union, Dict, List
 from fastapi import HTTPException
 from starlette import status
 
+# from Log import logger
 from app.config.config import settings
 from app.utils.rsa_crypto import RagflowCrypto
 
@@ -38,32 +40,90 @@
         else:
             return data
 
-    async def register(self, username: str, password: str):
-        password = RagflowCrypto(settings.PUBLIC_KEY, settings.PRIVATE_KEY).encrypt(password)
+    async def register(self, username: str, password: str, token=None):
+        if not token:
+            token = await get_df_token()
+        email = f"{username}@df.com"
+        invite_res = await self.invite_workspaces_member(token, [email], "admin")
+        # print(invite_res)
+        if invite_res.get("result") != "success" or not invite_res.get("invitation_results"):
+            # logger.error(invite_res)
+            return {}
+        invite_token = \
+        parse_qs(urlparse(invite_res.get("invitation_results")[0].get("url", "")).query).get('token', [None])[0]
+        # print(invite_token)
+        if not invite_token:
+            return {}
+        await self.login(email, password, True, invite_token)
+        activate_res = await self.activate(email, username, invite_token, "", "")
+        activate_res["email"] = email
+        activate_res["id"] = invite_token
+        return activate_res
+
+
+    async def invite_workspaces_member(self, token, emails: list, role: str):
         async with httpx.AsyncClient() as client:
             response = await client.post(
-                f"{self.base_url}/v1/user/register",
-                headers={'Content-Type': 'application/json'},
-                json={"nickname": username, "email":  f"{username}@example.com", "password": password}
+                f"{self.base_url}/console/api/workspaces/current/members/invite-email",
+                headers={'Content-Type': 'application/json',"Authorization": f'Bearer {token}'},
+                json={"emails": emails, "language":  "zh-Hans", "role": role}
             )
-            if response.status_code != 200:
-                raise Exception(f"Ragflow registration failed: {response.text}")
+            print(response.text)
             return self._handle_response(response)
 
-    async def login(self, username: str, password: str) -> str:
-        password = RagflowCrypto(settings.PUBLIC_KEY, settings.PRIVATE_KEY).encrypt(password)
+    async def login(self, email: str, password: str, remember_me,invite_token:str="") -> str:
+        # password = RagflowCrypto(settings.PUBLIC_KEY, settings.PRIVATE_KEY).encrypt(password)
+        data = {"email": email, "password": password, "remember_me": remember_me, "invite_token": invite_token,
+         "language": "zh-Hans"}
+
         async with httpx.AsyncClient() as client:
             response = await client.post(
-                f"{self.base_url}/v1/user/login",
+                f"{self.base_url}/console/api/login",
                 headers={'Content-Type': 'application/json'},
-                json={"email": f"{username}@example.com", "password": password}
+                json=data
             )
             if response.status_code != 200:
-                raise Exception(f"Ragflow login failed: {response.text}")
-            authorization = response.headers.get('Authorization')
-            if not authorization:
-                raise Exception("Authorization header not found in response")
-            return authorization
+                raise Exception(f"df login failed: {response.text}")
+            return self._handle_response(response)
+
+    async def email_check(self, token, email: str):
+        async with httpx.AsyncClient() as client:
+            response = await client.get(
+                f"{self.base_url}/console/api/activate/check?email={email}&token={token}",
+                headers={'Content-Type': 'application/json'}
+            )
+            return self._handle_response(response)
+
+    async def activate(self, email: str, name: str, token, workspace_id:str, access_token) -> str:
+        # password = RagflowCrypto(settings.PUBLIC_KEY, settings.PRIVATE_KEY).encrypt(password)
+        data = {"email": email, "name": name, "token": token, #  "workspace_id": workspace_id,
+         "interface_language": "en-US", "timezone": "Asia/Shanghai"}
+        print(data)
+        async with httpx.AsyncClient() as client:
+            response = await client.post(
+                f"{self.base_url}/console/api/activate",
+                headers={'Content-Type': 'application/json'},  # , 'Authorization': f'Bearer {access_token}'
+                json=data
+            )
+            if response.status_code != 200:
+                raise Exception(f"df login failed: {response.text}")
+            return self._handle_response(response)
+
+    async def invite_member_activate(self, token:str, email: str, name: str, password:str) -> str:
+        invite_res  =  await self.invite_workspaces_member(token, [email], "admin")
+        print(invite_res)
+        if invite_res.get("result") != "success" or not invite_res.get("invitation_results"):
+            # logger.error(invite_res)
+            return {}
+        invite_token = parse_qs(urlparse(invite_res.get("invitation_results")[0].get("url", "")).query).get('token', [None])[0]
+        # print(invite_token)
+        if not invite_token:
+            return {}
+        await self.login(email, password, True, invite_token)
+        activate_res = await self.activate(email, name,invite_token, "", "")
+        return activate_res
+
+
 
     async def chat(self, token: str, user_id: int,  message: str, upload_file_id: str, conversation_id: str):
 
@@ -186,8 +246,28 @@
 if __name__ == "__main__":
     async def a():
         a = DifyService("http://192.168.20.116")
-        b = await a.get_session_history("app-YmOAMDsPpDDlqryMHnc9TzTO", "f94c6328-8ff0-4713-af3f-e823d547682d",
-                                 "63")
+        # b = await a.invite_workspaces_member("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMjE0Y2I2ODctZTZlMC00ZTE2LWExNzUtYzcyNDNlMGRhMWEwIiwiZXhwIjoxNzMzNzI2NDA5LCJpc3MiOiJTRUxGX0hPU1RFRCIsInN1YiI6IkNvbnNvbGUgQVBJIFBhc3Nwb3J0In0.jLe1ODbcqCe79CDt6fFwnuuQL4I2FB9YTs9ynk4FeoQ", ["test05@163.com"],
+        #                          "admin")
+
+        # b = await a.email_check(
+        #     "ebd36739-0272-4b3f-95ab-0c6ac1639831",
+        #     "test05@163.com")
+        # b = await a.login(
+        #     "test05@163.com",
+        #     "zhaoqg123456",
+        #     True, "ebd36739-0272-4b3f-95ab-0c6ac1639831")
+
+
+
+        # b = await a.activate(
+        #     "test05@163.com",
+        #     "test05", "ebd36739-0272-4b3f-95ab-0c6ac1639831", "", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiNzg5OWUzOGQtNzczOS00NGNmLTgyODItZmFlMGZhNDJlZDYwIiwiZXhwIjoxNzMzNzI5NjQyLCJpc3MiOiJTRUxGX0hPU1RFRCIsInN1YiI6IkNvbnNvbGUgQVBJIFBhc3Nwb3J0In0.YMvypPnrvvUIfqzcESj820nP46IsFdTpF_YPz8_Exso")
+
+        b = await a.invite_member_activate(
+            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMDE2NTcxNjAtZTllYi00NzVhLWIzMzYtZjlmZWJlY2I5YjczIiwiZXhwIjoxNzMzNzM0ODE0LCJpc3MiOiJTRUxGX0hPU1RFRCIsInN1YiI6IkNvbnNvbGUgQVBJIFBhc3Nwb3J0In0.khaXX3ndDe_pccEHcyTUcO2sgBCEfXCR74ZniP_b54Y",
+                "zhao1@df.com",
+                 "zhao1Q",
+        "ZHAOQG123456")
         print(b)
 
     import asyncio
diff --git a/app/task/fetch_agent.py b/app/task/fetch_agent.py
index 178a55f..36b3c2e 100644
--- a/app/task/fetch_agent.py
+++ b/app/task/fetch_agent.py
@@ -119,7 +119,8 @@
             ('basic_excel_talk', 6, '鏅鸿兘鏁版嵁', 'BASIC', 'excelTalk'),
             ('basic_question_talk', 7, '鍑洪缁勫嵎', 'BASIC', 'questionTalk'),
             ('9d75142a-66eb-4e23-b7d4-03efe4584915', 8, '灏忔暟缁樺浘', 'DIFY', 'imageTalk'),
-            ('basic_paper_talk', 8, '鏂囨。鍑哄嵎', 'BASIC', 'paperTalk')
+            ('basic_paper_talk', 8, '鏂囨。鍑哄嵎', 'BASIC', 'paperTalk'),
+            ('basic_report_clean', 10, '鏂囨。鎶ュ憡', 'DIFY', 'reportWorkflow')
         ]
 
         for agent in initial_agents:
diff --git a/main.py b/main.py
index 0c77e3c..8e41c56 100644
--- a/main.py
+++ b/main.py
@@ -37,7 +37,7 @@
     # 鍦ㄥ簲鐢ㄥ叧闂椂鎵ц娓呯悊鎿嶄綔锛堝鏋滈渶瑕侊級
     pass
 
-init_db()
+# init_db()
 app = FastAPI(
     title="basic_rag_gateway",
     version="0.1",

--
Gitblit v1.8.0