Merge pull request #1403 from trheyi/main
Enhance OpenAPI and JSON Parsing Functionality
This commit is contained in:
commit
f6b8dc40fc
4 changed files with 128 additions and 16 deletions
91
openapi/app/app.go
Normal file
91
openapi/app/app.go
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/yaoapp/gou/process"
|
||||||
|
"github.com/yaoapp/yao/openapi/oauth/authorized"
|
||||||
|
"github.com/yaoapp/yao/openapi/oauth/types"
|
||||||
|
"github.com/yaoapp/yao/openapi/response"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Attach attaches the app handlers to the router
|
||||||
|
func Attach(group *gin.RouterGroup, oauth types.OAuth) {
|
||||||
|
// Menu endpoint - requires authentication
|
||||||
|
group.GET("/menu", oauth.Guard, getMenu)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MenuRequest represents the menu request parameters
|
||||||
|
type MenuRequest struct {
|
||||||
|
Locale string `form:"locale" json:"locale"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// getMenu handles GET /app/menu
|
||||||
|
// Returns the application menu based on user permissions and locale
|
||||||
|
func getMenu(c *gin.Context) {
|
||||||
|
var req MenuRequest
|
||||||
|
if err := c.ShouldBindQuery(&req); err != nil {
|
||||||
|
response.RespondWithError(c, http.StatusBadRequest, &response.ErrorResponse{
|
||||||
|
Code: response.ErrInvalidRequest.Code,
|
||||||
|
ErrorDescription: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get authorized info from context (set by oauth.Guard)
|
||||||
|
authInfo := authorized.GetInfo(c)
|
||||||
|
if authInfo == nil {
|
||||||
|
response.RespondWithError(c, http.StatusUnauthorized, &response.ErrorResponse{
|
||||||
|
Code: response.ErrInvalidToken.Code,
|
||||||
|
ErrorDescription: "Authorization required",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call yao.app.Menu process with locale parameter
|
||||||
|
handle, err := process.Of("yao.app.Menu", req.Locale)
|
||||||
|
if err != nil {
|
||||||
|
response.RespondWithError(c, http.StatusBadRequest, &response.ErrorResponse{
|
||||||
|
Code: response.ErrInvalidRequest.Code,
|
||||||
|
ErrorDescription: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set process context
|
||||||
|
handle.WithSID(authInfo.SessionID)
|
||||||
|
|
||||||
|
// Set authorized info for process
|
||||||
|
handle.WithAuthorized(map[string]interface{}{
|
||||||
|
"subject": authInfo.Subject,
|
||||||
|
"client_id": authInfo.ClientID,
|
||||||
|
"user_id": authInfo.UserID,
|
||||||
|
"scope": authInfo.Scope,
|
||||||
|
"team_id": authInfo.TeamID,
|
||||||
|
"tenant_id": authInfo.TenantID,
|
||||||
|
"session_id": authInfo.SessionID,
|
||||||
|
"remember_me": authInfo.RememberMe,
|
||||||
|
"constraints": map[string]interface{}{
|
||||||
|
"owner_only": authInfo.Constraints.OwnerOnly,
|
||||||
|
"creator_only": authInfo.Constraints.CreatorOnly,
|
||||||
|
"editor_only": authInfo.Constraints.EditorOnly,
|
||||||
|
"team_only": authInfo.Constraints.TeamOnly,
|
||||||
|
"extra": authInfo.Constraints.Extra,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Execute the process
|
||||||
|
err = handle.Execute()
|
||||||
|
if err != nil {
|
||||||
|
response.RespondWithError(c, http.StatusInternalServerError, &response.ErrorResponse{
|
||||||
|
Code: response.ErrServerError.Code,
|
||||||
|
ErrorDescription: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer handle.Dispose()
|
||||||
|
|
||||||
|
// Return the menu data
|
||||||
|
response.RespondWithSuccess(c, http.StatusOK, handle.Value())
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/yaoapp/gou/application"
|
"github.com/yaoapp/gou/application"
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
"github.com/yaoapp/yao/openapi/agent"
|
"github.com/yaoapp/yao/openapi/agent"
|
||||||
|
"github.com/yaoapp/yao/openapi/app"
|
||||||
"github.com/yaoapp/yao/openapi/captcha"
|
"github.com/yaoapp/yao/openapi/captcha"
|
||||||
"github.com/yaoapp/yao/openapi/chat"
|
"github.com/yaoapp/yao/openapi/chat"
|
||||||
"github.com/yaoapp/yao/openapi/dsl"
|
"github.com/yaoapp/yao/openapi/dsl"
|
||||||
|
|
@ -150,6 +151,9 @@ func (openapi *OpenAPI) Attach(router *gin.Engine) {
|
||||||
// Trace handlers
|
// Trace handlers
|
||||||
openapiTrace.Attach(group.Group("/trace"), openapi.OAuth)
|
openapiTrace.Attach(group.Group("/trace"), openapi.OAuth)
|
||||||
|
|
||||||
|
// App handlers (menu, etc.)
|
||||||
|
app.Attach(group.Group("/app"), openapi.OAuth)
|
||||||
|
|
||||||
// Custom handlers (Defined by developer)
|
// Custom handlers (Defined by developer)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
32
seed/seed.go
32
seed/seed.go
|
|
@ -572,17 +572,14 @@ func buildColumnTypeMap(mod *model.Model, header []string) []string {
|
||||||
return columnTypes
|
return columnTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseJSONField attempts to parse a value as JSON if the column type is json
|
// parseJSONField attempts to parse a value based on column type
|
||||||
// Returns the parsed JSON object if successful, otherwise returns the original value
|
// For JSON columns: parses JSON string to object
|
||||||
|
// For boolean columns: converts "true"/"false"/"1"/"0" to bool
|
||||||
|
// Returns the parsed value if successful, otherwise returns the original value
|
||||||
func parseJSONField(value interface{}, columnType string) interface{} {
|
func parseJSONField(value interface{}, columnType string) interface{} {
|
||||||
// Check if column type is JSON
|
// Try to parse string value
|
||||||
if columnType != "json" && columnType != "jsonb" {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to parse string value as JSON
|
|
||||||
strValue, ok := value.(string)
|
strValue, ok := value.(string)
|
||||||
if !ok || strValue == "" {
|
if !ok {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -592,6 +589,19 @@ func parseJSONField(value interface{}, columnType string) interface{} {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle boolean type
|
||||||
|
if columnType == "boolean" || columnType == "bool" {
|
||||||
|
switch strings.ToLower(strValue) {
|
||||||
|
case "true", "1", "yes":
|
||||||
|
return true
|
||||||
|
case "false", "0", "no":
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle JSON type
|
||||||
|
if columnType == "json" || columnType == "jsonb" {
|
||||||
// Try to parse as JSON
|
// Try to parse as JSON
|
||||||
var jsonValue interface{}
|
var jsonValue interface{}
|
||||||
if err := json.Unmarshal([]byte(strValue), &jsonValue); err != nil {
|
if err := json.Unmarshal([]byte(strValue), &jsonValue); err != nil {
|
||||||
|
|
@ -599,10 +609,12 @@ func parseJSONField(value interface{}, columnType string) interface{} {
|
||||||
// Don't log error as this is expected for non-JSON strings
|
// Don't log error as this is expected for non-JSON strings
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsonValue
|
return jsonValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
// sortColumns sorts column names alphabetically for consistent ordering
|
// sortColumns sorts column names alphabetically for consistent ordering
|
||||||
func sortColumns(columns []string) {
|
func sortColumns(columns []string) {
|
||||||
// Simple bubble sort for small arrays
|
// Simple bubble sort for small arrays
|
||||||
|
|
|
||||||
|
|
@ -396,7 +396,12 @@ func processMenu(p *process.Process) interface{} {
|
||||||
exception.New(err.Error(), 400).Throw()
|
exception.New(err.Error(), 400).Throw()
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handle.WithGlobal(p.Global).WithSID(p.Sid).Execute()
|
handle.WithGlobal(p.Global).WithSID(p.Sid)
|
||||||
|
if p.Authorized != nil {
|
||||||
|
handle = handle.WithAuthorized(p.Authorized)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = handle.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exception.New(err.Error(), 500).Throw()
|
exception.New(err.Error(), 500).Throw()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue