# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ Interface for Workspace feature — manages WorkspaceUserSettings. Uses a dedicated poweron_workspace database. """ import logging from typing import Dict, Any, Optional from modules.connectors.connectorDbPostgre import DatabaseConnector from modules.datamodels.datamodelUam import User from modules.features.workspace.datamodelFeatureWorkspace import WorkspaceUserSettings from modules.interfaces.interfaceRbac import getRecordsetWithRBAC from modules.security.rbac import RbacClass from modules.shared.configuration import APP_CONFIG logger = logging.getLogger(__name__) _workspaceInterfaces: Dict[str, "WorkspaceObjects"] = {} class WorkspaceObjects: """Interface for Workspace-specific database operations (voice + general settings).""" def __init__(self, currentUser: User, mandateId: Optional[str] = None, featureInstanceId: Optional[str] = None): self.currentUser = currentUser self.mandateId = mandateId self.featureInstanceId = featureInstanceId self.userId = currentUser.id if currentUser else None self._initializeDatabase() from modules.security.rootAccess import getRootDbAppConnector dbApp = getRootDbAppConnector() self.rbac = RbacClass(self.db, dbApp=dbApp) self.db.updateContext(self.userId) def _initializeDatabase(self): dbHost = APP_CONFIG.get("DB_HOST", "_no_config_default_data") dbDatabase = "poweron_workspace" dbUser = APP_CONFIG.get("DB_USER") dbPassword = APP_CONFIG.get("DB_PASSWORD_SECRET") dbPort = int(APP_CONFIG.get("DB_PORT", 5432)) self.db = DatabaseConnector( dbHost=dbHost, dbDatabase=dbDatabase, dbUser=dbUser, dbPassword=dbPassword, dbPort=dbPort, userId=self.userId, ) logger.debug(f"Workspace database initialized for user {self.userId}") def setUserContext(self, currentUser: User, mandateId: Optional[str] = None, featureInstanceId: Optional[str] = None): self.currentUser = currentUser self.userId = currentUser.id if currentUser else None self.mandateId = mandateId self.featureInstanceId = featureInstanceId self.db.updateContext(self.userId) # ========================================================================= # WorkspaceUserSettings CRUD # ========================================================================= def getWorkspaceUserSettings(self, userId: Optional[str] = None) -> Optional[WorkspaceUserSettings]: targetUserId = userId or self.userId if not targetUserId: return None try: recordFilter: Dict[str, Any] = {"userId": targetUserId} if self.featureInstanceId: recordFilter["featureInstanceId"] = self.featureInstanceId records = getRecordsetWithRBAC( self.db, WorkspaceUserSettings, self.currentUser, recordFilter=recordFilter, mandateId=self.mandateId, ) if not records: return None return WorkspaceUserSettings(**records[0]) except Exception as e: logger.error(f"Error getting workspace user settings: {e}") return None def saveWorkspaceUserSettings(self, data: Dict[str, Any]) -> WorkspaceUserSettings: """Upsert: create or update workspace user settings for the current user.""" targetUserId = data.get("userId", self.userId) if not targetUserId: raise ValueError("No user ID provided") existing = self.getWorkspaceUserSettings(targetUserId) if existing: updateData = {k: v for k, v in data.items() if k not in ("id", "userId", "mandateId", "featureInstanceId")} self.db.recordModify(WorkspaceUserSettings, existing.id, updateData) updated = self.getWorkspaceUserSettings(targetUserId) if not updated: raise ValueError("Failed to retrieve updated workspace user settings") return updated createData = { "userId": targetUserId, "mandateId": data.get("mandateId", self.mandateId), "featureInstanceId": data.get("featureInstanceId", self.featureInstanceId), } createData.update({k: v for k, v in data.items() if k not in ("id", "userId", "mandateId", "featureInstanceId")}) createdRecord = self.db.recordCreate(WorkspaceUserSettings, createData) if not createdRecord or not createdRecord.get("id"): raise ValueError("Failed to create workspace user settings") return WorkspaceUserSettings(**createdRecord) def getInterface(currentUser: Optional[User] = None, mandateId: Optional[str] = None, featureInstanceId: Optional[str] = None) -> WorkspaceObjects: if not currentUser: raise ValueError("Invalid user context: user is required") effectiveMandateId = str(mandateId) if mandateId else None effectiveFeatureInstanceId = str(featureInstanceId) if featureInstanceId else None contextKey = f"workspace_{effectiveMandateId}_{effectiveFeatureInstanceId}_{currentUser.id}" if contextKey not in _workspaceInterfaces: _workspaceInterfaces[contextKey] = WorkspaceObjects(currentUser, mandateId=effectiveMandateId, featureInstanceId=effectiveFeatureInstanceId) else: _workspaceInterfaces[contextKey].setUserContext(currentUser, mandateId=effectiveMandateId, featureInstanceId=effectiveFeatureInstanceId) return _workspaceInterfaces[contextKey]