diff --git a/superset/initialization/__init__.py b/superset/initialization/__init__.py index 3c5a43751834c..b39bdd53fe16b 100644 --- a/superset/initialization/__init__.py +++ b/superset/initialization/__init__.py @@ -145,7 +145,7 @@ def init_views(self) -> None: from superset.queries.saved_queries.api import SavedQueryRestApi from superset.reports.api import ReportScheduleRestApi from superset.reports.logs.api import ReportExecutionLogRestApi - from superset.security.api import SecurityRestApi + from superset.security.api import SecurityRestApi, UsersApi from superset.views.access_requests import AccessRequestsModelView from superset.views.alerts import AlertView, ReportView from superset.views.annotations import ( @@ -215,6 +215,7 @@ def init_views(self) -> None: appbuilder.add_api(ReportScheduleRestApi) appbuilder.add_api(ReportExecutionLogRestApi) appbuilder.add_api(SavedQueryRestApi) + appbuilder.add_api(UsersApi) # # Setup regular views # diff --git a/superset/security/api.py b/superset/security/api.py index 4eb7ebe660323..83ffd3dd82aba 100644 --- a/superset/security/api.py +++ b/superset/security/api.py @@ -20,16 +20,20 @@ from flask import request, Response from flask_appbuilder import expose from flask_appbuilder.api import BaseApi, safe +from flask_appbuilder.models.sqla.interface import SQLAInterface from flask_appbuilder.security.decorators import permission_name, protect from flask_wtf.csrf import generate_csrf from marshmallow import EXCLUDE, fields, post_load, Schema, ValidationError from marshmallow_enum import EnumField +from superset import security_manager +from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP, RouteMethod from superset.embedded_dashboard.commands.exceptions import ( EmbeddedDashboardNotFoundError, ) from superset.extensions import event_logger from superset.security.guest_token import GuestTokenResourceType +from superset.views.base_api import BaseSupersetModelRestApi logger = logging.getLogger(__name__) @@ -160,3 +164,36 @@ def guest_token(self) -> Response: return self.response_400(message=error.message) except ValidationError as error: return self.response_400(message=error.messages) + + +class UsersApi(BaseSupersetModelRestApi): + datamodel = SQLAInterface(security_manager.user_model) + + resource_name = "users" + allow_browser_login = True + method_permission_name = MODEL_API_RW_METHOD_PERMISSION_MAP + include_route_methods = {RouteMethod.GET_LIST, RouteMethod.GET, RouteMethod.DELETE} + openapi_spec_tag = "Users" + + list_columns = [ + "id", + "first_name", + "last_name", + "username", + "active", + "email", + "last_login", + "login_count", + "fail_login_count", + "roles", + ] + show_columns = list_columns + edit_columns = ["first_name", "last_name", "active", "email"] + add_columns = [ + "first_name", + "last_name", + "username", + "password", + "active", + "email", + ]