from __future__ import annotations from pathlib import Path from flask import current_app from app.extensions import db from app.models.setting import AppSetting from app.services.company_service import CompanyService class SettingsService: @staticmethod def _user_scope_key(key: str, user_id=None): from flask_login import current_user if user_id is None and getattr(current_user, 'is_authenticated', False): user_id = current_user.id return f'user.{user_id}.{key}' if user_id else key @staticmethod def _scope_key(key: str, company_id=None): if company_id is None: company = CompanyService.get_current_company() company_id = company.id if company else None return f'company.{company_id}.{key}' if company_id else key @staticmethod def get(key, default=None, company_id=None): scoped = AppSetting.get(SettingsService._scope_key(key, company_id), default=None) if scoped is not None: return scoped return AppSetting.get(key, default=default) @staticmethod def get_secret(key, default=None, company_id=None): scoped = AppSetting.get(SettingsService._scope_key(key, company_id), default=None, decrypt=True) if scoped is not None: return scoped return AppSetting.get(key, default=default, decrypt=True) @staticmethod def set_many(mapping: dict[str, tuple[object, bool] | object], company_id=None): for key, value in mapping.items(): if isinstance(value, tuple): raw, encrypt = value else: raw, encrypt = value, False AppSetting.set(SettingsService._scope_key(key, company_id), raw, encrypt=encrypt) db.session.commit() @staticmethod def storage_path(key: str, fallback: Path): value = SettingsService.get(key) if value: path = Path(value) if not path.is_absolute(): path = Path(current_app.root_path).parent / path path.mkdir(parents=True, exist_ok=True) return path fallback.mkdir(parents=True, exist_ok=True) return fallback @staticmethod def read_only_enabled(company_id=None) -> bool: from flask_login import current_user company = CompanyService.get_current_company() cid = company_id or (company.id if company else None) truly_global_ro = AppSetting.get('app.read_only_mode', 'false') == 'true' company_ro = AppSetting.get(f'company.{cid}.app.read_only_mode', 'false') == 'true' if cid else False user_ro = getattr(current_user, 'is_authenticated', False) and cid and current_user.is_company_readonly(cid) return truly_global_ro or company_ro or bool(user_ro) @staticmethod def get_user(key, default=None, user_id=None): return AppSetting.get(SettingsService._user_scope_key(key, user_id), default=default) @staticmethod def get_user_secret(key, default=None, user_id=None): return AppSetting.get(SettingsService._user_scope_key(key, user_id), default=default, decrypt=True) @staticmethod def set_many_user(mapping: dict[str, tuple[object, bool] | object], user_id=None): for key, value in mapping.items(): if isinstance(value, tuple): raw, encrypt = value else: raw, encrypt = value, False AppSetting.set(SettingsService._user_scope_key(key, user_id), raw, encrypt=encrypt) db.session.commit() @staticmethod def get_preference(scope_name: str, default='global', user_id=None): return AppSetting.get(SettingsService._user_scope_key(f'pref.{scope_name}.mode', user_id), default=default) @staticmethod def set_preference(scope_name: str, mode: str, user_id=None): AppSetting.set(SettingsService._user_scope_key(f'pref.{scope_name}.mode', user_id), mode) db.session.commit() @staticmethod def get_effective(key, default=None, company_id=None, user_id=None, scope_name=None, user_default='global'): scope_name = scope_name or key.split('.', 1)[0] mode = SettingsService.get_preference(scope_name, default=user_default, user_id=user_id) if mode == 'user': value = SettingsService.get_user(key, default=None, user_id=user_id) if value not in [None, '']: return value return SettingsService.get(key, default=default, company_id=company_id) @staticmethod def get_effective_secret(key, default=None, company_id=None, user_id=None, scope_name=None, user_default='global'): scope_name = scope_name or key.split('.', 1)[0] mode = SettingsService.get_preference(scope_name, default=user_default, user_id=user_id) if mode == 'user': value = SettingsService.get_user_secret(key, default=None, user_id=user_id) if value not in [None, '']: return value return SettingsService.get_secret(key, default=default, company_id=company_id)