prod azure 1.0.6
This commit is contained in:
parent
4c1d81160e
commit
ff85bc0398
8 changed files with 2336 additions and 752 deletions
|
|
@ -8,22 +8,10 @@ logger = logging.getLogger(__name__)
|
||||||
class DatabaseConnector:
|
class DatabaseConnector:
|
||||||
"""
|
"""
|
||||||
A connector for JSON-based data storage.
|
A connector for JSON-based data storage.
|
||||||
Provides generic database operations with tenant and user context support.
|
Provides generic database operations without user/mandate filtering.
|
||||||
"""
|
"""
|
||||||
def __init__(self, dbHost: str, dbDatabase: str, dbUser: str = None, dbPassword: str = None,
|
def __init__(self, dbHost: str, dbDatabase: str, dbUser: str = None, dbPassword: str = None,
|
||||||
mandateId: int = None, userId: int = None, skipInitialIdLookup: bool = False):
|
mandateId: int = None, userId: int = None, skipInitialIdLookup: bool = False):
|
||||||
"""
|
|
||||||
Initializes the JSON database connector.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
dbHost: Directory for the JSON files
|
|
||||||
dbDatabase: Database name
|
|
||||||
dbUser: Username for authentication (optional)
|
|
||||||
dbPassword: API key for authentication (optional)
|
|
||||||
mandateId: Context parameter for the tenant
|
|
||||||
userId: Context parameter for the user
|
|
||||||
skipInitialIdLookup: When True, skips looking up initial IDs for mandateId and userId
|
|
||||||
"""
|
|
||||||
# Store the input parameters
|
# Store the input parameters
|
||||||
self.dbHost = dbHost
|
self.dbHost = dbHost
|
||||||
self.dbDatabase = dbDatabase
|
self.dbDatabase = dbDatabase
|
||||||
|
|
@ -177,35 +165,6 @@ class DatabaseConnector:
|
||||||
logger.error(f"Error saving table {table}: {e}")
|
logger.error(f"Error saving table {table}: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _filterByContext(self, records: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
||||||
"""
|
|
||||||
Filters records by tenant and user context,
|
|
||||||
if these fields exist in the record.
|
|
||||||
"""
|
|
||||||
filteredRecords = []
|
|
||||||
|
|
||||||
for record in records:
|
|
||||||
# Check if mandateId exists in the record and is not null
|
|
||||||
hasMandate = "mandateId" in record and record["mandateId"] is not None and record["mandateId"] != ""
|
|
||||||
|
|
||||||
# Check if userId exists in the record and is not null
|
|
||||||
hasUser = "userId" in record and record["userId"] is not None and record["userId"] != ""
|
|
||||||
|
|
||||||
# If both exist, filter accordingly
|
|
||||||
if hasMandate and hasUser:
|
|
||||||
if record["mandateId"] == self.mandateId:
|
|
||||||
filteredRecords.append(record)
|
|
||||||
# If only mandateId exists
|
|
||||||
elif hasMandate and not hasUser:
|
|
||||||
if record["mandateId"] == self.mandateId:
|
|
||||||
filteredRecords.append(record)
|
|
||||||
# If neither mandateId nor userId exist, add the record
|
|
||||||
elif not hasMandate and not hasUser:
|
|
||||||
filteredRecords.append(record)
|
|
||||||
|
|
||||||
return filteredRecords
|
|
||||||
|
|
||||||
|
|
||||||
def _applyRecordFilter(self, records: List[Dict[str, Any]], recordFilter: Dict[str, Any] = None) -> List[Dict[str, Any]]:
|
def _applyRecordFilter(self, records: List[Dict[str, Any]], recordFilter: Dict[str, Any] = None) -> List[Dict[str, Any]]:
|
||||||
"""Applies a record filter to the records"""
|
"""Applies a record filter to the records"""
|
||||||
if not recordFilter:
|
if not recordFilter:
|
||||||
|
|
@ -244,21 +203,10 @@ class DatabaseConnector:
|
||||||
return filteredRecords
|
return filteredRecords
|
||||||
|
|
||||||
def _registerInitialId(self, table: str, initialId: int) -> bool:
|
def _registerInitialId(self, table: str, initialId: int) -> bool:
|
||||||
"""
|
"""Registers the initial ID for a table."""
|
||||||
Registers the initial ID for a table.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
table: Name of the table
|
|
||||||
initialId: The initial ID
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True on success, False on error
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
# Load the current system table
|
|
||||||
systemData = self._loadSystemTable()
|
systemData = self._loadSystemTable()
|
||||||
|
|
||||||
# Only register if not already present
|
|
||||||
if table not in systemData:
|
if table not in systemData:
|
||||||
systemData[table] = initialId
|
systemData[table] = initialId
|
||||||
success = self._saveSystemTable(systemData)
|
success = self._saveSystemTable(systemData)
|
||||||
|
|
@ -271,20 +219,10 @@ class DatabaseConnector:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _removeInitialId(self, table: str) -> bool:
|
def _removeInitialId(self, table: str) -> bool:
|
||||||
"""
|
"""Removes the initial ID for a table from the system table."""
|
||||||
Removes the initial ID for a table from the system table.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
table: Name of the table
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True on success, False on error
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
# Load the current system table
|
|
||||||
systemData = self._loadSystemTable()
|
systemData = self._loadSystemTable()
|
||||||
|
|
||||||
# Remove the entry if it exists
|
|
||||||
if table in systemData:
|
if table in systemData:
|
||||||
del systemData[table]
|
del systemData[table]
|
||||||
success = self._saveSystemTable(systemData)
|
success = self._saveSystemTable(systemData)
|
||||||
|
|
@ -299,12 +237,7 @@ class DatabaseConnector:
|
||||||
# Public API
|
# Public API
|
||||||
|
|
||||||
def getTables(self) -> List[str]:
|
def getTables(self) -> List[str]:
|
||||||
"""
|
"""Returns a list of all available tables."""
|
||||||
Returns a list of all available tables.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List of table names
|
|
||||||
"""
|
|
||||||
tables = []
|
tables = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -318,38 +251,18 @@ class DatabaseConnector:
|
||||||
return tables
|
return tables
|
||||||
|
|
||||||
def getFields(self, table: str) -> List[str]:
|
def getFields(self, table: str) -> List[str]:
|
||||||
"""
|
"""Returns a list of all fields in a table."""
|
||||||
Returns a list of all fields in a table.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
table: Name of the table
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List of field names
|
|
||||||
"""
|
|
||||||
# Load the table data
|
|
||||||
data = self._loadTable(table)
|
data = self._loadTable(table)
|
||||||
|
|
||||||
if not data:
|
if not data:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# Take the first record as a reference for the fields
|
|
||||||
fields = list(data[0].keys()) if data else []
|
fields = list(data[0].keys()) if data else []
|
||||||
|
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
def getSchema(self, table: str, language: str = None) -> Dict[str, Dict[str, Any]]:
|
def getSchema(self, table: str, language: str = None) -> Dict[str, Dict[str, Any]]:
|
||||||
"""
|
"""Returns a schema object for a table with data types and labels."""
|
||||||
Returns a schema object for a table with data types and labels.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
table: Name of the table
|
|
||||||
language: Language for the labels (optional)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Schema object with fields, data types and labels
|
|
||||||
"""
|
|
||||||
# Load the table data
|
|
||||||
data = self._loadTable(table)
|
data = self._loadTable(table)
|
||||||
|
|
||||||
schema = {}
|
schema = {}
|
||||||
|
|
@ -357,14 +270,10 @@ class DatabaseConnector:
|
||||||
if not data:
|
if not data:
|
||||||
return schema
|
return schema
|
||||||
|
|
||||||
# Take the first record as a reference for the fields and data types
|
|
||||||
firstRecord = data[0]
|
firstRecord = data[0]
|
||||||
|
|
||||||
for field, value in firstRecord.items():
|
for field, value in firstRecord.items():
|
||||||
# Determine the data type
|
|
||||||
dataType = type(value).__name__
|
dataType = type(value).__name__
|
||||||
|
|
||||||
# Create label (default is the field name)
|
|
||||||
label = field
|
label = field
|
||||||
|
|
||||||
schema[field] = {
|
schema[field] = {
|
||||||
|
|
@ -375,32 +284,18 @@ class DatabaseConnector:
|
||||||
return schema
|
return schema
|
||||||
|
|
||||||
def getRecordset(self, table: str, fieldFilter: List[str] = None, recordFilter: Dict[str, Any] = None) -> List[Dict[str, Any]]:
|
def getRecordset(self, table: str, fieldFilter: List[str] = None, recordFilter: Dict[str, Any] = None) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""Returns a list of records from a table, filtered by criteria."""
|
||||||
Returns a list of records from a table, filtered by criteria.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
table: Name of the table
|
|
||||||
fieldFilter: Filter for fields (which fields should be returned)
|
|
||||||
recordFilter: Filter for records (which records should be returned)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List of filtered records
|
|
||||||
"""
|
|
||||||
# Load the table data
|
|
||||||
data = self._loadTable(table)
|
data = self._loadTable(table)
|
||||||
logger.debug(f"getRecordset: data volume of {len(data)} bytes")
|
logger.debug(f"getRecordset: data volume of {len(data)} records")
|
||||||
|
|
||||||
# Filter by tenant and user context
|
|
||||||
filteredData = self._filterByContext(data)
|
|
||||||
|
|
||||||
# Apply recordFilter if available
|
# Apply recordFilter if available
|
||||||
if recordFilter:
|
if recordFilter:
|
||||||
filteredData = self._applyRecordFilter(filteredData, recordFilter)
|
data = self._applyRecordFilter(data, recordFilter)
|
||||||
|
|
||||||
# If fieldFilter is available, reduce the fields
|
# If fieldFilter is available, reduce the fields
|
||||||
if fieldFilter and isinstance(fieldFilter, list):
|
if fieldFilter and isinstance(fieldFilter, list):
|
||||||
result = []
|
result = []
|
||||||
for record in filteredData:
|
for record in data:
|
||||||
filteredRecord = {}
|
filteredRecord = {}
|
||||||
for field in fieldFilter:
|
for field in fieldFilter:
|
||||||
if field in record:
|
if field in record:
|
||||||
|
|
@ -408,23 +303,13 @@ class DatabaseConnector:
|
||||||
result.append(filteredRecord)
|
result.append(filteredRecord)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return filteredData
|
return data
|
||||||
|
|
||||||
def recordCreate(self, table: str, recordData: Dict[str, Any]) -> Dict[str, Any]:
|
def recordCreate(self, table: str, recordData: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
"""
|
"""Creates a new record in the table."""
|
||||||
Creates a new record in the table.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
table: Name of the table
|
|
||||||
recordData: Data for the new record
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The created record
|
|
||||||
"""
|
|
||||||
# Load the table data
|
|
||||||
data = self._loadTable(table)
|
data = self._loadTable(table)
|
||||||
|
|
||||||
# Add mandateId and userId if not present or 0
|
# Add mandateId and userId if not present
|
||||||
if "mandateId" not in recordData or recordData["mandateId"] == 0:
|
if "mandateId" not in recordData or recordData["mandateId"] == 0:
|
||||||
recordData["mandateId"] = self.mandateId
|
recordData["mandateId"] = self.mandateId
|
||||||
|
|
||||||
|
|
@ -453,30 +338,15 @@ class DatabaseConnector:
|
||||||
raise ValueError(f"Error creating the record in table {table}")
|
raise ValueError(f"Error creating the record in table {table}")
|
||||||
|
|
||||||
def recordDelete(self, table: str, recordId: Union[str, int]) -> bool:
|
def recordDelete(self, table: str, recordId: Union[str, int]) -> bool:
|
||||||
"""
|
"""Deletes a record from the table."""
|
||||||
Deletes a record from the table.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
table: Name of the table
|
|
||||||
recordId: ID of the record to delete
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True on success, False on error
|
|
||||||
"""
|
|
||||||
# Load table data
|
|
||||||
data = self._loadTable(table)
|
data = self._loadTable(table)
|
||||||
|
|
||||||
# Search for the record
|
# Search for the record
|
||||||
for i, record in enumerate(data):
|
for i, record in enumerate(data):
|
||||||
if "id" in record and record["id"] == recordId:
|
if "id" in record and record["id"] == recordId:
|
||||||
# Check if the record belongs to the current mandate
|
|
||||||
if "mandateId" in record and record["mandateId"] != self.mandateId:
|
|
||||||
raise ValueError("Not your mandate")
|
|
||||||
|
|
||||||
# Check if it's an initial record
|
# Check if it's an initial record
|
||||||
initialId = self.getInitialId(table)
|
initialId = self.getInitialId(table)
|
||||||
if initialId is not None and initialId == recordId:
|
if initialId is not None and initialId == recordId:
|
||||||
# Remove this entry from the system table
|
|
||||||
self._removeInitialId(table)
|
self._removeInitialId(table)
|
||||||
logger.info(f"Initial ID {recordId} for table {table} has been removed from the system table")
|
logger.info(f"Initial ID {recordId} for table {table} has been removed from the system table")
|
||||||
|
|
||||||
|
|
@ -490,27 +360,12 @@ class DatabaseConnector:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def recordModify(self, table: str, recordId: Union[str, int], recordData: Dict[str, Any]) -> Dict[str, Any]:
|
def recordModify(self, table: str, recordId: Union[str, int], recordData: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
"""
|
"""Modifies a record in the table."""
|
||||||
Modifies a record in the table.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
table: Name of the table
|
|
||||||
recordId: ID of the record to modify
|
|
||||||
recordData: New data for the record
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The updated record
|
|
||||||
"""
|
|
||||||
# Load table data
|
|
||||||
data = self._loadTable(table)
|
data = self._loadTable(table)
|
||||||
|
|
||||||
# Search for the record
|
# Search for the record
|
||||||
for i, record in enumerate(data):
|
for i, record in enumerate(data):
|
||||||
if "id" in record and record["id"] == recordId:
|
if "id" in record and record["id"] == recordId:
|
||||||
# Check if the record belongs to the current mandate
|
|
||||||
if "mandateId" in record and record["mandateId"] != self.mandateId:
|
|
||||||
raise ValueError("Not your mandate")
|
|
||||||
|
|
||||||
# Prevent changing the ID
|
# Prevent changing the ID
|
||||||
if "id" in recordData and recordData["id"] != recordId:
|
if "id" in recordData and recordData["id"] != recordId:
|
||||||
raise ValueError(f"The ID of a record in table {table} cannot be changed")
|
raise ValueError(f"The ID of a record in table {table} cannot be changed")
|
||||||
|
|
@ -529,28 +384,12 @@ class DatabaseConnector:
|
||||||
raise ValueError(f"Record with ID {recordId} not found in table {table}")
|
raise ValueError(f"Record with ID {recordId} not found in table {table}")
|
||||||
|
|
||||||
def hasInitialId(self, table: str) -> bool:
|
def hasInitialId(self, table: str) -> bool:
|
||||||
"""
|
"""Checks if an initial ID is registered for a table."""
|
||||||
Checks if an initial ID is registered for a table.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
table: Name of the table
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True if an initial ID is registered, otherwise False
|
|
||||||
"""
|
|
||||||
systemData = self._loadSystemTable()
|
systemData = self._loadSystemTable()
|
||||||
return table in systemData
|
return table in systemData
|
||||||
|
|
||||||
def getInitialId(self, table: str) -> Optional[int]:
|
def getInitialId(self, table: str) -> Optional[int]:
|
||||||
"""
|
"""Returns the initial ID for a table."""
|
||||||
Returns the initial ID for a table.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
table: Name of the table
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The initial ID or None if not present
|
|
||||||
"""
|
|
||||||
systemData = self._loadSystemTable()
|
systemData = self._loadSystemTable()
|
||||||
initialId = systemData.get(table)
|
initialId = systemData.get(table)
|
||||||
logger.debug(f"Database '{self.dbDatabase}': Initial ID for table '{table}' is {initialId}")
|
logger.debug(f"Database '{self.dbDatabase}': Initial ID for table '{table}' is {initialId}")
|
||||||
|
|
@ -559,11 +398,6 @@ class DatabaseConnector:
|
||||||
return initialId
|
return initialId
|
||||||
|
|
||||||
def getAllInitialIds(self) -> Dict[str, int]:
|
def getAllInitialIds(self) -> Dict[str, int]:
|
||||||
"""
|
"""Returns all registered initial IDs."""
|
||||||
Returns all registered initial IDs.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Dictionary with table names as keys and initial IDs as values
|
|
||||||
"""
|
|
||||||
systemData = self._loadSystemTable()
|
systemData = self._loadSystemTable()
|
||||||
return systemData.copy() # Return a copy to protect the original
|
return systemData.copy() # Return a copy to protect the original
|
||||||
1343
modules/BACKUP-lucydomInterface.py
Normal file
1343
modules/BACKUP-lucydomInterface.py
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -25,13 +25,7 @@ class GatewayInterface:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, mandateId: int = None, userId: int = None):
|
def __init__(self, mandateId: int = None, userId: int = None):
|
||||||
"""
|
"""Initializes the Gateway Interface with optional mandate and user context."""
|
||||||
Initializes the Gateway Interface with optional mandate and user context.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
mandateId: ID of the current mandate (optional)
|
|
||||||
userId: ID of the current user (optional)
|
|
||||||
"""
|
|
||||||
# Context can be empty during initialization
|
# Context can be empty during initialization
|
||||||
self.mandateId = mandateId
|
self.mandateId = mandateId
|
||||||
self.userId = userId
|
self.userId = userId
|
||||||
|
|
@ -46,12 +40,35 @@ class GatewayInterface:
|
||||||
|
|
||||||
# Initialize database
|
# Initialize database
|
||||||
self._initializeDatabase()
|
self._initializeDatabase()
|
||||||
|
|
||||||
|
# Load user information
|
||||||
|
self.currentUser = self._getCurrentUserInfo()
|
||||||
|
|
||||||
|
# Initialize standard records if needed
|
||||||
|
self._initRecords()
|
||||||
|
|
||||||
|
def _getCurrentUserInfo(self) -> Dict[str, Any]:
|
||||||
|
"""Gets information about the current user including privileges."""
|
||||||
|
# For initialization, set default values
|
||||||
|
userInfo = {
|
||||||
|
"id": self.userId,
|
||||||
|
"mandateId": self.mandateId,
|
||||||
|
"privilege": "user", # Default privilege level
|
||||||
|
"language": "en"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Try to load actual user info if IDs are provided
|
||||||
|
if self.userId:
|
||||||
|
userRecords = self.db.getRecordset("users", recordFilter={"id": self.userId})
|
||||||
|
if userRecords:
|
||||||
|
user = userRecords[0]
|
||||||
|
userInfo["privilege"] = user.get("privilege", "user")
|
||||||
|
userInfo["language"] = user.get("language", "en")
|
||||||
|
|
||||||
|
return userInfo
|
||||||
|
|
||||||
def _initializeDatabase(self):
|
def _initializeDatabase(self):
|
||||||
"""
|
"""Initializes the database connection."""
|
||||||
Initializes the database with minimal objects
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.db = DatabaseConnector(
|
self.db = DatabaseConnector(
|
||||||
dbHost=APP_CONFIG.get("DB_SYSTEM_HOST"),
|
dbHost=APP_CONFIG.get("DB_SYSTEM_HOST"),
|
||||||
dbDatabase=APP_CONFIG.get("DB_SYSTEM_DATABASE"),
|
dbDatabase=APP_CONFIG.get("DB_SYSTEM_DATABASE"),
|
||||||
|
|
@ -61,7 +78,13 @@ class GatewayInterface:
|
||||||
userId=self.userId if self.userId else 0
|
userId=self.userId if self.userId else 0
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create Root mandate if needed
|
def _initRecords(self):
|
||||||
|
"""Initializes standard records in the database if they don't exist."""
|
||||||
|
self._initRootMandate()
|
||||||
|
self._initAdminUser()
|
||||||
|
|
||||||
|
def _initRootMandate(self):
|
||||||
|
"""Creates the Root mandate if it doesn't exist."""
|
||||||
existingMandateId = self.getInitialId("mandates")
|
existingMandateId = self.getInitialId("mandates")
|
||||||
mandates = self.db.getRecordset("mandates")
|
mandates = self.db.getRecordset("mandates")
|
||||||
if existingMandateId is None or not mandates:
|
if existingMandateId is None or not mandates:
|
||||||
|
|
@ -75,19 +98,9 @@ class GatewayInterface:
|
||||||
|
|
||||||
# Update mandate context
|
# Update mandate context
|
||||||
self.mandateId = createdMandate['id']
|
self.mandateId = createdMandate['id']
|
||||||
self.userId = createdMandate['userId']
|
|
||||||
|
def _initAdminUser(self):
|
||||||
# Recreate connector with correct context
|
"""Creates the Admin user if it doesn't exist."""
|
||||||
self.db = DatabaseConnector(
|
|
||||||
dbHost=APP_CONFIG.get("DB_SYSTEM_HOST"),
|
|
||||||
dbDatabase=APP_CONFIG.get("DB_SYSTEM_DATABASE"),
|
|
||||||
dbUser=APP_CONFIG.get("DB_SYSTEM_USER"),
|
|
||||||
dbPassword=APP_CONFIG.get("DB_SYSTEM_PASSWORD_SECRET"),
|
|
||||||
mandateId=self.mandateId,
|
|
||||||
userId=self.userId
|
|
||||||
)
|
|
||||||
|
|
||||||
# Create Admin user if needed
|
|
||||||
existingUserId = self.getInitialId("users")
|
existingUserId = self.getInitialId("users")
|
||||||
users = self.db.getRecordset("users")
|
users = self.db.getRecordset("users")
|
||||||
if existingUserId is None or not users:
|
if existingUserId is None or not users:
|
||||||
|
|
@ -99,57 +112,127 @@ class GatewayInterface:
|
||||||
"fullName": "Administrator",
|
"fullName": "Administrator",
|
||||||
"disabled": False,
|
"disabled": False,
|
||||||
"language": "de",
|
"language": "de",
|
||||||
"privilege": "sysadmin", # SysAdmin privilege
|
"privilege": "sysadmin",
|
||||||
"hashedPassword": self._getPasswordHash("admin") # Use a secure password in production!
|
"hashedPassword": self._getPasswordHash("The 1st Poweron Admin") # Use a secure password in production!
|
||||||
}
|
}
|
||||||
createdUser = self.db.recordCreate("users", adminUser)
|
createdUser = self.db.recordCreate("users", adminUser)
|
||||||
logger.info(f"Admin user created with ID {createdUser['id']}")
|
logger.info(f"Admin user created with ID {createdUser['id']}")
|
||||||
|
|
||||||
# Update user context
|
# Update user context
|
||||||
self.userId = createdUser['id']
|
self.userId = createdUser['id']
|
||||||
|
|
||||||
|
def _uam(self, table: str, recordset: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
Unified user access management function that filters data based on user privileges.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table: Name of the table
|
||||||
|
recordset: Recordset to filter based on access rules
|
||||||
|
|
||||||
# Recreate connector with correct context
|
Returns:
|
||||||
self.db = DatabaseConnector(
|
Filtered recordset based on user privilege level
|
||||||
dbHost=APP_CONFIG.get("DB_SYSTEM_HOST"),
|
"""
|
||||||
dbDatabase=APP_CONFIG.get("DB_SYSTEM_DATABASE"),
|
userPrivilege = self.currentUser.get("privilege", "user")
|
||||||
dbUser=APP_CONFIG.get("DB_SYSTEM_USER"),
|
|
||||||
dbPassword=APP_CONFIG.get("DB_SYSTEM_PASSWORD_SECRET"),
|
# Apply filtering based on privilege
|
||||||
mandateId=self.mandateId,
|
if userPrivilege == "sysadmin":
|
||||||
userId=self.userId
|
return recordset # System admins see all records
|
||||||
)
|
elif userPrivilege == "admin":
|
||||||
|
# Admins see records in their mandate
|
||||||
|
return [r for r in recordset if r.get("mandateId") == self.mandateId]
|
||||||
|
else: # Regular users
|
||||||
|
# Users only see records they own within their mandate
|
||||||
|
return [r for r in recordset
|
||||||
|
if r.get("mandateId") == self.mandateId and r.get("userId") == self.userId]
|
||||||
|
|
||||||
|
def _canModify(self, table: str, recordId: Optional[int] = None) -> bool:
|
||||||
|
"""
|
||||||
|
Checks if the current user can modify (create/update/delete) records in a table.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table: Name of the table
|
||||||
|
recordId: Optional record ID for specific record check
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Boolean indicating permission
|
||||||
|
"""
|
||||||
|
userPrivilege = self.currentUser.get("privilege", "user")
|
||||||
|
|
||||||
|
# System admins can modify anything
|
||||||
|
if userPrivilege == "sysadmin":
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Check specific record permissions
|
||||||
|
if recordId is not None:
|
||||||
|
# Get the record to check ownership
|
||||||
|
records = self.db.getRecordset(table, recordFilter={"id": recordId})
|
||||||
|
if not records:
|
||||||
|
return False
|
||||||
|
|
||||||
|
record = records[0]
|
||||||
|
|
||||||
|
# Admins can modify anything in their mandate
|
||||||
|
if userPrivilege == "admin" and record.get("mandateId") == self.mandateId:
|
||||||
|
# Exception: Can't modify Root mandate unless you are a sysadmin
|
||||||
|
if table == "mandates" and recordId == 1 and userPrivilege != "sysadmin":
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Users can only modify their own records
|
||||||
|
if (record.get("mandateId") == self.mandateId and
|
||||||
|
record.get("userId") == self.userId):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# For general table modify permission (e.g., create)
|
||||||
|
# Admins can create anything in their mandate
|
||||||
|
if userPrivilege == "admin":
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Regular users can create most entities
|
||||||
|
if table == "mandates":
|
||||||
|
return False # Regular users can't create mandates
|
||||||
|
return True
|
||||||
|
|
||||||
def getInitialId(self, table: str) -> Optional[int]:
|
def getInitialId(self, table: str) -> Optional[int]:
|
||||||
"""Returns the initial ID for a table"""
|
"""Returns the initial ID for a table."""
|
||||||
return self.db.getInitialId(table)
|
return self.db.getInitialId(table)
|
||||||
|
|
||||||
def _getPasswordHash(self, password: str) -> str:
|
def _getPasswordHash(self, password: str) -> str:
|
||||||
"""Creates a hash for a password"""
|
"""Creates a hash for a password."""
|
||||||
return pwdContext.hash(password)
|
return pwdContext.hash(password)
|
||||||
|
|
||||||
def _verifyPassword(self, plainPassword: str, hashedPassword: str) -> bool:
|
def _verifyPassword(self, plainPassword: str, hashedPassword: str) -> bool:
|
||||||
"""Checks if the password matches the hash"""
|
"""Checks if the password matches the hash."""
|
||||||
return pwdContext.verify(plainPassword, hashedPassword)
|
return pwdContext.verify(plainPassword, hashedPassword)
|
||||||
|
|
||||||
def _getCurrentTimestamp(self) -> str:
|
def _getCurrentTimestamp(self) -> str:
|
||||||
"""Returns the current timestamp in ISO format"""
|
"""Returns the current timestamp in ISO format."""
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
return datetime.now().isoformat()
|
return datetime.now().isoformat()
|
||||||
|
|
||||||
# Mandate methods
|
# Mandate methods
|
||||||
|
|
||||||
def getAllMandates(self) -> List[Dict[str, Any]]:
|
def getAllMandates(self) -> List[Dict[str, Any]]:
|
||||||
"""Returns all mandates"""
|
"""Returns mandates based on user access level."""
|
||||||
return self.db.getRecordset("mandates")
|
allMandates = self.db.getRecordset("mandates")
|
||||||
|
return self._uam("mandates", allMandates)
|
||||||
|
|
||||||
def getMandate(self, mandateId: int) -> Optional[Dict[str, Any]]:
|
def getMandate(self, mandateId: int) -> Optional[Dict[str, Any]]:
|
||||||
"""Returns a mandate by its ID"""
|
"""Returns a mandate by ID if user has access."""
|
||||||
mandates = self.db.getRecordset("mandates", recordFilter={"id": mandateId})
|
mandates = self.db.getRecordset("mandates", recordFilter={"id": mandateId})
|
||||||
if mandates:
|
if not mandates:
|
||||||
return mandates[0]
|
return None
|
||||||
return None
|
|
||||||
|
filteredMandates = self._uam("mandates", mandates)
|
||||||
|
return filteredMandates[0] if filteredMandates else None
|
||||||
|
|
||||||
def createMandate(self, name: str, language: str = "de") -> Dict[str, Any]:
|
def createMandate(self, name: str, language: str = "de") -> Dict[str, Any]:
|
||||||
"""Creates a new mandate"""
|
"""Creates a new mandate if user has permission."""
|
||||||
|
if not self._canModify("mandates"):
|
||||||
|
raise PermissionError("No permission to create mandates")
|
||||||
|
|
||||||
mandateData = {
|
mandateData = {
|
||||||
"name": name,
|
"name": name,
|
||||||
"language": language
|
"language": language
|
||||||
|
|
@ -158,43 +241,29 @@ class GatewayInterface:
|
||||||
return self.db.recordCreate("mandates", mandateData)
|
return self.db.recordCreate("mandates", mandateData)
|
||||||
|
|
||||||
def updateMandate(self, mandateId: int, mandateData: Dict[str, Any]) -> Dict[str, Any]:
|
def updateMandate(self, mandateId: int, mandateData: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
"""
|
"""Updates a mandate if user has access."""
|
||||||
Updates an existing mandate
|
# Check if the mandate exists and user has access
|
||||||
|
|
||||||
Args:
|
|
||||||
mandateId: The ID of the mandate to update
|
|
||||||
mandateData: The mandate data to update
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Dict[str, Any]: The updated mandate data
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: If the mandate is not found
|
|
||||||
"""
|
|
||||||
# Check if the mandate exists
|
|
||||||
mandate = self.getMandate(mandateId)
|
mandate = self.getMandate(mandateId)
|
||||||
if not mandate:
|
if not mandate:
|
||||||
raise ValueError(f"Mandate with ID {mandateId} not found")
|
raise ValueError(f"Mandate with ID {mandateId} not found")
|
||||||
|
|
||||||
|
if not self._canModify("mandates", mandateId):
|
||||||
|
raise PermissionError(f"No permission to update mandate {mandateId}")
|
||||||
|
|
||||||
# Update the mandate
|
# Update the mandate
|
||||||
updatedMandate = self.db.recordModify("mandates", mandateId, mandateData)
|
return self.db.recordModify("mandates", mandateId, mandateData)
|
||||||
|
|
||||||
return updatedMandate
|
|
||||||
|
|
||||||
def deleteMandate(self, mandateId: int) -> bool:
|
def deleteMandate(self, mandateId: int) -> bool:
|
||||||
"""
|
"""
|
||||||
Deletes a mandate and all associated users and data
|
Deletes a mandate and all associated users and data if user has permission.
|
||||||
|
|
||||||
Args:
|
|
||||||
mandateId: The ID of the mandate to delete
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: True if the mandate was successfully deleted, otherwise False
|
|
||||||
"""
|
"""
|
||||||
# Check if the mandate exists
|
# Check if the mandate exists and user has access
|
||||||
mandate = self.getMandate(mandateId)
|
mandate = self.getMandate(mandateId)
|
||||||
if not mandate:
|
if not mandate:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if not self._canModify("mandates", mandateId):
|
||||||
|
raise PermissionError(f"No permission to delete mandate {mandateId}")
|
||||||
|
|
||||||
# Check if it's the initial mandate
|
# Check if it's the initial mandate
|
||||||
initialMandateId = self.getInitialId("mandates")
|
initialMandateId = self.getInitialId("mandates")
|
||||||
|
|
@ -222,33 +291,37 @@ class GatewayInterface:
|
||||||
# User methods
|
# User methods
|
||||||
|
|
||||||
def getAllUsers(self) -> List[Dict[str, Any]]:
|
def getAllUsers(self) -> List[Dict[str, Any]]:
|
||||||
"""Returns all users"""
|
"""Returns users based on user access level."""
|
||||||
users = self.db.getRecordset("users")
|
allUsers = self.db.getRecordset("users")
|
||||||
# Remove password hashes from the response
|
filteredUsers = self._uam("users", allUsers)
|
||||||
for user in users:
|
|
||||||
|
# Remove password hashes
|
||||||
|
for user in filteredUsers:
|
||||||
if "hashedPassword" in user:
|
if "hashedPassword" in user:
|
||||||
del user["hashedPassword"]
|
del user["hashedPassword"]
|
||||||
return users
|
|
||||||
|
return filteredUsers
|
||||||
|
|
||||||
def getUsersByMandate(self, mandateId: int) -> List[Dict[str, Any]]:
|
def getUsersByMandate(self, mandateId: int) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""Returns users for a specific mandate if user has access."""
|
||||||
Returns all users of a specific mandate
|
# First check if user has access to the mandate
|
||||||
|
mandate = self.getMandate(mandateId)
|
||||||
Args:
|
if not mandate:
|
||||||
mandateId: The ID of the mandate
|
return []
|
||||||
|
|
||||||
Returns:
|
# Get users for this mandate
|
||||||
List[Dict[str, Any]]: List of users in the mandate
|
|
||||||
"""
|
|
||||||
users = self.db.getRecordset("users", recordFilter={"mandateId": mandateId})
|
users = self.db.getRecordset("users", recordFilter={"mandateId": mandateId})
|
||||||
# Remove password hashes from the response
|
filteredUsers = self._uam("users", users)
|
||||||
for user in users:
|
|
||||||
|
# Remove password hashes
|
||||||
|
for user in filteredUsers:
|
||||||
if "hashedPassword" in user:
|
if "hashedPassword" in user:
|
||||||
del user["hashedPassword"]
|
del user["hashedPassword"]
|
||||||
return users
|
|
||||||
|
return filteredUsers
|
||||||
|
|
||||||
def getUserByUsername(self, username: str) -> Optional[Dict[str, Any]]:
|
def getUserByUsername(self, username: str) -> Optional[Dict[str, Any]]:
|
||||||
"""Returns a user by username"""
|
"""Returns a user by username."""
|
||||||
users = self.db.getRecordset("users")
|
users = self.db.getRecordset("users")
|
||||||
for user in users:
|
for user in users:
|
||||||
if user.get("username") == username:
|
if user.get("username") == username:
|
||||||
|
|
@ -256,48 +329,49 @@ class GatewayInterface:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getUser(self, userId: int) -> Optional[Dict[str, Any]]:
|
def getUser(self, userId: int) -> Optional[Dict[str, Any]]:
|
||||||
"""Returns a user by ID"""
|
"""Returns a user by ID if user has access."""
|
||||||
users = self.db.getRecordset("users", recordFilter={"id": userId})
|
users = self.db.getRecordset("users", recordFilter={"id": userId})
|
||||||
if users:
|
if not users:
|
||||||
user = users[0]
|
return None
|
||||||
# Remove password hash from the API response
|
|
||||||
if "hashedPassword" in user:
|
filteredUsers = self._uam("users", users)
|
||||||
userCopy = user.copy()
|
if not filteredUsers:
|
||||||
del userCopy["hashedPassword"]
|
return None
|
||||||
return userCopy
|
|
||||||
return user
|
user = filteredUsers[0]
|
||||||
return None
|
|
||||||
|
# Remove password hash
|
||||||
|
if "hashedPassword" in user:
|
||||||
|
userCopy = user.copy()
|
||||||
|
del userCopy["hashedPassword"]
|
||||||
|
return userCopy
|
||||||
|
|
||||||
|
return user
|
||||||
|
|
||||||
def createUser(self, username: str, password: str, email: str = None,
|
def createUser(self, username: str, password: str, email: str = None,
|
||||||
fullName: str = None, language: str = "de", mandateId: int = None,
|
fullName: str = None, language: str = "de", mandateId: int = None,
|
||||||
disabled: bool = False, privilege: str = "user") -> Dict[str, Any]:
|
disabled: bool = False, privilege: str = "user") -> Dict[str, Any]:
|
||||||
"""
|
"""Creates a new user if current user has permission."""
|
||||||
Creates a new user
|
|
||||||
|
|
||||||
Args:
|
|
||||||
username: The username
|
|
||||||
password: The password
|
|
||||||
email: The email address (optional)
|
|
||||||
fullName: The full name (optional)
|
|
||||||
language: The preferred language (default: "de")
|
|
||||||
mandateId: The ID of the mandate (optional)
|
|
||||||
disabled: Whether the user is disabled (default: False)
|
|
||||||
privilege: The privilege level (default: "user")
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Dict[str, Any]: The created user data
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: If the username already exists
|
|
||||||
"""
|
|
||||||
# Check if the username already exists
|
# Check if the username already exists
|
||||||
existingUser = self.getUserByUsername(username)
|
existingUser = self.getUserByUsername(username)
|
||||||
if existingUser:
|
if existingUser:
|
||||||
raise ValueError(f"User '{username}' already exists")
|
raise ValueError(f"User '{username}' already exists")
|
||||||
|
|
||||||
# Use the provided mandateId or the current context
|
# Use the provided mandateId or the current context
|
||||||
userMandateId = mandateId if mandateId is not None else self.mandateId
|
userMandateId = mandateId if mandateId is not None else self.mandateId
|
||||||
|
|
||||||
|
# Check if user has access to the mandate
|
||||||
|
if userMandateId != self.mandateId and self.currentUser.get("privilege") != "sysadmin":
|
||||||
|
raise PermissionError(f"No permission to create users in mandate {userMandateId}")
|
||||||
|
|
||||||
|
if not self._canModify("users"):
|
||||||
|
raise PermissionError("No permission to create users")
|
||||||
|
|
||||||
|
# Check privilege escalation
|
||||||
|
if (privilege == "sysadmin" or
|
||||||
|
(privilege == "admin" and self.currentUser.get("privilege") == "user")):
|
||||||
|
raise PermissionError(f"Cannot create user with higher privilege: {privilege}")
|
||||||
|
|
||||||
userData = {
|
userData = {
|
||||||
"mandateId": userMandateId,
|
"mandateId": userMandateId,
|
||||||
"username": username,
|
"username": username,
|
||||||
|
|
@ -318,16 +392,7 @@ class GatewayInterface:
|
||||||
return createdUser
|
return createdUser
|
||||||
|
|
||||||
def authenticateUser(self, username: str, password: str) -> Optional[Dict[str, Any]]:
|
def authenticateUser(self, username: str, password: str) -> Optional[Dict[str, Any]]:
|
||||||
"""
|
"""Authenticates a user by username and password."""
|
||||||
Authenticates a user by username and password
|
|
||||||
|
|
||||||
Args:
|
|
||||||
username: The username
|
|
||||||
password: The password
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Optional[Dict[str, Any]]: The user data or None if authentication fails
|
|
||||||
"""
|
|
||||||
user = self.getUserByUsername(username)
|
user = self.getUserByUsername(username)
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
|
|
@ -348,25 +413,29 @@ class GatewayInterface:
|
||||||
return authenticatedUser
|
return authenticatedUser
|
||||||
|
|
||||||
def updateUser(self, userId: int, userData: Dict[str, Any]) -> Dict[str, Any]:
|
def updateUser(self, userId: int, userData: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
"""
|
"""Updates a user if current user has permission."""
|
||||||
Updates a user
|
# Check if the user exists and current user has access
|
||||||
|
user = self.getUser(userId)
|
||||||
|
if not user:
|
||||||
|
# Try to get the raw user record for admin access check
|
||||||
|
users = self.db.getRecordset("users", recordFilter={"id": userId})
|
||||||
|
if not users:
|
||||||
|
raise ValueError(f"User with ID {userId} not found")
|
||||||
|
|
||||||
|
# Check if current user is admin/sysadmin
|
||||||
|
if not self._canModify("users", userId):
|
||||||
|
raise PermissionError(f"No permission to update user {userId}")
|
||||||
|
|
||||||
|
user = users[0]
|
||||||
|
|
||||||
Args:
|
# Check privilege escalation
|
||||||
userId: The ID of the user to update
|
if "privilege" in userData:
|
||||||
userData: The user data to update
|
currentPrivilege = self.currentUser.get("privilege")
|
||||||
|
targetPrivilege = userData["privilege"]
|
||||||
|
|
||||||
Returns:
|
if (targetPrivilege == "sysadmin" and currentPrivilege != "sysadmin") or (
|
||||||
Dict[str, Any]: The updated user data
|
targetPrivilege == "admin" and currentPrivilege == "user"):
|
||||||
|
raise PermissionError(f"Cannot escalate privilege to {targetPrivilege}")
|
||||||
Raises:
|
|
||||||
ValueError: If the user is not found
|
|
||||||
"""
|
|
||||||
# Get the current user with password hash (directly from DB)
|
|
||||||
users = self.db.getRecordset("users", recordFilter={"id": userId})
|
|
||||||
if not users:
|
|
||||||
raise ValueError(f"User with ID {userId} not found")
|
|
||||||
|
|
||||||
user = users[0]
|
|
||||||
|
|
||||||
# If the password is being changed, hash it
|
# If the password is being changed, hash it
|
||||||
if "password" in userData:
|
if "password" in userData:
|
||||||
|
|
@ -383,22 +452,15 @@ class GatewayInterface:
|
||||||
return updatedUser
|
return updatedUser
|
||||||
|
|
||||||
def disableUser(self, userId: int) -> Dict[str, Any]:
|
def disableUser(self, userId: int) -> Dict[str, Any]:
|
||||||
"""Disables a user"""
|
"""Disables a user if current user has permission."""
|
||||||
return self.updateUser(userId, {"disabled": True})
|
return self.updateUser(userId, {"disabled": True})
|
||||||
|
|
||||||
def enableUser(self, userId: int) -> Dict[str, Any]:
|
def enableUser(self, userId: int) -> Dict[str, Any]:
|
||||||
"""Enables a user"""
|
"""Enables a user if current user has permission."""
|
||||||
return self.updateUser(userId, {"disabled": False})
|
return self.updateUser(userId, {"disabled": False})
|
||||||
|
|
||||||
def _deleteUserReferencedData(self, userId: int) -> None:
|
def _deleteUserReferencedData(self, userId: int) -> None:
|
||||||
"""
|
"""Deletes all data associated with a user."""
|
||||||
Deletes all data associated with a user
|
|
||||||
|
|
||||||
Args:
|
|
||||||
userId: The ID of the user
|
|
||||||
"""
|
|
||||||
# Here all tables are searched and all entries referencing this user are deleted
|
|
||||||
|
|
||||||
# Delete user attributes
|
# Delete user attributes
|
||||||
try:
|
try:
|
||||||
attributes = self.db.getRecordset("attributes", recordFilter={"userId": userId})
|
attributes = self.db.getRecordset("attributes", recordFilter={"userId": userId})
|
||||||
|
|
@ -407,25 +469,18 @@ class GatewayInterface:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error deleting attributes for user {userId}: {e}")
|
logger.error(f"Error deleting attributes for user {userId}: {e}")
|
||||||
|
|
||||||
# Other tables that might reference the user
|
|
||||||
# (Depending on the application's database structure)
|
|
||||||
|
|
||||||
logger.info(f"All referenced data for user {userId} has been deleted")
|
logger.info(f"All referenced data for user {userId} has been deleted")
|
||||||
|
|
||||||
def deleteUser(self, userId: int) -> bool:
|
def deleteUser(self, userId: int) -> bool:
|
||||||
"""
|
"""Deletes a user and all associated data if current user has permission."""
|
||||||
Deletes a user and all associated data
|
|
||||||
|
|
||||||
Args:
|
|
||||||
userId: The ID of the user to delete
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: True if the user was successfully deleted, otherwise False
|
|
||||||
"""
|
|
||||||
# Check if the user exists
|
# Check if the user exists
|
||||||
users = self.db.getRecordset("users", recordFilter={"id": userId})
|
users = self.db.getRecordset("users", recordFilter={"id": userId})
|
||||||
if not users:
|
if not users:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Check if current user has permission
|
||||||
|
if not self._canModify("users", userId):
|
||||||
|
raise PermissionError(f"No permission to delete user {userId}")
|
||||||
|
|
||||||
# Check if it's the initial user
|
# Check if it's the initial user
|
||||||
initialUserId = self.getInitialId("users")
|
initialUserId = self.getInitialId("users")
|
||||||
|
|
@ -454,18 +509,11 @@ def getGatewayInterface(mandateId: int = None, userId: int = None) -> GatewayInt
|
||||||
"""
|
"""
|
||||||
Returns a GatewayInterface instance for the specified context.
|
Returns a GatewayInterface instance for the specified context.
|
||||||
Reuses existing instances.
|
Reuses existing instances.
|
||||||
|
|
||||||
Args:
|
|
||||||
mandateId: ID of the mandate
|
|
||||||
userId: ID of the user
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
GatewayInterface instance
|
|
||||||
"""
|
"""
|
||||||
contextKey = f"{mandateId}_{userId}"
|
contextKey = f"{mandateId}_{userId}"
|
||||||
if contextKey not in _gatewayInterfaces:
|
if contextKey not in _gatewayInterfaces:
|
||||||
_gatewayInterfaces[contextKey] = GatewayInterface(mandateId, userId)
|
_gatewayInterfaces[contextKey] = GatewayInterface(mandateId, userId)
|
||||||
return _gatewayInterfaces[contextKey]
|
return _gatewayInterfaces[contextKey]
|
||||||
|
|
||||||
# Initialize the interface
|
# Initialize an instance
|
||||||
getGatewayInterface()
|
getGatewayInterface()
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1 +0,0 @@
|
||||||
{'total_pixels': None, 'total_characters': None}
|
|
||||||
38
static/1_generated_code.py
Normal file
38
static/1_generated_code.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
inputFiles = [] # DO NOT CHANGE THIS LINE
|
||||||
|
|
||||||
|
def is_prime(n):
|
||||||
|
if n <= 1:
|
||||||
|
return False
|
||||||
|
if n <= 3:
|
||||||
|
return True
|
||||||
|
if n % 2 == 0 or n % 3 == 0:
|
||||||
|
return False
|
||||||
|
i = 5
|
||||||
|
while i * i <= n:
|
||||||
|
if n % i == 0 or n % (i + 2) == 0:
|
||||||
|
return False
|
||||||
|
i += 6
|
||||||
|
return True
|
||||||
|
|
||||||
|
def generate_primes(count):
|
||||||
|
primes = []
|
||||||
|
num = 2
|
||||||
|
while len(primes) < count:
|
||||||
|
if is_prime(num):
|
||||||
|
primes.append(num)
|
||||||
|
num += 1
|
||||||
|
return primes
|
||||||
|
|
||||||
|
primes = generate_primes(1000)
|
||||||
|
prime_numbers_content = "\n".join(map(str, primes))
|
||||||
|
|
||||||
|
result = {
|
||||||
|
"prime_numbers.txt": {
|
||||||
|
"content": prime_numbers_content,
|
||||||
|
"base64Encoded": False,
|
||||||
|
"contentType": "text/plain"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import json
|
||||||
|
print(json.dumps(result))
|
||||||
19
static/2_execution_history.json
Normal file
19
static/2_execution_history.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -648,3 +648,353 @@
|
||||||
4813
|
4813
|
||||||
4817
|
4817
|
||||||
4831
|
4831
|
||||||
|
4861
|
||||||
|
4871
|
||||||
|
4877
|
||||||
|
4889
|
||||||
|
4903
|
||||||
|
4909
|
||||||
|
4919
|
||||||
|
4931
|
||||||
|
4933
|
||||||
|
4937
|
||||||
|
4943
|
||||||
|
4951
|
||||||
|
4957
|
||||||
|
4967
|
||||||
|
4969
|
||||||
|
4973
|
||||||
|
4987
|
||||||
|
4993
|
||||||
|
4999
|
||||||
|
5003
|
||||||
|
5009
|
||||||
|
5011
|
||||||
|
5021
|
||||||
|
5023
|
||||||
|
5039
|
||||||
|
5051
|
||||||
|
5059
|
||||||
|
5077
|
||||||
|
5081
|
||||||
|
5087
|
||||||
|
5099
|
||||||
|
5101
|
||||||
|
5107
|
||||||
|
5113
|
||||||
|
5119
|
||||||
|
5147
|
||||||
|
5153
|
||||||
|
5167
|
||||||
|
5171
|
||||||
|
5179
|
||||||
|
5189
|
||||||
|
5197
|
||||||
|
5209
|
||||||
|
5227
|
||||||
|
5231
|
||||||
|
5233
|
||||||
|
5237
|
||||||
|
5261
|
||||||
|
5273
|
||||||
|
5279
|
||||||
|
5281
|
||||||
|
5297
|
||||||
|
5303
|
||||||
|
5309
|
||||||
|
5323
|
||||||
|
5333
|
||||||
|
5347
|
||||||
|
5351
|
||||||
|
5381
|
||||||
|
5387
|
||||||
|
5393
|
||||||
|
5399
|
||||||
|
5407
|
||||||
|
5413
|
||||||
|
5417
|
||||||
|
5419
|
||||||
|
5431
|
||||||
|
5437
|
||||||
|
5441
|
||||||
|
5443
|
||||||
|
5449
|
||||||
|
5471
|
||||||
|
5477
|
||||||
|
5479
|
||||||
|
5483
|
||||||
|
5501
|
||||||
|
5503
|
||||||
|
5507
|
||||||
|
5519
|
||||||
|
5521
|
||||||
|
5527
|
||||||
|
5531
|
||||||
|
5557
|
||||||
|
5563
|
||||||
|
5569
|
||||||
|
5573
|
||||||
|
5581
|
||||||
|
5591
|
||||||
|
5623
|
||||||
|
5639
|
||||||
|
5641
|
||||||
|
5647
|
||||||
|
5651
|
||||||
|
5653
|
||||||
|
5657
|
||||||
|
5659
|
||||||
|
5669
|
||||||
|
5683
|
||||||
|
5689
|
||||||
|
5693
|
||||||
|
5701
|
||||||
|
5711
|
||||||
|
5717
|
||||||
|
5737
|
||||||
|
5741
|
||||||
|
5743
|
||||||
|
5749
|
||||||
|
5779
|
||||||
|
5783
|
||||||
|
5791
|
||||||
|
5801
|
||||||
|
5807
|
||||||
|
5813
|
||||||
|
5821
|
||||||
|
5827
|
||||||
|
5839
|
||||||
|
5843
|
||||||
|
5849
|
||||||
|
5851
|
||||||
|
5857
|
||||||
|
5861
|
||||||
|
5867
|
||||||
|
5869
|
||||||
|
5879
|
||||||
|
5881
|
||||||
|
5897
|
||||||
|
5903
|
||||||
|
5923
|
||||||
|
5927
|
||||||
|
5939
|
||||||
|
5953
|
||||||
|
5981
|
||||||
|
5987
|
||||||
|
6007
|
||||||
|
6011
|
||||||
|
6029
|
||||||
|
6037
|
||||||
|
6043
|
||||||
|
6047
|
||||||
|
6053
|
||||||
|
6067
|
||||||
|
6073
|
||||||
|
6079
|
||||||
|
6089
|
||||||
|
6091
|
||||||
|
6101
|
||||||
|
6113
|
||||||
|
6121
|
||||||
|
6131
|
||||||
|
6133
|
||||||
|
6143
|
||||||
|
6151
|
||||||
|
6163
|
||||||
|
6173
|
||||||
|
6197
|
||||||
|
6199
|
||||||
|
6203
|
||||||
|
6211
|
||||||
|
6217
|
||||||
|
6221
|
||||||
|
6229
|
||||||
|
6247
|
||||||
|
6257
|
||||||
|
6263
|
||||||
|
6269
|
||||||
|
6271
|
||||||
|
6277
|
||||||
|
6287
|
||||||
|
6299
|
||||||
|
6301
|
||||||
|
6311
|
||||||
|
6317
|
||||||
|
6323
|
||||||
|
6329
|
||||||
|
6337
|
||||||
|
6343
|
||||||
|
6353
|
||||||
|
6359
|
||||||
|
6361
|
||||||
|
6367
|
||||||
|
6373
|
||||||
|
6379
|
||||||
|
6389
|
||||||
|
6397
|
||||||
|
6421
|
||||||
|
6427
|
||||||
|
6449
|
||||||
|
6451
|
||||||
|
6469
|
||||||
|
6473
|
||||||
|
6481
|
||||||
|
6491
|
||||||
|
6521
|
||||||
|
6529
|
||||||
|
6547
|
||||||
|
6551
|
||||||
|
6553
|
||||||
|
6563
|
||||||
|
6569
|
||||||
|
6571
|
||||||
|
6577
|
||||||
|
6581
|
||||||
|
6599
|
||||||
|
6607
|
||||||
|
6619
|
||||||
|
6637
|
||||||
|
6653
|
||||||
|
6659
|
||||||
|
6661
|
||||||
|
6673
|
||||||
|
6679
|
||||||
|
6689
|
||||||
|
6691
|
||||||
|
6701
|
||||||
|
6703
|
||||||
|
6709
|
||||||
|
6719
|
||||||
|
6733
|
||||||
|
6737
|
||||||
|
6761
|
||||||
|
6763
|
||||||
|
6779
|
||||||
|
6781
|
||||||
|
6791
|
||||||
|
6793
|
||||||
|
6803
|
||||||
|
6823
|
||||||
|
6827
|
||||||
|
6829
|
||||||
|
6833
|
||||||
|
6841
|
||||||
|
6857
|
||||||
|
6863
|
||||||
|
6869
|
||||||
|
6871
|
||||||
|
6883
|
||||||
|
6899
|
||||||
|
6907
|
||||||
|
6911
|
||||||
|
6917
|
||||||
|
6947
|
||||||
|
6949
|
||||||
|
6959
|
||||||
|
6961
|
||||||
|
6967
|
||||||
|
6971
|
||||||
|
6977
|
||||||
|
6983
|
||||||
|
6991
|
||||||
|
6997
|
||||||
|
7001
|
||||||
|
7013
|
||||||
|
7019
|
||||||
|
7027
|
||||||
|
7039
|
||||||
|
7043
|
||||||
|
7057
|
||||||
|
7069
|
||||||
|
7079
|
||||||
|
7103
|
||||||
|
7109
|
||||||
|
7121
|
||||||
|
7127
|
||||||
|
7129
|
||||||
|
7151
|
||||||
|
7159
|
||||||
|
7177
|
||||||
|
7187
|
||||||
|
7193
|
||||||
|
7207
|
||||||
|
7211
|
||||||
|
7213
|
||||||
|
7219
|
||||||
|
7229
|
||||||
|
7237
|
||||||
|
7243
|
||||||
|
7247
|
||||||
|
7253
|
||||||
|
7283
|
||||||
|
7297
|
||||||
|
7307
|
||||||
|
7309
|
||||||
|
7321
|
||||||
|
7331
|
||||||
|
7333
|
||||||
|
7349
|
||||||
|
7351
|
||||||
|
7369
|
||||||
|
7393
|
||||||
|
7411
|
||||||
|
7417
|
||||||
|
7433
|
||||||
|
7451
|
||||||
|
7457
|
||||||
|
7459
|
||||||
|
7477
|
||||||
|
7481
|
||||||
|
7487
|
||||||
|
7489
|
||||||
|
7499
|
||||||
|
7507
|
||||||
|
7517
|
||||||
|
7523
|
||||||
|
7529
|
||||||
|
7537
|
||||||
|
7541
|
||||||
|
7547
|
||||||
|
7549
|
||||||
|
7559
|
||||||
|
7561
|
||||||
|
7573
|
||||||
|
7577
|
||||||
|
7583
|
||||||
|
7589
|
||||||
|
7591
|
||||||
|
7603
|
||||||
|
7607
|
||||||
|
7621
|
||||||
|
7639
|
||||||
|
7643
|
||||||
|
7649
|
||||||
|
7669
|
||||||
|
7673
|
||||||
|
7681
|
||||||
|
7687
|
||||||
|
7691
|
||||||
|
7699
|
||||||
|
7703
|
||||||
|
7717
|
||||||
|
7723
|
||||||
|
7727
|
||||||
|
7741
|
||||||
|
7753
|
||||||
|
7757
|
||||||
|
7759
|
||||||
|
7789
|
||||||
|
7793
|
||||||
|
7817
|
||||||
|
7823
|
||||||
|
7829
|
||||||
|
7841
|
||||||
|
7853
|
||||||
|
7867
|
||||||
|
7873
|
||||||
|
7877
|
||||||
|
7879
|
||||||
|
7883
|
||||||
|
7901
|
||||||
|
7907
|
||||||
|
7919
|
||||||
Loading…
Reference in a new issue