{render_html5_access_publish_plan(project_id=project_id, profile=_DictProfile(profile), plan=plan)}
"""
def render_html5_access_user_detail(*, project_id: str, user_payload: dict | None) -> str:
if user_payload is None:
return """
Выберите пользователя, чтобы увидеть группы и эффективные роли.
"""
user = dict(user_payload.get("user") or {})
roles = list(user_payload.get("effective_roles") or [])
groups = list(user.get("groups") or [])
name = str(user.get("name") or "")
full_name = str(user.get("full_name") or "")
return f"""
{''.join(_role_card(_DictRole(item)) for item in roles) or '
Эффективные роли не найдены
'}
"""
def render_html5_access_profile(*, project_id: str, profile: object | None) -> str:
if profile is None:
return """
Выберите профиль доступаПлан публикации и dry-run будут построены сервером по данным нормализованного объекта 1С.
"""
roles = list(getattr(profile, "roles", []) or [])
attrs = dict(getattr(profile, "attributes", {}) or {})
target_objects = list(attrs.get("target_objects") or [])
permissions = list(attrs.get("permissions") or [])
profile_name = _profile_name(profile)
return f"""
{escape(profile_name)}
{escape(str(getattr(profile, "qualified_name", "") or ""))}
" for item in warnings)
dry_run_button = (
f"""
"""
if ready
else '
План не готов к отправке в расширение
'
)
return f"""
План публикации
{'готов' if ready else 'требует проверки'}{len(operations)} операций
{dry_run_button}
{warning_html}
{''.join(_operation_card(item) for item in operations) or '
Операций нет
'}
"""
def render_html5_access_publish_result(*, project_id: str, result: object | None) -> str:
if result is None:
return '
Ответ расширения
Dry-run еще не выполнялся
'
checks = list(getattr(result, "checks", []) or [])
payload = dict(getattr(result, "result", {}) or {})
status = str(getattr(result, "status", ""))
ready = bool(getattr(result, "ready", False))
return f"""
Ответ расширения
{escape(status)}{'расширение ответило' if ready else 'требуется настройка публикации'}
{''.join(_check_card(item) for item in checks)}
{escape(_short_json(payload))}
"""
def _selected_profile(profiles: list[object], selected_profile: str | None) -> object | None:
if not profiles:
return None
if not selected_profile:
return profiles[0]
wanted = selected_profile.casefold()
return next(
(
item
for item in profiles
if _profile_name(item).casefold() == wanted
or str(getattr(item, "qualified_name", "") or "").casefold() == wanted
),
profiles[0],
)
def _profile_link(project_id: str, profile: object, selected: object | None) -> str:
name = _profile_name(profile)
active = selected is profile
roles = list(getattr(profile, "roles", []) or [])
return f"""
{escape(name)}
{len(roles)} ролей
"""
def _profile_name(profile: object) -> str:
return str(getattr(profile, "name", None) or getattr(profile, "qualified_name", None) or "Профиль")
def _role_card(role: object) -> str:
name = str(getattr(role, "role_qualified_name", None) or getattr(role, "role", None) or role)
source = str(getattr(role, "source", "") or "")
return f'{escape(name)}{escape(source)}'
def _group_card(group: object) -> str:
name = str(getattr(group, "name", ""))
profile = str(getattr(group, "profile_qualified_name", None) or getattr(group, "profile", None) or "без профиля")
users = list(getattr(group, "users", []) or [])
return f'{escape(name)}{escape(profile)} · {len(users)} пользователей'
def _user_card(project_id: str, user: object) -> str:
name = str(getattr(user, "name", ""))
full_name = str(getattr(user, "full_name", "") or "")
groups = list(getattr(user, "groups", []) or [])
return f"""
{escape(name)}
{escape(full_name)} · {len(groups)} групп
"""
def _operation_card(operation: dict) -> str:
action = str(operation.get("action", "operation"))
target = str(operation.get("target", ""))
detail = str(operation.get("role") or operation.get("profile") or operation.get("name") or "")
return f'{escape(action)}{escape(target)} {escape(detail)}'
def _check_card(check: object) -> str:
code = str(getattr(check, "code", ""))
status = str(getattr(check, "status", ""))
message = str(getattr(check, "message", ""))
return f'{escape(code)} · {escape(status)}{escape(message)}'
def _notice_list(title: str, values: list[object]) -> str:
if not values:
return ""
return f"""
{escape(title)}
{''.join(f'
{escape(str(item))}
' for item in values)}
"""
def _assignment_count(profiles: list[object], groups: list[object], users: list[object]) -> int:
return (
sum(len(getattr(item, "roles", []) or []) for item in profiles)
+ sum(len(getattr(item, "roles", []) or []) + len(getattr(item, "users", []) or []) for item in groups)
+ sum(len(getattr(item, "roles", []) or []) + len(getattr(item, "groups", []) or []) for item in users)
)
def _short_json(payload: dict) -> str:
if not payload:
return "{}"
return json.dumps({key: value for key, value in list(payload.items())[:12]}, ensure_ascii=False, indent=2, default=str)
class _DictProfile:
def __init__(self, payload: dict):
self.name = str(payload.get("name") or "")
self.qualified_name = str(payload.get("qualified_name") or self.name)
self.roles = payload.get("roles") or []
self.attributes = payload.get("attributes") or {}
self.source = payload.get("source") or "workspace"
class _DictRole:
def __init__(self, payload: dict):
self.role = str(payload.get("role") or payload.get("name") or "")
self.role_qualified_name = str(payload.get("role_qualified_name") or payload.get("qualified_name") or self.role)
self.source = str(payload.get("source") or "")