diff --git a/api/controllers/console/explore/conversation.py b/api/controllers/console/explore/conversation.py index 06c050ea15..dc7004e5f1 100644 --- a/api/controllers/console/explore/conversation.py +++ b/api/controllers/console/explore/conversation.py @@ -49,7 +49,7 @@ class ConversationListApi(InstalledAppResource): try: return WebConversationService.pagination_by_last_id( app_model=app_model, - end_user=current_user, + user=current_user, last_id=args['last_id'], limit=args['limit'], pinned=pinned @@ -86,7 +86,7 @@ class ConversationRenameApi(InstalledAppResource): args = parser.parse_args() try: - return ConversationService.rename(app_model, conversation_id, end_user, args['name']) + return ConversationService.rename(app_model, conversation_id, current_user, args['name']) except ConversationNotExistsError: raise NotFound("Conversation Not Exists.") diff --git a/api/controllers/console/explore/installed_app.py b/api/controllers/console/explore/installed_app.py index b88a956297..99e6df90b0 100644 --- a/api/controllers/console/explore/installed_app.py +++ b/api/controllers/console/explore/installed_app.py @@ -22,11 +22,12 @@ app_fields = { installed_app_fields = { 'id': fields.String, - 'app': fields.Nested(app_fields, attribute='app'), + 'app': fields.Nested(app_fields), 'app_owner_tenant_id': fields.String, 'is_pinned': fields.Boolean, 'last_used_at': fields.DateTime, - 'editable': fields.Boolean + 'editable': fields.Boolean, + 'uninstallable': fields.Boolean, } installed_app_list_fields = { @@ -53,6 +54,7 @@ class InstalledAppsListApi(Resource): 'is_pinned': installed_app.is_pinned, 'last_used_at': installed_app.last_used_at, "editable": current_user.role in ["owner", "admin"], + "uninstallable": current_user.current_tenant_id == installed_app.app_owner_tenant_id } for installed_app in installed_apps ] diff --git a/api/migrations/versions/9f4e3427ea84_add_created_by_role.py b/api/migrations/versions/9f4e3427ea84_add_created_by_role.py new file mode 100644 index 0000000000..c7e3e801ec --- /dev/null +++ b/api/migrations/versions/9f4e3427ea84_add_created_by_role.py @@ -0,0 +1,46 @@ +"""add created by role + +Revision ID: 9f4e3427ea84 +Revises: 64b051264f32 +Create Date: 2023-05-17 17:29:01.060435 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '9f4e3427ea84' +down_revision = '64b051264f32' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('pinned_conversations', schema=None) as batch_op: + batch_op.add_column(sa.Column('created_by_role', sa.String(length=255), server_default=sa.text("'end_user'::character varying"), nullable=False)) + batch_op.drop_index('pinned_conversation_conversation_idx') + batch_op.create_index('pinned_conversation_conversation_idx', ['app_id', 'conversation_id', 'created_by_role', 'created_by'], unique=False) + + with op.batch_alter_table('saved_messages', schema=None) as batch_op: + batch_op.add_column(sa.Column('created_by_role', sa.String(length=255), server_default=sa.text("'end_user'::character varying"), nullable=False)) + batch_op.drop_index('saved_message_message_idx') + batch_op.create_index('saved_message_message_idx', ['app_id', 'message_id', 'created_by_role', 'created_by'], unique=False) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('saved_messages', schema=None) as batch_op: + batch_op.drop_index('saved_message_message_idx') + batch_op.create_index('saved_message_message_idx', ['app_id', 'message_id', 'created_by'], unique=False) + batch_op.drop_column('created_by_role') + + with op.batch_alter_table('pinned_conversations', schema=None) as batch_op: + batch_op.drop_index('pinned_conversation_conversation_idx') + batch_op.create_index('pinned_conversation_conversation_idx', ['app_id', 'conversation_id', 'created_by'], unique=False) + batch_op.drop_column('created_by_role') + + # ### end Alembic commands ### diff --git a/api/models/web.py b/api/models/web.py index 1580ce74c9..b2466430b9 100644 --- a/api/models/web.py +++ b/api/models/web.py @@ -8,12 +8,13 @@ class SavedMessage(db.Model): __tablename__ = 'saved_messages' __table_args__ = ( db.PrimaryKeyConstraint('id', name='saved_message_pkey'), - db.Index('saved_message_message_idx', 'app_id', 'message_id', 'created_by'), + db.Index('saved_message_message_idx', 'app_id', 'message_id', 'created_by_role', 'created_by'), ) id = db.Column(UUID, server_default=db.text('uuid_generate_v4()')) app_id = db.Column(UUID, nullable=False) message_id = db.Column(UUID, nullable=False) + created_by_role = db.Column(db.String(255), nullable=False, server_default=db.text("'end_user'::character varying")) created_by = db.Column(UUID, nullable=False) created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)')) @@ -26,11 +27,12 @@ class PinnedConversation(db.Model): __tablename__ = 'pinned_conversations' __table_args__ = ( db.PrimaryKeyConstraint('id', name='pinned_conversation_pkey'), - db.Index('pinned_conversation_conversation_idx', 'app_id', 'conversation_id', 'created_by'), + db.Index('pinned_conversation_conversation_idx', 'app_id', 'conversation_id', 'created_by_role', 'created_by'), ) id = db.Column(UUID, server_default=db.text('uuid_generate_v4()')) app_id = db.Column(UUID, nullable=False) conversation_id = db.Column(UUID, nullable=False) + created_by_role = db.Column(db.String(255), nullable=False, server_default=db.text("'end_user'::character varying")) created_by = db.Column(UUID, nullable=False) created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)')) diff --git a/api/services/saved_message_service.py b/api/services/saved_message_service.py index 1a68a1ba34..e363f65fa9 100644 --- a/api/services/saved_message_service.py +++ b/api/services/saved_message_service.py @@ -1,7 +1,8 @@ -from typing import Optional +from typing import Optional, Union from libs.infinite_scroll_pagination import InfiniteScrollPagination from extensions.ext_database import db +from models.account import Account from models.model import App, EndUser from models.web import SavedMessage from services.message_service import MessageService @@ -9,27 +10,29 @@ from services.message_service import MessageService class SavedMessageService: @classmethod - def pagination_by_last_id(cls, app_model: App, end_user: Optional[EndUser], + def pagination_by_last_id(cls, app_model: App, user: Optional[Union[Account | EndUser]], last_id: Optional[str], limit: int) -> InfiniteScrollPagination: saved_messages = db.session.query(SavedMessage).filter( SavedMessage.app_id == app_model.id, - SavedMessage.created_by == end_user.id + SavedMessage.created_by_role == ('account' if isinstance(user, Account) else 'end_user'), + SavedMessage.created_by == user.id ).order_by(SavedMessage.created_at.desc()).all() message_ids = [sm.message_id for sm in saved_messages] return MessageService.pagination_by_last_id( app_model=app_model, - user=end_user, + user=user, last_id=last_id, limit=limit, include_ids=message_ids ) @classmethod - def save(cls, app_model: App, user: Optional[EndUser], message_id: str): + def save(cls, app_model: App, user: Optional[Union[Account | EndUser]], message_id: str): saved_message = db.session.query(SavedMessage).filter( SavedMessage.app_id == app_model.id, SavedMessage.message_id == message_id, + SavedMessage.created_by_role == ('account' if isinstance(user, Account) else 'end_user'), SavedMessage.created_by == user.id ).first() @@ -45,6 +48,7 @@ class SavedMessageService: saved_message = SavedMessage( app_id=app_model.id, message_id=message.id, + created_by_role='account' if isinstance(user, Account) else 'end_user', created_by=user.id ) @@ -52,10 +56,11 @@ class SavedMessageService: db.session.commit() @classmethod - def delete(cls, app_model: App, user: Optional[EndUser], message_id: str): + def delete(cls, app_model: App, user: Optional[Union[Account | EndUser]], message_id: str): saved_message = db.session.query(SavedMessage).filter( SavedMessage.app_id == app_model.id, SavedMessage.message_id == message_id, + SavedMessage.created_by_role == ('account' if isinstance(user, Account) else 'end_user'), SavedMessage.created_by == user.id ).first() diff --git a/api/services/web_conversation_service.py b/api/services/web_conversation_service.py index 5cfab25006..231083db19 100644 --- a/api/services/web_conversation_service.py +++ b/api/services/web_conversation_service.py @@ -2,6 +2,7 @@ from typing import Optional, Union from libs.infinite_scroll_pagination import InfiniteScrollPagination from extensions.ext_database import db +from models.account import Account from models.model import App, EndUser from models.web import PinnedConversation from services.conversation_service import ConversationService @@ -9,14 +10,15 @@ from services.conversation_service import ConversationService class WebConversationService: @classmethod - def pagination_by_last_id(cls, app_model: App, end_user: Optional[EndUser], + def pagination_by_last_id(cls, app_model: App, user: Optional[Union[Account | EndUser]], last_id: Optional[str], limit: int, pinned: Optional[bool] = None) -> InfiniteScrollPagination: include_ids = None exclude_ids = None if pinned is not None: pinned_conversations = db.session.query(PinnedConversation).filter( PinnedConversation.app_id == app_model.id, - PinnedConversation.created_by == end_user.id + PinnedConversation.created_by_role == ('account' if isinstance(user, Account) else 'end_user'), + PinnedConversation.created_by == user.id ).order_by(PinnedConversation.created_at.desc()).all() pinned_conversation_ids = [pc.conversation_id for pc in pinned_conversations] if pinned: @@ -26,7 +28,7 @@ class WebConversationService: return ConversationService.pagination_by_last_id( app_model=app_model, - user=end_user, + user=user, last_id=last_id, limit=limit, include_ids=include_ids, @@ -34,10 +36,11 @@ class WebConversationService: ) @classmethod - def pin(cls, app_model: App, conversation_id: str, user: Optional[EndUser]): + def pin(cls, app_model: App, conversation_id: str, user: Optional[Union[Account | EndUser]]): pinned_conversation = db.session.query(PinnedConversation).filter( PinnedConversation.app_id == app_model.id, PinnedConversation.conversation_id == conversation_id, + PinnedConversation.created_by_role == ('account' if isinstance(user, Account) else 'end_user'), PinnedConversation.created_by == user.id ).first() @@ -53,6 +56,7 @@ class WebConversationService: pinned_conversation = PinnedConversation( app_id=app_model.id, conversation_id=conversation.id, + created_by_role='account' if isinstance(user, Account) else 'end_user', created_by=user.id ) @@ -60,10 +64,11 @@ class WebConversationService: db.session.commit() @classmethod - def unpin(cls, app_model: App, conversation_id: str, user: Optional[EndUser]): + def unpin(cls, app_model: App, conversation_id: str, user: Optional[Union[Account | EndUser]]): pinned_conversation = db.session.query(PinnedConversation).filter( PinnedConversation.app_id == app_model.id, PinnedConversation.conversation_id == conversation_id, + PinnedConversation.created_by_role == ('account' if isinstance(user, Account) else 'end_user'), PinnedConversation.created_by == user.id ).first()