209 lines
5.9 KiB
Python
209 lines
5.9 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, Field
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
from paths import DATA_DIR, EXTENSION_DIR, ROOT_DIR, get_dates_file_path, get_env_files
|
|
from services.settings_store import load_overrides, save_overrides
|
|
|
|
CONFIGURABLE_FIELDS = [
|
|
"gitlab_url",
|
|
"gitlab_token",
|
|
"gitlab_project_path",
|
|
"gitlab_board_id",
|
|
"gitlab_board_labels",
|
|
"gitlab_milestone_title",
|
|
"pts_url",
|
|
"pts_project_name",
|
|
"pts_default_task_name",
|
|
"auto_fill_enabled",
|
|
"auto_fill_hour",
|
|
"auto_fill_minute",
|
|
"max_hours_per_day",
|
|
"hour_step",
|
|
"xai_api_key",
|
|
"xai_base_url",
|
|
"grok_model",
|
|
"use_llm",
|
|
"use_description_variation",
|
|
"pts_username",
|
|
"pts_password",
|
|
"teams_username",
|
|
"teams_password",
|
|
"teams_calendar_enabled",
|
|
"teams_calendar_timezone",
|
|
"teams_meeting_task_name",
|
|
"teams_headless",
|
|
"teams_meeting_exclude_keywords",
|
|
# CompBase attendance punch (independent of PTS)
|
|
"compbase_list_url",
|
|
"compbase_fill_url",
|
|
"compbase_username",
|
|
"compbase_password",
|
|
"compbase_default_days",
|
|
"compbase_out_time_mode",
|
|
# legacy Graph fields kept for backward-compatible settings files
|
|
"azure_client_id",
|
|
"azure_tenant_id",
|
|
]
|
|
|
|
|
|
class EnvSettings(BaseSettings):
|
|
model_config = SettingsConfigDict(
|
|
env_file=get_env_files() or None,
|
|
env_file_encoding="utf-8",
|
|
extra="ignore",
|
|
)
|
|
|
|
gitlab_url: str = "https://gitlab.supermicro.com"
|
|
gitlab_token: str = ""
|
|
gitlab_project_path: str = "super-cloud/scc-flex"
|
|
gitlab_board_id: int = 1126
|
|
gitlab_board_labels: str = "Category::BugFix,Type::Bug"
|
|
gitlab_milestone_title: str = ""
|
|
|
|
pts_url: str = "https://tw-timesheet.supermicro.com/PTS"
|
|
pts_project_name: str = "SuperCloud Composer"
|
|
pts_default_task_name: str = "Implement"
|
|
pts_username: str = ""
|
|
pts_password: str = ""
|
|
|
|
auto_fill_enabled: bool = True
|
|
auto_fill_hour: int = 18
|
|
auto_fill_minute: int = 0
|
|
|
|
backend_host: str = "0.0.0.0"
|
|
backend_port: int = 8765
|
|
|
|
max_hours_per_day: float = 8.0
|
|
hour_step: float = 0.5
|
|
|
|
xai_api_key: str = ""
|
|
xai_base_url: str = "https://api.x.ai"
|
|
grok_model: str = "grok-3-mini"
|
|
use_llm: bool = True
|
|
use_description_variation: bool = True
|
|
|
|
teams_calendar_enabled: bool = False
|
|
teams_username: str = ""
|
|
teams_password: str = ""
|
|
teams_calendar_timezone: str = "Asia/Taipei"
|
|
teams_meeting_task_name: str = "Meeting"
|
|
teams_headless: bool = False
|
|
teams_meeting_exclude_keywords: str = "貼心的提醒,請記得下班刷退"
|
|
azure_client_id: str = ""
|
|
azure_tenant_id: str = "organizations"
|
|
|
|
compbase_list_url: str = "http://tw-compbase.supermicro.com:6699"
|
|
compbase_fill_url: str = "http://tw-compbase.supermicro.com:6671"
|
|
compbase_username: str = ""
|
|
compbase_password: str = ""
|
|
compbase_default_days: int = 14
|
|
compbase_out_time_mode: str = "expected"
|
|
|
|
|
|
class AppSettings(BaseModel):
|
|
gitlab_url: str = "https://gitlab.supermicro.com"
|
|
gitlab_token: str = ""
|
|
gitlab_project_path: str = "super-cloud/scc-flex"
|
|
gitlab_board_id: int = 1126
|
|
gitlab_board_labels: str = "Category::BugFix,Type::Bug"
|
|
gitlab_milestone_title: str = ""
|
|
|
|
pts_url: str = "https://tw-timesheet.supermicro.com/PTS"
|
|
pts_project_name: str = "SuperCloud Composer"
|
|
pts_default_task_name: str = "Implement"
|
|
pts_username: str = ""
|
|
pts_password: str = ""
|
|
|
|
auto_fill_enabled: bool = True
|
|
auto_fill_hour: int = 18
|
|
auto_fill_minute: int = 0
|
|
|
|
backend_host: str = "0.0.0.0"
|
|
backend_port: int = 8765
|
|
|
|
max_hours_per_day: float = 8.0
|
|
hour_step: float = 0.5
|
|
|
|
xai_api_key: str = ""
|
|
xai_base_url: str = "https://api.x.ai"
|
|
grok_model: str = "grok-3-mini"
|
|
use_llm: bool = True
|
|
use_description_variation: bool = True
|
|
|
|
teams_calendar_enabled: bool = False
|
|
teams_username: str = ""
|
|
teams_password: str = ""
|
|
teams_calendar_timezone: str = "Asia/Taipei"
|
|
teams_meeting_task_name: str = "Meeting"
|
|
teams_headless: bool = False
|
|
teams_meeting_exclude_keywords: str = "貼心的提醒,請記得下班刷退"
|
|
azure_client_id: str = ""
|
|
azure_tenant_id: str = "organizations"
|
|
|
|
compbase_list_url: str = "http://tw-compbase.supermicro.com:6699"
|
|
compbase_fill_url: str = "http://tw-compbase.supermicro.com:6671"
|
|
compbase_username: str = ""
|
|
compbase_password: str = ""
|
|
compbase_default_days: int = 14
|
|
compbase_out_time_mode: str = "expected"
|
|
|
|
@property
|
|
def teams_meeting_exclude_keyword_list(self) -> list[str]:
|
|
return [part.strip() for part in self.teams_meeting_exclude_keywords.split(",") if part.strip()]
|
|
|
|
@property
|
|
def gitlab_board_label_list(self) -> list[str]:
|
|
return [part.strip() for part in self.gitlab_board_labels.split(",") if part.strip()]
|
|
|
|
|
|
_env = EnvSettings()
|
|
|
|
|
|
def build_settings() -> AppSettings:
|
|
data = _env.model_dump()
|
|
overrides = load_overrides()
|
|
for key in CONFIGURABLE_FIELDS:
|
|
if key in overrides and overrides[key] is not None:
|
|
data[key] = overrides[key]
|
|
return AppSettings(**data)
|
|
|
|
|
|
def get_settings_dict() -> dict[str, Any]:
|
|
return build_settings().model_dump()
|
|
|
|
|
|
def update_settings(updates: dict[str, Any]) -> AppSettings:
|
|
current = load_overrides()
|
|
merged = {**current}
|
|
for key in CONFIGURABLE_FIELDS:
|
|
if key not in updates:
|
|
continue
|
|
value = updates[key]
|
|
if value is not None:
|
|
merged[key] = value
|
|
save_overrides(merged)
|
|
return reload_settings()
|
|
|
|
|
|
def reload_settings() -> AppSettings:
|
|
global _runtime
|
|
_runtime = build_settings()
|
|
return _runtime
|
|
|
|
|
|
_runtime = build_settings()
|
|
|
|
|
|
class SettingsProxy:
|
|
def __getattr__(self, name: str) -> Any:
|
|
return getattr(_runtime, name)
|
|
|
|
def __repr__(self) -> str:
|
|
return f"SettingsProxy({_runtime!r})"
|
|
|
|
|
|
settings = SettingsProxy() |