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