From 538f76e3172f63f3d18e0aa489fb36a612e1a488 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 29 Oct 2025 15:32:36 +0800 Subject: [PATCH] Add features query endpoint to user API - Introduced a new endpoint `GET /features` to allow authenticated users to query available features. - This addition enhances the user experience by providing access to feature-related information directly through the API. --- openapi/user/features.go | 55 ++++++++++++++++++++++++++++++++++++++++ openapi/user/user.go | 3 +++ 2 files changed, 58 insertions(+) create mode 100644 openapi/user/features.go diff --git a/openapi/user/features.go b/openapi/user/features.go new file mode 100644 index 00000000..9150a372 --- /dev/null +++ b/openapi/user/features.go @@ -0,0 +1,55 @@ +package user + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/yaoapp/kun/log" + "github.com/yaoapp/yao/openapi/oauth/acl" + "github.com/yaoapp/yao/openapi/oauth/authorized" + "github.com/yaoapp/yao/openapi/response" +) + +// GinFeatures handles GET /user/features - Get features for the current user +// Supports optional domain filtering via query parameter: ?domain=user/team +func GinFeatures(c *gin.Context) { + // Get authorized user info + authInfo := authorized.GetInfo(c) + if authInfo == nil || authInfo.UserID == "" { + errorResp := &response.ErrorResponse{ + Code: response.ErrInvalidClient.Code, + ErrorDescription: "User not authenticated", + } + response.RespondWithError(c, response.StatusUnauthorized, errorResp) + return + } + + // Parse query parameters for optional domain filtering + domain := c.Query("domain") + + // Get features from ACL + var features map[string]bool + var err error + + if domain != "" { + // Get features filtered by domain + features, err = acl.GetFeaturesByDomain(c, domain) + } else { + // Get all features + features, err = acl.GetFeatures(c) + } + + if err != nil { + log.Error("Failed to get user features: %v", err) + errorResp := &response.ErrorResponse{ + Code: response.ErrServerError.Code, + ErrorDescription: "Failed to retrieve user features", + } + response.RespondWithError(c, response.StatusInternalServerError, errorResp) + return + } + + // Return features map directly for O(1) frontend lookups + // Frontend can check: if (features["profile:write"]) { ... } + response.RespondWithSuccess(c, http.StatusOK, features) +} diff --git a/openapi/user/user.go b/openapi/user/user.go index cfb60776..1b7f00d8 100644 --- a/openapi/user/user.go +++ b/openapi/user/user.go @@ -100,6 +100,9 @@ func Attach(group *gin.RouterGroup, oauth types.OAuth) { group.POST("/entry/otp", oauth.Guard, GinSendOTP) // Send OTP group.POST("/logout", oauth.Guard, GinLogout) // User logout + // Features query endpoint + group.GET("/features", oauth.Guard, GinFeatures) + // Logined User Settings attachProfile(group, oauth) // User profile management attachPreferences(group, oauth) // User preferences management