MemoryOS 2.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- memoryos-2.0.3.dist-info/METADATA +418 -0
- memoryos-2.0.3.dist-info/RECORD +315 -0
- memoryos-2.0.3.dist-info/WHEEL +4 -0
- memoryos-2.0.3.dist-info/entry_points.txt +3 -0
- memoryos-2.0.3.dist-info/licenses/LICENSE +201 -0
- memos/__init__.py +20 -0
- memos/api/client.py +571 -0
- memos/api/config.py +1018 -0
- memos/api/context/dependencies.py +50 -0
- memos/api/exceptions.py +53 -0
- memos/api/handlers/__init__.py +62 -0
- memos/api/handlers/add_handler.py +158 -0
- memos/api/handlers/base_handler.py +194 -0
- memos/api/handlers/chat_handler.py +1401 -0
- memos/api/handlers/component_init.py +388 -0
- memos/api/handlers/config_builders.py +190 -0
- memos/api/handlers/feedback_handler.py +93 -0
- memos/api/handlers/formatters_handler.py +237 -0
- memos/api/handlers/memory_handler.py +316 -0
- memos/api/handlers/scheduler_handler.py +497 -0
- memos/api/handlers/search_handler.py +222 -0
- memos/api/handlers/suggestion_handler.py +117 -0
- memos/api/mcp_serve.py +614 -0
- memos/api/middleware/request_context.py +101 -0
- memos/api/product_api.py +38 -0
- memos/api/product_models.py +1206 -0
- memos/api/routers/__init__.py +1 -0
- memos/api/routers/product_router.py +477 -0
- memos/api/routers/server_router.py +394 -0
- memos/api/server_api.py +44 -0
- memos/api/start_api.py +433 -0
- memos/chunkers/__init__.py +4 -0
- memos/chunkers/base.py +24 -0
- memos/chunkers/charactertext_chunker.py +41 -0
- memos/chunkers/factory.py +24 -0
- memos/chunkers/markdown_chunker.py +62 -0
- memos/chunkers/sentence_chunker.py +54 -0
- memos/chunkers/simple_chunker.py +50 -0
- memos/cli.py +113 -0
- memos/configs/__init__.py +0 -0
- memos/configs/base.py +82 -0
- memos/configs/chunker.py +59 -0
- memos/configs/embedder.py +88 -0
- memos/configs/graph_db.py +236 -0
- memos/configs/internet_retriever.py +100 -0
- memos/configs/llm.py +151 -0
- memos/configs/mem_agent.py +54 -0
- memos/configs/mem_chat.py +81 -0
- memos/configs/mem_cube.py +105 -0
- memos/configs/mem_os.py +83 -0
- memos/configs/mem_reader.py +91 -0
- memos/configs/mem_scheduler.py +385 -0
- memos/configs/mem_user.py +70 -0
- memos/configs/memory.py +324 -0
- memos/configs/parser.py +38 -0
- memos/configs/reranker.py +18 -0
- memos/configs/utils.py +8 -0
- memos/configs/vec_db.py +80 -0
- memos/context/context.py +355 -0
- memos/dependency.py +52 -0
- memos/deprecation.py +262 -0
- memos/embedders/__init__.py +0 -0
- memos/embedders/ark.py +95 -0
- memos/embedders/base.py +106 -0
- memos/embedders/factory.py +29 -0
- memos/embedders/ollama.py +77 -0
- memos/embedders/sentence_transformer.py +49 -0
- memos/embedders/universal_api.py +51 -0
- memos/exceptions.py +30 -0
- memos/graph_dbs/__init__.py +0 -0
- memos/graph_dbs/base.py +274 -0
- memos/graph_dbs/factory.py +27 -0
- memos/graph_dbs/item.py +46 -0
- memos/graph_dbs/nebular.py +1794 -0
- memos/graph_dbs/neo4j.py +1942 -0
- memos/graph_dbs/neo4j_community.py +1058 -0
- memos/graph_dbs/polardb.py +5446 -0
- memos/hello_world.py +97 -0
- memos/llms/__init__.py +0 -0
- memos/llms/base.py +25 -0
- memos/llms/deepseek.py +13 -0
- memos/llms/factory.py +38 -0
- memos/llms/hf.py +443 -0
- memos/llms/hf_singleton.py +114 -0
- memos/llms/ollama.py +135 -0
- memos/llms/openai.py +222 -0
- memos/llms/openai_new.py +198 -0
- memos/llms/qwen.py +13 -0
- memos/llms/utils.py +14 -0
- memos/llms/vllm.py +218 -0
- memos/log.py +237 -0
- memos/mem_agent/base.py +19 -0
- memos/mem_agent/deepsearch_agent.py +391 -0
- memos/mem_agent/factory.py +36 -0
- memos/mem_chat/__init__.py +0 -0
- memos/mem_chat/base.py +30 -0
- memos/mem_chat/factory.py +21 -0
- memos/mem_chat/simple.py +200 -0
- memos/mem_cube/__init__.py +0 -0
- memos/mem_cube/base.py +30 -0
- memos/mem_cube/general.py +240 -0
- memos/mem_cube/navie.py +172 -0
- memos/mem_cube/utils.py +169 -0
- memos/mem_feedback/base.py +15 -0
- memos/mem_feedback/feedback.py +1192 -0
- memos/mem_feedback/simple_feedback.py +40 -0
- memos/mem_feedback/utils.py +230 -0
- memos/mem_os/client.py +5 -0
- memos/mem_os/core.py +1203 -0
- memos/mem_os/main.py +582 -0
- memos/mem_os/product.py +1608 -0
- memos/mem_os/product_server.py +455 -0
- memos/mem_os/utils/default_config.py +359 -0
- memos/mem_os/utils/format_utils.py +1403 -0
- memos/mem_os/utils/reference_utils.py +162 -0
- memos/mem_reader/__init__.py +0 -0
- memos/mem_reader/base.py +47 -0
- memos/mem_reader/factory.py +53 -0
- memos/mem_reader/memory.py +298 -0
- memos/mem_reader/multi_modal_struct.py +965 -0
- memos/mem_reader/read_multi_modal/__init__.py +43 -0
- memos/mem_reader/read_multi_modal/assistant_parser.py +311 -0
- memos/mem_reader/read_multi_modal/base.py +273 -0
- memos/mem_reader/read_multi_modal/file_content_parser.py +826 -0
- memos/mem_reader/read_multi_modal/image_parser.py +359 -0
- memos/mem_reader/read_multi_modal/multi_modal_parser.py +252 -0
- memos/mem_reader/read_multi_modal/string_parser.py +139 -0
- memos/mem_reader/read_multi_modal/system_parser.py +327 -0
- memos/mem_reader/read_multi_modal/text_content_parser.py +131 -0
- memos/mem_reader/read_multi_modal/tool_parser.py +210 -0
- memos/mem_reader/read_multi_modal/user_parser.py +218 -0
- memos/mem_reader/read_multi_modal/utils.py +358 -0
- memos/mem_reader/simple_struct.py +912 -0
- memos/mem_reader/strategy_struct.py +163 -0
- memos/mem_reader/utils.py +157 -0
- memos/mem_scheduler/__init__.py +0 -0
- memos/mem_scheduler/analyzer/__init__.py +0 -0
- memos/mem_scheduler/analyzer/api_analyzer.py +714 -0
- memos/mem_scheduler/analyzer/eval_analyzer.py +219 -0
- memos/mem_scheduler/analyzer/mos_for_test_scheduler.py +571 -0
- memos/mem_scheduler/analyzer/scheduler_for_eval.py +280 -0
- memos/mem_scheduler/base_scheduler.py +1319 -0
- memos/mem_scheduler/general_modules/__init__.py +0 -0
- memos/mem_scheduler/general_modules/api_misc.py +137 -0
- memos/mem_scheduler/general_modules/base.py +80 -0
- memos/mem_scheduler/general_modules/init_components_for_scheduler.py +425 -0
- memos/mem_scheduler/general_modules/misc.py +313 -0
- memos/mem_scheduler/general_modules/scheduler_logger.py +389 -0
- memos/mem_scheduler/general_modules/task_threads.py +315 -0
- memos/mem_scheduler/general_scheduler.py +1495 -0
- memos/mem_scheduler/memory_manage_modules/__init__.py +5 -0
- memos/mem_scheduler/memory_manage_modules/memory_filter.py +306 -0
- memos/mem_scheduler/memory_manage_modules/retriever.py +547 -0
- memos/mem_scheduler/monitors/__init__.py +0 -0
- memos/mem_scheduler/monitors/dispatcher_monitor.py +366 -0
- memos/mem_scheduler/monitors/general_monitor.py +394 -0
- memos/mem_scheduler/monitors/task_schedule_monitor.py +254 -0
- memos/mem_scheduler/optimized_scheduler.py +410 -0
- memos/mem_scheduler/orm_modules/__init__.py +0 -0
- memos/mem_scheduler/orm_modules/api_redis_model.py +518 -0
- memos/mem_scheduler/orm_modules/base_model.py +729 -0
- memos/mem_scheduler/orm_modules/monitor_models.py +261 -0
- memos/mem_scheduler/orm_modules/redis_model.py +699 -0
- memos/mem_scheduler/scheduler_factory.py +23 -0
- memos/mem_scheduler/schemas/__init__.py +0 -0
- memos/mem_scheduler/schemas/analyzer_schemas.py +52 -0
- memos/mem_scheduler/schemas/api_schemas.py +233 -0
- memos/mem_scheduler/schemas/general_schemas.py +55 -0
- memos/mem_scheduler/schemas/message_schemas.py +173 -0
- memos/mem_scheduler/schemas/monitor_schemas.py +406 -0
- memos/mem_scheduler/schemas/task_schemas.py +132 -0
- memos/mem_scheduler/task_schedule_modules/__init__.py +0 -0
- memos/mem_scheduler/task_schedule_modules/dispatcher.py +740 -0
- memos/mem_scheduler/task_schedule_modules/local_queue.py +247 -0
- memos/mem_scheduler/task_schedule_modules/orchestrator.py +74 -0
- memos/mem_scheduler/task_schedule_modules/redis_queue.py +1385 -0
- memos/mem_scheduler/task_schedule_modules/task_queue.py +162 -0
- memos/mem_scheduler/utils/__init__.py +0 -0
- memos/mem_scheduler/utils/api_utils.py +77 -0
- memos/mem_scheduler/utils/config_utils.py +100 -0
- memos/mem_scheduler/utils/db_utils.py +50 -0
- memos/mem_scheduler/utils/filter_utils.py +176 -0
- memos/mem_scheduler/utils/metrics.py +125 -0
- memos/mem_scheduler/utils/misc_utils.py +290 -0
- memos/mem_scheduler/utils/monitor_event_utils.py +67 -0
- memos/mem_scheduler/utils/status_tracker.py +229 -0
- memos/mem_scheduler/webservice_modules/__init__.py +0 -0
- memos/mem_scheduler/webservice_modules/rabbitmq_service.py +485 -0
- memos/mem_scheduler/webservice_modules/redis_service.py +380 -0
- memos/mem_user/factory.py +94 -0
- memos/mem_user/mysql_persistent_user_manager.py +271 -0
- memos/mem_user/mysql_user_manager.py +502 -0
- memos/mem_user/persistent_factory.py +98 -0
- memos/mem_user/persistent_user_manager.py +260 -0
- memos/mem_user/redis_persistent_user_manager.py +225 -0
- memos/mem_user/user_manager.py +488 -0
- memos/memories/__init__.py +0 -0
- memos/memories/activation/__init__.py +0 -0
- memos/memories/activation/base.py +42 -0
- memos/memories/activation/item.py +56 -0
- memos/memories/activation/kv.py +292 -0
- memos/memories/activation/vllmkv.py +219 -0
- memos/memories/base.py +19 -0
- memos/memories/factory.py +42 -0
- memos/memories/parametric/__init__.py +0 -0
- memos/memories/parametric/base.py +19 -0
- memos/memories/parametric/item.py +11 -0
- memos/memories/parametric/lora.py +41 -0
- memos/memories/textual/__init__.py +0 -0
- memos/memories/textual/base.py +92 -0
- memos/memories/textual/general.py +236 -0
- memos/memories/textual/item.py +304 -0
- memos/memories/textual/naive.py +187 -0
- memos/memories/textual/prefer_text_memory/__init__.py +0 -0
- memos/memories/textual/prefer_text_memory/adder.py +504 -0
- memos/memories/textual/prefer_text_memory/config.py +106 -0
- memos/memories/textual/prefer_text_memory/extractor.py +221 -0
- memos/memories/textual/prefer_text_memory/factory.py +85 -0
- memos/memories/textual/prefer_text_memory/retrievers.py +177 -0
- memos/memories/textual/prefer_text_memory/spliter.py +132 -0
- memos/memories/textual/prefer_text_memory/utils.py +93 -0
- memos/memories/textual/preference.py +344 -0
- memos/memories/textual/simple_preference.py +161 -0
- memos/memories/textual/simple_tree.py +69 -0
- memos/memories/textual/tree.py +459 -0
- memos/memories/textual/tree_text_memory/__init__.py +0 -0
- memos/memories/textual/tree_text_memory/organize/__init__.py +0 -0
- memos/memories/textual/tree_text_memory/organize/handler.py +184 -0
- memos/memories/textual/tree_text_memory/organize/manager.py +518 -0
- memos/memories/textual/tree_text_memory/organize/relation_reason_detector.py +238 -0
- memos/memories/textual/tree_text_memory/organize/reorganizer.py +622 -0
- memos/memories/textual/tree_text_memory/retrieve/__init__.py +0 -0
- memos/memories/textual/tree_text_memory/retrieve/advanced_searcher.py +364 -0
- memos/memories/textual/tree_text_memory/retrieve/bm25_util.py +186 -0
- memos/memories/textual/tree_text_memory/retrieve/bochasearch.py +419 -0
- memos/memories/textual/tree_text_memory/retrieve/internet_retriever.py +270 -0
- memos/memories/textual/tree_text_memory/retrieve/internet_retriever_factory.py +102 -0
- memos/memories/textual/tree_text_memory/retrieve/reasoner.py +61 -0
- memos/memories/textual/tree_text_memory/retrieve/recall.py +497 -0
- memos/memories/textual/tree_text_memory/retrieve/reranker.py +111 -0
- memos/memories/textual/tree_text_memory/retrieve/retrieval_mid_structs.py +16 -0
- memos/memories/textual/tree_text_memory/retrieve/retrieve_utils.py +472 -0
- memos/memories/textual/tree_text_memory/retrieve/searcher.py +848 -0
- memos/memories/textual/tree_text_memory/retrieve/task_goal_parser.py +135 -0
- memos/memories/textual/tree_text_memory/retrieve/utils.py +54 -0
- memos/memories/textual/tree_text_memory/retrieve/xinyusearch.py +387 -0
- memos/memos_tools/dinding_report_bot.py +453 -0
- memos/memos_tools/lockfree_dict.py +120 -0
- memos/memos_tools/notification_service.py +44 -0
- memos/memos_tools/notification_utils.py +142 -0
- memos/memos_tools/singleton.py +174 -0
- memos/memos_tools/thread_safe_dict.py +310 -0
- memos/memos_tools/thread_safe_dict_segment.py +382 -0
- memos/multi_mem_cube/__init__.py +0 -0
- memos/multi_mem_cube/composite_cube.py +86 -0
- memos/multi_mem_cube/single_cube.py +874 -0
- memos/multi_mem_cube/views.py +54 -0
- memos/parsers/__init__.py +0 -0
- memos/parsers/base.py +15 -0
- memos/parsers/factory.py +21 -0
- memos/parsers/markitdown.py +28 -0
- memos/reranker/__init__.py +4 -0
- memos/reranker/base.py +25 -0
- memos/reranker/concat.py +103 -0
- memos/reranker/cosine_local.py +102 -0
- memos/reranker/factory.py +72 -0
- memos/reranker/http_bge.py +324 -0
- memos/reranker/http_bge_strategy.py +327 -0
- memos/reranker/noop.py +19 -0
- memos/reranker/strategies/__init__.py +4 -0
- memos/reranker/strategies/base.py +61 -0
- memos/reranker/strategies/concat_background.py +94 -0
- memos/reranker/strategies/concat_docsource.py +110 -0
- memos/reranker/strategies/dialogue_common.py +109 -0
- memos/reranker/strategies/factory.py +31 -0
- memos/reranker/strategies/single_turn.py +107 -0
- memos/reranker/strategies/singleturn_outmem.py +98 -0
- memos/settings.py +10 -0
- memos/templates/__init__.py +0 -0
- memos/templates/advanced_search_prompts.py +211 -0
- memos/templates/cloud_service_prompt.py +107 -0
- memos/templates/instruction_completion.py +66 -0
- memos/templates/mem_agent_prompts.py +85 -0
- memos/templates/mem_feedback_prompts.py +822 -0
- memos/templates/mem_reader_prompts.py +1096 -0
- memos/templates/mem_reader_strategy_prompts.py +238 -0
- memos/templates/mem_scheduler_prompts.py +626 -0
- memos/templates/mem_search_prompts.py +93 -0
- memos/templates/mos_prompts.py +403 -0
- memos/templates/prefer_complete_prompt.py +735 -0
- memos/templates/tool_mem_prompts.py +139 -0
- memos/templates/tree_reorganize_prompts.py +230 -0
- memos/types/__init__.py +34 -0
- memos/types/general_types.py +151 -0
- memos/types/openai_chat_completion_types/__init__.py +15 -0
- memos/types/openai_chat_completion_types/chat_completion_assistant_message_param.py +56 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_image_param.py +27 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_input_audio_param.py +23 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_param.py +43 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_refusal_param.py +16 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_text_param.py +16 -0
- memos/types/openai_chat_completion_types/chat_completion_message_custom_tool_call_param.py +27 -0
- memos/types/openai_chat_completion_types/chat_completion_message_function_tool_call_param.py +32 -0
- memos/types/openai_chat_completion_types/chat_completion_message_param.py +18 -0
- memos/types/openai_chat_completion_types/chat_completion_message_tool_call_union_param.py +15 -0
- memos/types/openai_chat_completion_types/chat_completion_system_message_param.py +36 -0
- memos/types/openai_chat_completion_types/chat_completion_tool_message_param.py +30 -0
- memos/types/openai_chat_completion_types/chat_completion_user_message_param.py +34 -0
- memos/utils.py +123 -0
- memos/vec_dbs/__init__.py +0 -0
- memos/vec_dbs/base.py +117 -0
- memos/vec_dbs/factory.py +23 -0
- memos/vec_dbs/item.py +50 -0
- memos/vec_dbs/milvus.py +654 -0
- memos/vec_dbs/qdrant.py +355 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"""Persistent user management system for MemOS with configuration storage.
|
|
2
|
+
|
|
3
|
+
This module extends the MySQL UserManager to provide persistent storage
|
|
4
|
+
for user configurations and MOS instances.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from sqlalchemy import Column, String, Text
|
|
13
|
+
|
|
14
|
+
from memos.configs.mem_os import MOSConfig
|
|
15
|
+
from memos.log import get_logger
|
|
16
|
+
from memos.mem_user.mysql_user_manager import Base, MySQLUserManager
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
logger = get_logger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class UserConfig(Base):
|
|
23
|
+
"""User configuration model for the database."""
|
|
24
|
+
|
|
25
|
+
__tablename__ = "user_configs"
|
|
26
|
+
|
|
27
|
+
user_id = Column(String(255), primary_key=True)
|
|
28
|
+
config_data = Column(Text, nullable=False) # JSON string of MOSConfig
|
|
29
|
+
created_at = Column(String(50), nullable=False) # ISO format timestamp
|
|
30
|
+
updated_at = Column(String(50), nullable=False) # ISO format timestamp
|
|
31
|
+
|
|
32
|
+
def __repr__(self):
|
|
33
|
+
return f"<UserConfig(user_id='{self.user_id}')>"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class MySQLPersistentUserManager(MySQLUserManager):
|
|
37
|
+
"""Extended MySQLUserManager with configuration persistence."""
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
user_id: str = "root",
|
|
42
|
+
host: str = "localhost",
|
|
43
|
+
port: int = 3306,
|
|
44
|
+
username: str = "root",
|
|
45
|
+
password: str = "",
|
|
46
|
+
database: str = "memos_users",
|
|
47
|
+
charset: str = "utf8mb4",
|
|
48
|
+
):
|
|
49
|
+
"""Initialize the persistent user manager.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
user_id (str, optional): User ID. If None, uses default user ID.
|
|
53
|
+
host (str): MySQL server host. Defaults to "localhost".
|
|
54
|
+
port (int): MySQL server port. Defaults to 3306.
|
|
55
|
+
username (str): MySQL username. Defaults to "root".
|
|
56
|
+
password (str): MySQL password. Defaults to "".
|
|
57
|
+
database (str): MySQL database name. Defaults to "memos_users".
|
|
58
|
+
charset (str): MySQL charset. Defaults to "utf8mb4".
|
|
59
|
+
"""
|
|
60
|
+
super().__init__(user_id, host, port, username, password, database, charset)
|
|
61
|
+
|
|
62
|
+
# Create user_configs table
|
|
63
|
+
Base.metadata.create_all(bind=self.engine)
|
|
64
|
+
logger.info("MySQLPersistentUserManager initialized with configuration storage")
|
|
65
|
+
|
|
66
|
+
def _convert_datetime_strings(self, obj: Any) -> Any:
|
|
67
|
+
"""Recursively convert datetime strings back to datetime objects in config dict.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
obj: The object to process (dict, list, or primitive type)
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
The object with datetime strings converted to datetime objects
|
|
74
|
+
"""
|
|
75
|
+
if isinstance(obj, dict):
|
|
76
|
+
result = {}
|
|
77
|
+
for key, value in obj.items():
|
|
78
|
+
if key == "created_at" and isinstance(value, str):
|
|
79
|
+
try:
|
|
80
|
+
result[key] = datetime.fromisoformat(value)
|
|
81
|
+
except ValueError:
|
|
82
|
+
# If parsing fails, keep the original string
|
|
83
|
+
result[key] = value
|
|
84
|
+
else:
|
|
85
|
+
result[key] = self._convert_datetime_strings(value)
|
|
86
|
+
return result
|
|
87
|
+
elif isinstance(obj, list):
|
|
88
|
+
return [self._convert_datetime_strings(item) for item in obj]
|
|
89
|
+
else:
|
|
90
|
+
return obj
|
|
91
|
+
|
|
92
|
+
def save_user_config(self, user_id: str, config: MOSConfig) -> bool:
|
|
93
|
+
"""Save user configuration to database.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
user_id (str): The user ID.
|
|
97
|
+
config (MOSConfig): The user's MOS configuration.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
bool: True if successful, False otherwise.
|
|
101
|
+
"""
|
|
102
|
+
session = self._get_session()
|
|
103
|
+
try:
|
|
104
|
+
# Convert config to JSON string with proper datetime handling
|
|
105
|
+
config_dict = config.model_dump(mode="json")
|
|
106
|
+
config_json = json.dumps(config_dict, indent=2)
|
|
107
|
+
|
|
108
|
+
now = datetime.now().isoformat()
|
|
109
|
+
|
|
110
|
+
# Check if config already exists
|
|
111
|
+
existing_config = (
|
|
112
|
+
session.query(UserConfig).filter(UserConfig.user_id == user_id).first()
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if existing_config:
|
|
116
|
+
# Update existing config
|
|
117
|
+
existing_config.config_data = config_json
|
|
118
|
+
existing_config.updated_at = now
|
|
119
|
+
logger.info(f"Updated configuration for user {user_id}")
|
|
120
|
+
else:
|
|
121
|
+
# Create new config
|
|
122
|
+
user_config = UserConfig(
|
|
123
|
+
user_id=user_id, config_data=config_json, created_at=now, updated_at=now
|
|
124
|
+
)
|
|
125
|
+
session.add(user_config)
|
|
126
|
+
logger.info(f"Saved new configuration for user {user_id}")
|
|
127
|
+
|
|
128
|
+
session.commit()
|
|
129
|
+
return True
|
|
130
|
+
|
|
131
|
+
except Exception as e:
|
|
132
|
+
session.rollback()
|
|
133
|
+
logger.error(f"Error saving user config for {user_id}: {e}")
|
|
134
|
+
return False
|
|
135
|
+
finally:
|
|
136
|
+
session.close()
|
|
137
|
+
|
|
138
|
+
def get_user_config(self, user_id: str) -> MOSConfig | None:
|
|
139
|
+
"""Get user configuration from database.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
user_id (str): The user ID.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
MOSConfig | None: The user's configuration or None if not found.
|
|
146
|
+
"""
|
|
147
|
+
session = self._get_session()
|
|
148
|
+
try:
|
|
149
|
+
user_config = session.query(UserConfig).filter(UserConfig.user_id == user_id).first()
|
|
150
|
+
|
|
151
|
+
if user_config:
|
|
152
|
+
config_dict = json.loads(user_config.config_data)
|
|
153
|
+
# Convert datetime strings back to datetime objects
|
|
154
|
+
config_dict = self._convert_datetime_strings(config_dict)
|
|
155
|
+
return MOSConfig(**config_dict)
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
except Exception as e:
|
|
159
|
+
logger.error(f"Error loading user config for {user_id}: {e}")
|
|
160
|
+
return None
|
|
161
|
+
finally:
|
|
162
|
+
session.close()
|
|
163
|
+
|
|
164
|
+
def delete_user_config(self, user_id: str) -> bool:
|
|
165
|
+
"""Delete user configuration from database.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
user_id (str): The user ID.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
bool: True if successful, False otherwise.
|
|
172
|
+
"""
|
|
173
|
+
session = self._get_session()
|
|
174
|
+
try:
|
|
175
|
+
user_config = session.query(UserConfig).filter(UserConfig.user_id == user_id).first()
|
|
176
|
+
|
|
177
|
+
if user_config:
|
|
178
|
+
session.delete(user_config)
|
|
179
|
+
session.commit()
|
|
180
|
+
logger.info(f"Deleted configuration for user {user_id}")
|
|
181
|
+
return True
|
|
182
|
+
return False
|
|
183
|
+
|
|
184
|
+
except Exception as e:
|
|
185
|
+
session.rollback()
|
|
186
|
+
logger.error(f"Error deleting user config for {user_id}: {e}")
|
|
187
|
+
return False
|
|
188
|
+
finally:
|
|
189
|
+
session.close()
|
|
190
|
+
|
|
191
|
+
def list_user_configs(self, limit: int = 1) -> dict[str, MOSConfig]:
|
|
192
|
+
"""List all user configurations.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Dict[str, MOSConfig]: Dictionary mapping user_id to MOSConfig.
|
|
196
|
+
"""
|
|
197
|
+
session = self._get_session()
|
|
198
|
+
try:
|
|
199
|
+
user_configs = session.query(UserConfig).limit(limit).all()
|
|
200
|
+
result = {}
|
|
201
|
+
|
|
202
|
+
for user_config in user_configs:
|
|
203
|
+
try:
|
|
204
|
+
config_dict = json.loads(user_config.config_data)
|
|
205
|
+
# Convert datetime strings back to datetime objects
|
|
206
|
+
config_dict = self._convert_datetime_strings(config_dict)
|
|
207
|
+
result[user_config.user_id] = MOSConfig(**config_dict)
|
|
208
|
+
except Exception as e:
|
|
209
|
+
logger.error(f"Error parsing config for user {user_config.user_id}: {e}")
|
|
210
|
+
continue
|
|
211
|
+
|
|
212
|
+
return result
|
|
213
|
+
|
|
214
|
+
except Exception as e:
|
|
215
|
+
logger.error(f"Error listing user configs: {e}")
|
|
216
|
+
return {}
|
|
217
|
+
finally:
|
|
218
|
+
session.close()
|
|
219
|
+
|
|
220
|
+
def create_user_with_config(
|
|
221
|
+
self, user_name: str, config: MOSConfig, role=None, user_id: str | None = None
|
|
222
|
+
) -> str:
|
|
223
|
+
"""Create a new user with configuration.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
user_name (str): Name of the user.
|
|
227
|
+
config (MOSConfig): The user's configuration.
|
|
228
|
+
role: User role (optional, uses default from UserManager).
|
|
229
|
+
user_id (str, optional): Custom user ID.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
str: The created user ID.
|
|
233
|
+
|
|
234
|
+
Raises:
|
|
235
|
+
ValueError: If user_name already exists.
|
|
236
|
+
"""
|
|
237
|
+
# Create user using parent method
|
|
238
|
+
created_user_id = self.create_user(user_name, role, user_id)
|
|
239
|
+
|
|
240
|
+
# Save configuration
|
|
241
|
+
if not self.save_user_config(created_user_id, config):
|
|
242
|
+
logger.error(f"Failed to save configuration for user {created_user_id}")
|
|
243
|
+
|
|
244
|
+
return created_user_id
|
|
245
|
+
|
|
246
|
+
def delete_user(self, user_id: str) -> bool:
|
|
247
|
+
"""Delete a user and their configuration.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
user_id (str): The user ID.
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
bool: True if successful, False otherwise.
|
|
254
|
+
"""
|
|
255
|
+
# Delete configuration first
|
|
256
|
+
self.delete_user_config(user_id)
|
|
257
|
+
|
|
258
|
+
# Delete user using parent method
|
|
259
|
+
return super().delete_user(user_id)
|
|
260
|
+
|
|
261
|
+
def get_user_cube_access(self, user_id: str) -> list[str]:
|
|
262
|
+
"""Get list of cube IDs that a user has access to.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
user_id (str): The user ID.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
list[str]: List of cube IDs the user can access.
|
|
269
|
+
"""
|
|
270
|
+
cubes = self.get_user_cubes(user_id)
|
|
271
|
+
return [cube.cube_id for cube in cubes]
|