ppt-tool/backend/utils/dict_utils.py
Vadym Samoilenko cf21ba4516 Phase 1-2: Foundation + Admin Panel & Client Management
Phase 1 (Foundation):
- Project restructure (presenton-main → backend/ + frontend/)
- Database schema (8 new models, Alembic config, seed script)
- Auth (Azure AD SSO + dev bypass, JWT sessions, AuthMiddleware)
- RBAC (access_service, rbac_middleware, admin routers)
- Audit logging (fire-and-forget, AuditMiddleware, admin router)
- i18n (react-i18next with 5 namespace files)

Phase 2 (Admin Panel & Client Management):
- Admin panel shell (sidebar layout, role guard, 12 pages)
- Redux admin slice with 18 async thunks
- User management (role changes, deactivation)
- Client management (CRUD, brand config, team management)
- Brand config editor (colors, fonts, logos, voice rules)
- Master deck upload & parser (PPTX → HTML → React pipeline)
- Audit log viewer with filters and CSV/JSON export

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 15:37:17 +00:00

89 lines
3.1 KiB
Python

from typing import List
from models.json_path_guide import JsonPathGuide, DictGuide, ListGuide
def get_dict_paths_with_key(data: dict, key: str) -> List[JsonPathGuide]:
result = []
def _find_paths(obj, current_path: List[DictGuide | ListGuide]):
if isinstance(obj, dict):
if key in obj:
result.append(JsonPathGuide(guides=current_path.copy()))
for k, v in obj.items():
new_path = current_path + [DictGuide(key=k)]
_find_paths(v, new_path)
elif isinstance(obj, list):
for i, item in enumerate(obj):
new_path = current_path + [ListGuide(index=i)]
_find_paths(item, new_path)
_find_paths(data, [])
return result
def get_dict_at_path(data: dict, path: JsonPathGuide) -> dict:
current = data
for guide in path.guides:
if isinstance(guide, DictGuide):
current = current[guide.key]
elif isinstance(guide, ListGuide):
current = current[guide.index]
return current
def set_dict_at_path(data: dict, path: JsonPathGuide, value: dict):
current = data
for guide in path.guides[:-1]:
if isinstance(guide, DictGuide):
current = current[guide.key]
elif isinstance(guide, ListGuide):
current = current[guide.index]
if path.guides:
final_guide = path.guides[-1]
if isinstance(final_guide, DictGuide):
current[final_guide.key] = value
elif isinstance(final_guide, ListGuide):
current[final_guide.index] = value
def deep_update(original: dict, updates: dict) -> dict:
for key, value in updates.items():
if key in original:
if isinstance(original[key], dict) and isinstance(value, dict):
deep_update(original[key], value)
elif isinstance(original[key], list) and isinstance(value, list):
if len(value) == 0:
continue
elif len(value) == 1 and isinstance(value[0], dict):
if len(original[key]) > 0 and isinstance(original[key][0], dict):
deep_update(original[key][0], value[0])
else:
original[key][0] = (
value[0] if len(original[key]) > 0 else value[0]
)
else:
min_length = min(len(original[key]), len(value))
for i in range(min_length):
if isinstance(original[key][i], dict) and isinstance(
value[i], dict
):
deep_update(original[key][i], value[i])
else:
original[key][i] = value[i]
elif not isinstance(value, (dict, list)):
original[key] = value
else:
if not isinstance(value, (dict, list)):
original[key] = value
return original
def has_more_than_n_keys(obj: dict[str, object], n: int) -> bool:
i = 0
for _ in obj.keys():
i += 1
if i > n:
return True
return False