# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """Reusable helpers for syncing Subject rows from User/Role/Group models.""" from __future__ import annotations import logging from typing import Any from superset.daos.subject import SubjectDAO from superset.subjects.types import SubjectType from superset.subjects.utils import get_user_label logger = logging.getLogger(__name__) def sync_user_subject(user: Any) -> None: """Create or update the Subject row for a User.""" if not user or not getattr(user, "id", None): return subject = SubjectDAO.find_one_or_none(user_id=user.id) if subject: subject.label = get_user_label(user) subject.secondary_label = getattr(user, "email", None) subject.extra_search = getattr(user, "email", None) subject.active = getattr(user, "active", True) else: SubjectDAO.create( attributes={ "label": get_user_label(user), "secondary_label": getattr(user, "email", None), "extra_search": getattr(user, "email", None), "active": getattr(user, "active", True), "type": SubjectType.USER, "user_id": user.id, } ) logger.debug("Created Subject for user %s (id=%s)", user.username, user.id) def sync_role_subject(role: Any) -> None: """Create or update the Subject row for a Role.""" if not role or not getattr(role, "id", None): return subject = SubjectDAO.find_one_or_none(role_id=role.id) if subject: subject.label = role.name else: SubjectDAO.create( attributes={ "label": role.name, "active": True, "type": SubjectType.ROLE, "role_id": role.id, } ) logger.debug("Created Subject for role %s (id=%s)", role.name, role.id) def _group_subject_fields(group: Any) -> tuple[str, str | None, str | None]: """Compute label, secondary_label, and extra_search for a group Subject. Rules: - Only name provided → label=name, secondary_label=None - name + label (different) → label=label, secondary_label=name - name + label (identical) → label=label, secondary_label=None - name + label + description → label=label, secondary_label=description """ name = group.name group_label = getattr(group, "label", None) description = getattr(group, "description", None) if group_label and group_label != name: label = group_label if description: secondary_label = description else: secondary_label = name else: label = name secondary_label = description if description else None extra_search = name if group_label and group_label != name else None return label, secondary_label, extra_search def sync_group_subject(group: Any) -> None: """Create or update the Subject row for a Group.""" if not group or not getattr(group, "id", None): return subject = SubjectDAO.find_one_or_none(group_id=group.id) label, secondary_label, extra_search = _group_subject_fields(group) if subject: subject.label = label subject.secondary_label = secondary_label subject.extra_search = extra_search else: SubjectDAO.create( attributes={ "label": label, "secondary_label": secondary_label, "extra_search": extra_search, "active": True, "type": SubjectType.GROUP, "group_id": group.id, } ) logger.debug("Created Subject for group %s (id=%s)", group.name, group.id) def delete_user_subject(user_id: int) -> None: """Delete the Subject row for a User.""" if subject := SubjectDAO.find_one_or_none(user_id=user_id): SubjectDAO.delete([subject]) logger.debug("Deleted Subject for user id=%s", user_id) def delete_role_subject(role_id: int) -> None: """Delete the Subject row for a Role.""" if subject := SubjectDAO.find_one_or_none(role_id=role_id): SubjectDAO.delete([subject]) logger.debug("Deleted Subject for role id=%s", role_id) def delete_group_subject(group_id: int) -> None: """Delete the Subject row for a Group.""" if subject := SubjectDAO.find_one_or_none(group_id=group_id): SubjectDAO.delete([subject]) logger.debug("Deleted Subject for group id=%s", group_id)