refactor(backend): rename OpenFlare directory to lowercase openflare

This commit is contained in:
ryan
2026-08-30 17:43:23 +08:00
parent 06d5fedbfc
commit c93ff6674f
543 changed files with 819 additions and 819 deletions
@@ -0,0 +1,45 @@
// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
// Package apiutil provides HTTP helpers for OpenFlare v1 custom API handlers.
package apiutil
import (
"strconv"
"Wavelet/pkg/response"
"github.com/gin-gonic/gin"
)
const errInvalidParams = "参数错误"
const errInvalidID = "无效的 ID"
// BindJSON binds JSON body; returns false after aborting with 400.
func BindJSON(c *gin.Context, dst any) bool {
if err := c.ShouldBindJSON(dst); err != nil {
response.AbortBadRequest(c, errInvalidParams)
return false
}
return true
}
// IDParam parses :id from the URL path.
func IDParam(c *gin.Context) (uint, bool) {
return NamedIDParam(c, "id")
}
// NamedIDParam parses a named path parameter as a positive uint ID.
func NamedIDParam(c *gin.Context, name string) (uint, bool) {
raw := c.Param(name)
if raw == "" {
response.AbortBadRequest(c, errInvalidID)
return 0, false
}
id64, err := strconv.ParseUint(raw, 10, 64)
if err != nil || id64 == 0 {
response.AbortBadRequest(c, errInvalidID)
return 0, false
}
return uint(id64), true
}
@@ -0,0 +1,35 @@
// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
package apiutil
import (
"errors"
"Wavelet/pkg/response"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// AbortNotFoundIfMissing maps gorm.ErrRecordNotFound to 404; other errors to 400.
func AbortNotFoundIfMissing(c *gin.Context, err error, notFoundMsg string) bool {
if err == nil {
return false
}
if errors.Is(err, gorm.ErrRecordNotFound) {
response.AbortNotFound(c, notFoundMsg)
return true
}
response.AbortBadRequest(c, err.Error())
return true
}
// AbortBadRequestOnError writes a 400 for any non-nil error.
func AbortBadRequestOnError(c *gin.Context, err error) bool {
if err == nil {
return false
}
response.AbortBadRequest(c, err.Error())
return true
}
@@ -0,0 +1,16 @@
// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
package apiutil
import "Wavelet/core/contracts"
// AdminMiddlewares returns Wavelet-standard middlewares for OpenFlare console routes.
// OpenFlare no longer distinguishes Admin vs Root tiers; all management endpoints share
// the same gate: RequireAuth + RequireAdmin from the platform AuthService.
//
// 返回 []any 而非 []gin.HandlerFunc:内核 RouterExtension.Use 收 ...any,
// 而 Go 不允许把 []T 直接展开成 ...any。
func AdminMiddlewares(auth contracts.AuthService) []any {
return []any{auth.RequireAuthMiddleware(), auth.RequireAdminMiddleware()}
}
@@ -0,0 +1,67 @@
// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
package apiutil
import (
"net/http"
"net/http/httptest"
"testing"
"Wavelet/openflare/plugins/server/kernel/testhelper"
"Wavelet/pkg/response"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
func TestAdminMiddlewaresRunsAuthThenAdmin(t *testing.T) {
gin.SetMode(gin.TestMode)
var order []string
auth := sequentialAuth{
auth: func(c *gin.Context) {
order = append(order, "auth")
c.Next()
},
admin: func(c *gin.Context) {
order = append(order, "admin")
c.Next()
},
}
engine := testhelper.NewTestGinEngine()
group := engine.Group("/protected", ginHandlerMiddlewares(AdminMiddlewares(auth)...)...)
group.GET("", func(c *gin.Context) {
c.JSON(http.StatusOK, response.OKNil())
})
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/protected", nil)
engine.ServeHTTP(rec, req)
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, []string{"auth", "admin"}, order)
}
func ginHandlerMiddlewares(middlewares ...any) []gin.HandlerFunc {
handlers := make([]gin.HandlerFunc, 0, len(middlewares))
for _, m := range middlewares {
switch h := m.(type) {
case gin.HandlerFunc:
handlers = append(handlers, h)
case func(*gin.Context):
handlers = append(handlers, gin.HandlerFunc(h))
default:
panic("unexpected middleware type")
}
}
return handlers
}
type sequentialAuth struct {
testhelper.StubAuth
auth, admin gin.HandlerFunc
}
func (s sequentialAuth) RequireAuthMiddleware() any { return s.auth }
func (s sequentialAuth) RequireAdminMiddleware() any { return s.admin }
@@ -0,0 +1,26 @@
// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
package apiutil
import (
"Wavelet/core"
"github.com/gin-gonic/gin"
)
// RegisterCollection registers a collection endpoint on both "" and "/" so requests
// work with or without a trailing slash.
//
// 尾部斜杠变体必须用 HandleRaw 注册:RouterExtension.Handle 会经 cleanPath 归一化
// 掉尾部斜杠,而部署关闭了 gin 的 RedirectTrailingSlash,缺一条即 404。
func RegisterCollection(route core.RouterExtension, method string, handlers ...gin.HandlerFunc) {
hs := make([]any, len(handlers))
for i, h := range handlers {
hs[i] = h
}
route.Handle(method, "", hs...)
if route.BasePath() != "" {
route.HandleRaw(method, "/", hs...)
}
}