Skip to content

Commit d4d9a86

Browse files
authored
Merge pull request #49 from pattern-tech/feat/access-check
fix[api]: access check added
2 parents 7b9120e + 2156865 commit d4d9a86

4 files changed

Lines changed: 57 additions & 4 deletions

File tree

api/src/conversation/routers/playground_conversation_router.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from uuid import UUID
22
from enum import Enum
3-
from typing import List
3+
from typing import List, Dict
44
from pydantic import BaseModel
55
from sqlalchemy.orm import Session
66
from fastapi.responses import StreamingResponse
@@ -59,6 +59,7 @@ class ConversationOutput(BaseModel):
5959
id: UUID
6060
name: str
6161
project_id: UUID
62+
chat_history: List[Dict]
6263

6364
class Config:
6465
from_attributes = True
@@ -255,7 +256,7 @@ def delete_conversation(
255256
"/{project_id}/{conversation_id}/chat",
256257
summary="Send Message",
257258
description="Sends a message in the conversation chat for the authenticated user.",
258-
response_description="The message response data along with intermediate steps metadata."
259+
response_description="The message response data along with chat history in metadata."
259260
)
260261
async def send_message(
261262
input: MessageInput,
@@ -277,9 +278,13 @@ async def send_message(
277278
- **service**: Conversation service handling business logic.
278279
- **user_id**: The authenticated user's ID.
279280
281+
- **metadata**: The chat history metadata.
282+
280283
Returns:
281284
StreamingResponse: If `stream` is true.
282285
dict: A JSON response containing the complete message data if `stream` is false.
286+
287+
metadata: The chat history metadata.
283288
"""
284289
try:
285290

@@ -298,6 +303,7 @@ async def send_message(
298303
input.message,
299304
user_id,
300305
conversation_id,
306+
project_id,
301307
input.message_type,
302308
input.stream),
303309
media_type="text/plain"
@@ -309,6 +315,7 @@ async def send_message(
309315
input.message,
310316
user_id,
311317
conversation_id,
318+
project_id,
312319
input.message_type,
313320
input.stream
314321
):

api/src/conversation/services/conversation_service.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from src.agent.services.memory_service import MemoryService
1313
from src.project.services.project_service import ProjectService
1414
from src.agent.services.agent_service import RouterAgentService
15+
from src.project.repositories.project_repository import ProjectRepository
1516
from src.query_usage.services.query_usage_service import QueryUsageService
1617
from src.conversation.repositories.conversation_repository import ConversationRepository
1718

@@ -23,6 +24,7 @@ class ConversationService:
2324

2425
def __init__(self):
2526
self.repository = ConversationRepository()
27+
self.project_repository = ProjectRepository()
2628
self.memory_service = MemoryService()
2729
self.project_service = ProjectService()
2830
self.query_usage_service = QueryUsageService()
@@ -43,6 +45,12 @@ def create_conversation(
4345
Returns:
4446
Conversation: The created conversation instance.
4547
"""
48+
if name.strip() == "":
49+
raise Exception("Name is required")
50+
51+
if not self.project_repository.get_by_id(db_session, project_id, user_id):
52+
raise Exception("Project not exists or not owned by user")
53+
4654
conversation = Conversation(
4755
name=name, project_id=project_id, user_id=user_id)
4856
return self.repository.create(db_session, conversation)
@@ -106,6 +114,12 @@ def update_conversation(
106114
Raises:
107115
Exception: If the conversation is not found.
108116
"""
117+
if data["name"].strip() == "":
118+
raise Exception("Name is required")
119+
120+
if not self.project_repository.get_by_id(db_session, data["project_id"], user_id):
121+
raise Exception("Project not exists or not owned by user")
122+
109123
return self.repository.update(db_session, conversation_id, data, user_id)
110124

111125
def delete_conversation(
@@ -143,6 +157,7 @@ async def send_message(
143157
message: str,
144158
user_id: UUID,
145159
conversation_id: UUID,
160+
project_id: UUID,
146161
message_type: str,
147162
stream: bool
148163
):
@@ -154,6 +169,7 @@ async def send_message(
154169
message (str): The message to be processed
155170
user_id (UUID): ID of the user sending the message
156171
conversation_id (UUID): ID of the conversation the message belongs to
172+
project_id (UUID): ID of the project associated with the conversation
157173
message_type (str): Type of the message
158174
stream (bool): If True, streams response tokens. If False, returns complete response
159175
@@ -168,6 +184,14 @@ async def send_message(
168184
Raises:
169185
Exception: If associated project is not found
170186
"""
187+
conversation = self.repository.get_by_id(
188+
db_session, conversation_id, user_id)
189+
190+
if not conversation:
191+
raise Exception("Conversation not found or is not owned by user")
192+
193+
if conversation.project_id != project_id:
194+
raise Exception("Project not found or is not owned by user")
171195

172196
config = Config.get_config()
173197

api/src/project/services/project_service.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from uuid import UUID
2-
from typing import Set
32
from typing import List
43
from sqlalchemy.orm import Session
54

65
from src.db.models import Project
76
from src.project.repositories.project_repository import ProjectRepository
7+
from src.workspace.repositories.workspace_repository import WorkspaceRepository
88

99

1010
class ProjectService:
@@ -14,6 +14,7 @@ class ProjectService:
1414

1515
def __init__(self):
1616
self.repository = ProjectRepository()
17+
self.workspace_repository = WorkspaceRepository()
1718

1819
def create_project(
1920
self, db_session: Session, name: str, user_id: UUID, workspace_id: UUID
@@ -30,6 +31,14 @@ def create_project(
3031
Returns:
3132
Project: The created project instance.
3233
"""
34+
if name.strip() == "":
35+
raise Exception("Name is required")
36+
37+
workspace = self.workspace_repository.get_by_id(
38+
db_session, workspace_id, user_id)
39+
if not workspace:
40+
raise Exception("Workspace not found or not owned by user")
41+
3342
project = Project(name=name, user_id=user_id,
3443
workspace_id=workspace_id)
3544
return self.repository.create(db_session, project)
@@ -84,6 +93,13 @@ def update_project(
8493
Returns:
8594
Project: The updated project instance.
8695
"""
96+
if data["name"].strip() == "":
97+
raise Exception("Name is required")
98+
99+
workspace = self.workspace_repository.get_by_id(
100+
db_session, data["workspace_id"], user_id)
101+
if not workspace:
102+
raise Exception("Workspace not found or not owned by user")
87103
return self.repository.update(db_session, project_id, data, user_id)
88104

89105
def delete_project(
@@ -100,4 +116,4 @@ def delete_project(
100116
Returns:
101117
None
102118
"""
103-
self.repository.delete(db_session, project_id, user_id)
119+
self.repository.delete(db_session, project_id, user_id)

api/src/workspace/services/workspace_service.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ def create_workspace(
2828
Returns:
2929
Workspace: The created Workspace instance.
3030
"""
31+
if name.strip() == "":
32+
raise Exception("Name is required")
33+
3134
workspace = Workspace(name=name, user_id=user_id)
3235
return self.repository.create(db_session, workspace)
3336

@@ -97,6 +100,9 @@ def update_workspace(
97100
Returns:
98101
Workspace: The updated Workspace instance.
99102
"""
103+
if data["name"].strip() == "":
104+
raise Exception("Name is required")
105+
100106
return self.repository.update(db_session, workspace_id, data, user_id)
101107

102108
def delete_workspace(

0 commit comments

Comments
 (0)