fixes
This commit is contained in:
parent
7051a6e35f
commit
1ce125ac75
4 changed files with 37 additions and 38 deletions
|
|
@ -501,25 +501,25 @@ class AutomationObjects:
|
||||||
System templates (isSystem=True) are always included (read-only for non-SysAdmin).
|
System templates (isSystem=True) are always included (read-only for non-SysAdmin).
|
||||||
Instance templates (featureInstanceId matches) are included with RBAC filtering.
|
Instance templates (featureInstanceId matches) are included with RBAC filtering.
|
||||||
"""
|
"""
|
||||||
# 1. System templates — always visible to all users
|
# Load ALL templates and filter in Python.
|
||||||
systemTemplates = self.db.getRecordset(
|
# Reason: seeded/legacy templates may have isSystem=NULL (not False/True),
|
||||||
AutomationTemplate,
|
# which breaks SQL equality filters (NULL != True AND NULL != False).
|
||||||
recordFilter={"isSystem": True}
|
allTemplates = self.db.getRecordset(AutomationTemplate)
|
||||||
)
|
|
||||||
|
|
||||||
# 2. Instance templates — scoped to current feature instance, RBAC-filtered
|
filteredTemplates = []
|
||||||
instanceTemplates = []
|
for t in allTemplates:
|
||||||
if self.featureInstanceId:
|
isSystem = t.get("isSystem")
|
||||||
allInstanceTemplates = self.db.getRecordset(
|
fid = t.get("featureInstanceId")
|
||||||
AutomationTemplate,
|
|
||||||
recordFilter={"featureInstanceId": self.featureInstanceId, "isSystem": False}
|
|
||||||
)
|
|
||||||
# Apply RBAC filtering on instance templates
|
|
||||||
for t in allInstanceTemplates:
|
|
||||||
instanceTemplates.append(t)
|
|
||||||
|
|
||||||
# Combine: system first, then instance
|
if isSystem is True:
|
||||||
filteredTemplates = systemTemplates + instanceTemplates
|
# System templates — always visible to all users
|
||||||
|
filteredTemplates.append(t)
|
||||||
|
elif fid and fid == self.featureInstanceId:
|
||||||
|
# Instance templates — scoped to current feature instance
|
||||||
|
filteredTemplates.append(t)
|
||||||
|
elif not fid:
|
||||||
|
# Global/legacy templates (no featureInstanceId) — visible to all users
|
||||||
|
filteredTemplates.append(t)
|
||||||
|
|
||||||
# Enrich with user names
|
# Enrich with user names
|
||||||
self._enrichTemplatesWithUserName(filteredTemplates)
|
self._enrichTemplatesWithUserName(filteredTemplates)
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,7 @@ def initAutomationTemplates(dbApp: DatabaseConnector, adminUserId: Optional[str]
|
||||||
"label": labelDict,
|
"label": labelDict,
|
||||||
"overview": overviewDict,
|
"overview": overviewDict,
|
||||||
"template": json.dumps(templateContent), # Store entire template JSON
|
"template": json.dumps(templateContent), # Store entire template JSON
|
||||||
|
"isSystem": True, # Seeded templates are system-level, visible to all users
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -1242,27 +1242,23 @@ class ChatObjects:
|
||||||
if not self.checkRbacPermission(ChatWorkflow, "update", workflowId):
|
if not self.checkRbacPermission(ChatWorkflow, "update", workflowId):
|
||||||
raise PermissionError(f"No permission to modify workflow {workflowId}")
|
raise PermissionError(f"No permission to modify workflow {workflowId}")
|
||||||
|
|
||||||
# Check if the message exists
|
# Check if the message exists (bypass RBAC -- workflow access already verified above)
|
||||||
messages = self.getMessages(workflowId)
|
matchingMessages = self.db.getRecordset(ChatMessage, recordFilter={"id": messageId, "workflowId": workflowId})
|
||||||
message = next((m for m in messages if m.get("id") == messageId), None)
|
|
||||||
|
|
||||||
if not message:
|
if not matchingMessages:
|
||||||
logger.warning(f"Message {messageId} for workflow {workflowId} not found")
|
logger.warning(f"Message {messageId} for workflow {workflowId} not found")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# CASCADE DELETE: Delete all related data first
|
# CASCADE DELETE: Delete all related data first
|
||||||
|
|
||||||
# 1. Delete message stats
|
# 1. Delete message documents (but NOT the files themselves)
|
||||||
existing_stats = self._getRecordset(ChatStat, recordFilter={"messageId": messageId})
|
# Bypass RBAC -- workflow access already verified, child records may have different _createdBy
|
||||||
for stat in existing_stats:
|
existing_docs = self.db.getRecordset(ChatDocument, recordFilter={"messageId": messageId})
|
||||||
self.db.recordDelete(ChatStat, stat["id"])
|
|
||||||
|
|
||||||
# 2. Delete message documents (but NOT the files!)
|
|
||||||
existing_docs = self._getRecordset(ChatDocument, recordFilter={"messageId": messageId})
|
|
||||||
for doc in existing_docs:
|
for doc in existing_docs:
|
||||||
self.db.recordDelete(ChatDocument, doc["id"])
|
self.db.recordDelete(ChatDocument, doc["id"])
|
||||||
|
|
||||||
# 3. Finally delete the message itself
|
# 2. Finally delete the message itself
|
||||||
|
# Note: ChatStat has no messageId field -- stats are workflow-level, not message-level
|
||||||
success = self.db.recordDelete(ChatMessage, messageId)
|
success = self.db.recordDelete(ChatMessage, messageId)
|
||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
@ -1285,11 +1281,14 @@ class ChatObjects:
|
||||||
|
|
||||||
|
|
||||||
# Get documents for this message from normalized table
|
# Get documents for this message from normalized table
|
||||||
documents = self._getRecordset(ChatDocument, recordFilter={"messageId": messageId})
|
# Bypass RBAC -- workflow access already verified, child records may have different _createdBy
|
||||||
|
documents = self.db.getRecordset(ChatDocument, recordFilter={"messageId": messageId})
|
||||||
|
|
||||||
if not documents:
|
if not documents:
|
||||||
logger.warning(f"No documents found for message {messageId}")
|
# No ChatDocument records -- documents may be stored inline on the message (legacy).
|
||||||
return False
|
# The frontend handles removal optimistically, file itself is preserved.
|
||||||
|
logger.debug(f"No ChatDocument records for message {messageId} -- inline/legacy data, nothing to delete")
|
||||||
|
return True
|
||||||
|
|
||||||
# Find and delete the specific document
|
# Find and delete the specific document
|
||||||
removed = False
|
removed = False
|
||||||
|
|
@ -1317,6 +1316,8 @@ class ChatObjects:
|
||||||
logger.warning(f"No matching file {fileId} found in message {messageId}")
|
logger.warning(f"No matching file {fileId} found in message {messageId}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error removing file {fileId} from message {messageId}: {str(e)}")
|
logger.error(f"Error removing file {fileId} from message {messageId}: {str(e)}")
|
||||||
return False
|
return False
|
||||||
|
|
|
||||||
|
|
@ -549,11 +549,8 @@ def delete_workflow_message(
|
||||||
detail=f"Message with ID {messageId} not found in workflow {workflowId}"
|
detail=f"Message with ID {messageId} not found in workflow {workflowId}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Update workflow's messageIds
|
# Messages are stored in ChatMessage table linked by workflowId --
|
||||||
messageIds = workflow.get("messageIds", [])
|
# no messageIds list on ChatWorkflow to update.
|
||||||
if messageId in messageIds:
|
|
||||||
messageIds.remove(messageId)
|
|
||||||
interfaceDbChat.updateWorkflow(workflowId, {"messageIds": messageIds})
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"workflowId": workflowId,
|
"workflowId": workflowId,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue