fix: swagger

This commit is contained in:
2025-12-16 17:11:49 +08:00
parent 0e303e8a5c
commit 9bc2155008
16 changed files with 998 additions and 704 deletions

View File

@@ -1,207 +0,0 @@
package api
import (
"strconv"
"strings"
"quyun/v2/app/errorx"
"quyun/v2/app/tenancy"
"github.com/gofiber/fiber/v3"
)
// @provider
type ApiController struct{}
type PostsQuery struct {
Page int `query:"page"`
Limit int `query:"limit"`
Keyword string `query:"keyword"`
}
type UpdateUsernameReq struct {
Username string `json:"username"`
}
// WeChatOAuthStart
//
// @Router /v1/auth/wechat [get]
func (a *ApiController) WeChatOAuthStart(ctx fiber.Ctx) error {
return ctx.Status(fiber.StatusNotImplemented).JSON(fiber.Map{"ok": false, "todo": "wechat oauth: /auth/wechat"})
}
// WeChatOAuthCallback
//
// @Router /v1/auth/login [get]
func (a *ApiController) WeChatOAuthCallback(ctx fiber.Ctx) error {
return ctx.Status(fiber.StatusNotImplemented).JSON(fiber.Map{"ok": false, "todo": "wechat oauth: /auth/login"})
}
// ListPosts
//
// @Router /v1/posts [get]
// @Bind query query
func (a *ApiController) ListPosts(ctx fiber.Ctx, query *PostsQuery) error {
page := 1
limit := 10
if query != nil {
if query.Page > 0 {
page = query.Page
}
if query.Limit > 0 {
limit = query.Limit
}
}
return ctx.JSON(fiber.Map{
"items": []any{},
"total": 0,
"page": page,
"limit": limit,
})
}
// ShowPost
//
// @Router /v1/posts/:id/show [get]
// @Bind id path
func (a *ApiController) ShowPost(ctx fiber.Ctx, id int) error {
if id <= 0 {
return errorx.ErrInvalidParameter.WithMsg("invalid id")
}
return fiber.ErrNotFound
}
// PlayPost
//
// @Router /v1/posts/:id/play [get]
// @Bind id path
func (a *ApiController) PlayPost(ctx fiber.Ctx, id int) error {
if id <= 0 {
return errorx.ErrInvalidParameter.WithMsg("invalid id")
}
return ctx.Status(fiber.StatusNotImplemented).JSON(fiber.Map{"ok": false, "todo": "post play"})
}
// MinePosts
//
// @Router /v1/posts/mine [get]
// @Bind query query
func (a *ApiController) MinePosts(ctx fiber.Ctx, query *PostsQuery) error {
page := 1
limit := 10
if query != nil {
if query.Page > 0 {
page = query.Page
}
if query.Limit > 0 {
limit = query.Limit
}
}
return ctx.JSON(fiber.Map{
"items": []any{},
"total": 0,
"page": page,
"limit": limit,
})
}
// BuyPost
//
// @Router /v1/posts/:id/buy [post]
// @Bind id path
func (a *ApiController) BuyPost(ctx fiber.Ctx, id int) error {
if id <= 0 {
return errorx.ErrInvalidParameter.WithMsg("invalid id")
}
return ctx.Status(fiber.StatusNotImplemented).JSON(fiber.Map{"ok": false, "todo": "post buy"})
}
// UserProfile
//
// @Router /v1/users/profile [get]
func (a *ApiController) UserProfile(ctx fiber.Ctx) error {
tenantCode := ctx.Locals(tenancy.LocalTenantCode)
return ctx.JSON(fiber.Map{
"id": 0,
"created_at": "1970-01-01T00:00:00Z",
"username": "",
"avatar": "",
"balance": 0,
"tenant": tenantCode,
})
}
// UpdateUsername
//
// @Router /v1/users/username [put]
// @Bind req body
func (a *ApiController) UpdateUsername(ctx fiber.Ctx, req *UpdateUsernameReq) error {
if req == nil {
return errorx.ErrInvalidJSON
}
name := strings.TrimSpace(req.Username)
if name == "" {
return errorx.ErrDataValidationFail.WithMsg("username required")
}
if len([]rune(name)) > 12 {
return errorx.ErrDataValidationFail.WithMsg("username too long")
}
return ctx.JSON(fiber.Map{"ok": true})
}
// WechatJSSDK
//
// @Router /v1/wechats/js-sdk [get]
func (a *ApiController) WechatJSSDK(ctx fiber.Ctx) error {
return ctx.Status(fiber.StatusNotImplemented).JSON(fiber.Map{"ok": false, "todo": "wechat js-sdk"})
}
// AdminAuth (stub)
//
// @Router /v1/admin/auth [post]
func (a *ApiController) AdminAuth(ctx fiber.Ctx) error {
return ctx.Status(fiber.StatusNotImplemented).JSON(fiber.Map{"ok": false, "todo": "admin auth"})
}
// AdminStatistics (stub)
//
// @Router /v1/admin/statistics [get]
func (a *ApiController) AdminStatistics(ctx fiber.Ctx) error {
return ctx.Status(fiber.StatusNotImplemented).JSON(fiber.Map{"ok": false, "todo": "admin statistics"})
}
// AdminOrders (stub)
//
// @Router /v1/admin/orders [get]
func (a *ApiController) AdminOrders(ctx fiber.Ctx) error {
return ctx.Status(fiber.StatusNotImplemented).JSON(fiber.Map{"ok": false, "todo": "admin orders list"})
}
// AdminOrderRefund (stub)
//
// @Router /v1/admin/orders/:id/refund [post]
// @Bind id path
func (a *ApiController) AdminOrderRefund(ctx fiber.Ctx, id int) error {
if id <= 0 {
return errorx.ErrInvalidParameter.WithMsg("invalid id")
}
return ctx.Status(fiber.StatusNotImplemented).JSON(fiber.Map{"ok": false, "todo": "admin orders refund"})
}
// AdminMedias (stub)
//
// @Router /v1/admin/medias [get]
func (a *ApiController) AdminMedias(ctx fiber.Ctx) error {
return ctx.Status(fiber.StatusNotImplemented).JSON(fiber.Map{"ok": false, "todo": "admin medias list"})
}
// AdminMediaShow (stub)
//
// @Router /v1/admin/medias/:id [get]
func (a *ApiController) AdminMediaShow(ctx fiber.Ctx) error {
_, err := strconv.ParseInt(ctx.Params("id"), 10, 64)
if err != nil {
return errorx.ErrInvalidParameter.WithMsg("invalid id")
}
return ctx.Status(fiber.StatusNotImplemented).JSON(fiber.Map{"ok": false, "todo": "admin medias show"})
}

View File

@@ -1,33 +0,0 @@
package api
import (
"go.ipao.vip/atom"
"go.ipao.vip/atom/container"
"go.ipao.vip/atom/contracts"
"go.ipao.vip/atom/opt"
)
func Provide(opts ...opt.Option) error {
if err := container.Container.Provide(func() (*ApiController, error) {
obj := &ApiController{}
return obj, nil
}); err != nil {
return err
}
if err := container.Container.Provide(func(
apiController *ApiController,
) (contracts.HttpRoute, error) {
obj := &Routes{
apiController: apiController,
}
if err := obj.Prepare(); err != nil {
return nil, err
}
return obj, nil
}, atom.GroupRoutes); err != nil {
return err
}
return nil
}

View File

@@ -1,114 +0,0 @@
// Code generated by atomctl. DO NOT EDIT.
// Package api provides HTTP route definitions and registration
// for the quyun/v2 application.
package api
import (
"github.com/gofiber/fiber/v3"
log "github.com/sirupsen/logrus"
_ "go.ipao.vip/atom"
_ "go.ipao.vip/atom/contracts"
. "go.ipao.vip/atom/fen"
)
// Routes implements the HttpRoute contract and provides route registration
// for all controllers in the api module.
//
// @provider contracts.HttpRoute atom.GroupRoutes
type Routes struct {
log *log.Entry `inject:"false"`
// Controller instances
apiController *ApiController
}
// Prepare initializes the routes provider with logging configuration.
func (r *Routes) Prepare() error {
r.log = log.WithField("module", "routes.api")
r.log.Info("Initializing routes module")
return nil
}
// Name returns the unique identifier for this routes provider.
func (r *Routes) Name() string {
return "api"
}
// Register registers all HTTP routes with the provided fiber router.
// Each route is registered with its corresponding controller action and parameter bindings.
func (r *Routes) Register(router fiber.Router) {
// Register routes for controller: ApiController
r.log.Debugf("Registering route: Get /v1/admin/medias -> apiController.AdminMedias")
router.Get("/v1/admin/medias", Func0(
r.apiController.AdminMedias,
))
r.log.Debugf("Registering route: Get /v1/admin/medias/:id -> apiController.AdminMediaShow")
router.Get("/v1/admin/medias/:id", Func0(
r.apiController.AdminMediaShow,
))
r.log.Debugf("Registering route: Get /v1/admin/orders -> apiController.AdminOrders")
router.Get("/v1/admin/orders", Func0(
r.apiController.AdminOrders,
))
r.log.Debugf("Registering route: Get /v1/admin/statistics -> apiController.AdminStatistics")
router.Get("/v1/admin/statistics", Func0(
r.apiController.AdminStatistics,
))
r.log.Debugf("Registering route: Get /v1/auth/login -> apiController.WeChatOAuthCallback")
router.Get("/v1/auth/login", Func0(
r.apiController.WeChatOAuthCallback,
))
r.log.Debugf("Registering route: Get /v1/auth/wechat -> apiController.WeChatOAuthStart")
router.Get("/v1/auth/wechat", Func0(
r.apiController.WeChatOAuthStart,
))
r.log.Debugf("Registering route: Get /v1/posts -> apiController.ListPosts")
router.Get("/v1/posts", Func1(
r.apiController.ListPosts,
Query[PostsQuery]("query"),
))
r.log.Debugf("Registering route: Get /v1/posts/:id/play -> apiController.PlayPost")
router.Get("/v1/posts/:id/play", Func1(
r.apiController.PlayPost,
PathParam[int]("id"),
))
r.log.Debugf("Registering route: Get /v1/posts/:id/show -> apiController.ShowPost")
router.Get("/v1/posts/:id/show", Func1(
r.apiController.ShowPost,
PathParam[int]("id"),
))
r.log.Debugf("Registering route: Get /v1/posts/mine -> apiController.MinePosts")
router.Get("/v1/posts/mine", Func1(
r.apiController.MinePosts,
Query[PostsQuery]("query"),
))
r.log.Debugf("Registering route: Get /v1/users/profile -> apiController.UserProfile")
router.Get("/v1/users/profile", Func0(
r.apiController.UserProfile,
))
r.log.Debugf("Registering route: Get /v1/wechats/js-sdk -> apiController.WechatJSSDK")
router.Get("/v1/wechats/js-sdk", Func0(
r.apiController.WechatJSSDK,
))
r.log.Debugf("Registering route: Post /v1/admin/auth -> apiController.AdminAuth")
router.Post("/v1/admin/auth", Func0(
r.apiController.AdminAuth,
))
r.log.Debugf("Registering route: Post /v1/admin/orders/:id/refund -> apiController.AdminOrderRefund")
router.Post("/v1/admin/orders/:id/refund", Func1(
r.apiController.AdminOrderRefund,
PathParam[int]("id"),
))
r.log.Debugf("Registering route: Post /v1/posts/:id/buy -> apiController.BuyPost")
router.Post("/v1/posts/:id/buy", Func1(
r.apiController.BuyPost,
PathParam[int]("id"),
))
r.log.Debugf("Registering route: Put /v1/users/username -> apiController.UpdateUsername")
router.Put("/v1/users/username", Func1(
r.apiController.UpdateUsername,
Body[UpdateUsernameReq]("req"),
))
r.log.Info("Successfully registered all routes")
}

View File

@@ -4,6 +4,7 @@ import (
"quyun/v2/app/errorx"
"quyun/v2/app/http/super/dto"
"quyun/v2/app/services"
"quyun/v2/pkg/consts"
"quyun/v2/providers/app"
"quyun/v2/providers/jwt"
@@ -16,8 +17,16 @@ type authController struct {
jwt *jwt.JWT
}
// @Router /super/v1/auth/login [post]
// @Bind form body
// Login
//
// @Tags Super
// @Accept json
// @Produce json
// @Param form body dto.LoginForm true "form"
// @Success 200 {object} dto.LoginResponse "成功"
//
// @Router /super/v1/auth/login [post]
// @Bind form body
func (ctl *authController) login(ctx fiber.Ctx, form *dto.LoginForm) (*dto.LoginResponse, error) {
m, err := services.User.FindByUsername(ctx, form.Username)
if err != nil {
@@ -28,6 +37,10 @@ func (ctl *authController) login(ctx fiber.Ctx, form *dto.LoginForm) (*dto.Login
return nil, errorx.Wrap(err).WithMsg("用户名或密码错误")
}
if !m.Roles.Contains(consts.RoleSuperAdmin) {
return nil, errorx.Wrap(err).WithMsg("用户名或密码错误")
}
token, err := ctl.jwt.CreateToken(ctl.jwt.CreateClaims(jwt.BaseClaims{
UserID: m.ID,
}))

View File

@@ -12,7 +12,7 @@ type TenantFilter struct {
requests.Pagination
requests.SortQueryFilter
Name *string `json:"name,omitempty"`
Name *string `json:"name,omitempty" query:"name"`
}
type TenantItem struct {

View File

@@ -5,18 +5,19 @@
package super
import (
"quyun/v2/app/http/super/dto"
"github.com/gofiber/fiber/v3"
log "github.com/sirupsen/logrus"
_ "go.ipao.vip/atom"
_ "go.ipao.vip/atom/contracts"
. "go.ipao.vip/atom/fen"
"quyun/v2/app/http/super/dto"
)
// Routes implements the HttpRoute contract and provides route registration
// for all controllers in the super module.
//
// @provider contracts.HttpRoute atom.GroupRoutes
// @provider contracts.HttpRoute atom.GroupRoutes
type Routes struct {
log *log.Entry `inject:"false"`
// Controller instances

View File

@@ -13,16 +13,32 @@ import (
type tenant struct{}
// list
// @Router /super/v1/tenants [get]
// @Bind filter query
//
// @Summary 租户列表
// @Tags Super
// @Accept json
// @Produce json
// @Param filter query dto.TenantFilter true "Filter"
// @Success 200 {object} requests.Pager{items=dto.TenantItem}
//
// @Router /super/v1/tenants [get]
// @Bind filter query
func (*tenant) list(ctx fiber.Ctx, filter *dto.TenantFilter) (*requests.Pager, error) {
return services.Tenant.Pager(ctx, filter)
}
// list
// @Router /super/v1/tenants/:tenantID [patch]
// @Bind tenantID path
// @Bind form body
// updateExpire
//
// @Summary 更新过期时间
// @Tags Super
// @Accept json
// @Produce json
// @Param tenantID path int64 true "TenantID"
// @Param form body dto.TenantExpireUpdateForm true "Form"
//
// @Router /super/v1/tenants/:tenantID [patch]
// @Bind tenantID path
// @Bind form body
func (*tenant) updateExpire(ctx fiber.Ctx, tenantID int64, form *dto.TenantExpireUpdateForm) error {
duration, err := form.ParseDuration()
if err != nil {

View File

@@ -1,76 +0,0 @@
package v1
import (
"mime/multipart"
"quyun/v2/app/errorx"
"quyun/v2/app/requests"
"quyun/v2/app/services"
"quyun/v2/providers/jwt"
"github.com/gofiber/fiber/v3"
)
// @provider
type demo struct{}
type FooUploadReq struct {
Folder string `json:"folder" form:"folder"` // 上传到指定文件夹
}
type FooQuery struct {
Search string `query:"search"` // 搜索关键词
}
type FooHeader struct {
ContentType string `header:"Content-Type"` // 内容类型
}
type Filter struct {
Name string `query:"name"` // 名称
Age int `query:"age"` // 年龄
}
type ResponseItem struct{}
// Foo
//
// @Summary Test
// @Description Test
// @Tags Test
// @Accept json
// @Produce json
//
// @Param id path int true "ID"
// @Param query query Filter true "Filter"
// @Param pager query requests.Pagination true "Pager"
// @Success 200 {object} requests.Pager{list=ResponseItem} "成功"
//
// @Router /v1/medias/:id [post]
// @Bind query query
// @Bind pager query
// @Bind header header
// @Bind id path
// @Bind req body
// @Bind file file
// @Bind claim local
func (d *demo) Foo(
ctx fiber.Ctx,
id int,
pager *requests.Pagination,
query *FooQuery,
header *FooHeader,
claim *jwt.Claims,
file *multipart.FileHeader,
req *FooUploadReq,
) error {
_, err := services.Test.Test(ctx)
if err != nil {
// 示例:在控制器层自定义错误消息/附加数据
appErr := errorx.Wrap(err).
WithMsg("获取测试失败").
WithData(fiber.Map{"route": "/v1/test"}).
WithParams("handler", "Test.Hello")
return appErr
}
return nil
}

View File

@@ -1,33 +0,0 @@
package v1
import (
"go.ipao.vip/atom"
"go.ipao.vip/atom/container"
"go.ipao.vip/atom/contracts"
"go.ipao.vip/atom/opt"
)
func Provide(opts ...opt.Option) error {
if err := container.Container.Provide(func() (*demo, error) {
obj := &demo{}
return obj, nil
}); err != nil {
return err
}
if err := container.Container.Provide(func(
demo *demo,
) (contracts.HttpRoute, error) {
obj := &Routes{
demo: demo,
}
if err := obj.Prepare(); err != nil {
return nil, err
}
return obj, nil
}, atom.GroupRoutes); err != nil {
return err
}
return nil
}

View File

@@ -1,57 +0,0 @@
// Code generated by atomctl. DO NOT EDIT.
// Package v1 provides HTTP route definitions and registration
// for the quyun/v2 application.
package v1
import (
"github.com/gofiber/fiber/v3"
log "github.com/sirupsen/logrus"
_ "go.ipao.vip/atom"
_ "go.ipao.vip/atom/contracts"
. "go.ipao.vip/atom/fen"
"mime/multipart"
"quyun/v2/app/requests"
"quyun/v2/providers/jwt"
)
// Routes implements the HttpRoute contract and provides route registration
// for all controllers in the v1 module.
//
// @provider contracts.HttpRoute atom.GroupRoutes
type Routes struct {
log *log.Entry `inject:"false"`
// Controller instances
demo *demo
}
// Prepare initializes the routes provider with logging configuration.
func (r *Routes) Prepare() error {
r.log = log.WithField("module", "routes.v1")
r.log.Info("Initializing routes module")
return nil
}
// Name returns the unique identifier for this routes provider.
func (r *Routes) Name() string {
return "v1"
}
// Register registers all HTTP routes with the provided fiber router.
// Each route is registered with its corresponding controller action and parameter bindings.
func (r *Routes) Register(router fiber.Router) {
// Register routes for controller: demo
r.log.Debugf("Registering route: Post /v1/medias/:id -> demo.Foo")
router.Post("/v1/medias/:id", Func7(
r.demo.Foo,
PathParam[int]("id"),
Query[requests.Pagination]("pager"),
Query[FooQuery]("query"),
Header[FooHeader]("header"),
Local[*jwt.Claims]("claim"),
File[multipart.FileHeader]("file"),
Body[FooUploadReq]("req"),
))
r.log.Info("Successfully registered all routes")
}

View File

@@ -1,78 +0,0 @@
package web
import (
"os"
"path/filepath"
"strings"
"github.com/gofiber/fiber/v3"
)
// @provider
type WebController struct{}
func resolveDistDir(primary, fallback string) string {
if st, err := os.Stat(primary); err == nil && st.IsDir() {
return primary
}
return fallback
}
func sendIndex(ctx fiber.Ctx, distDir string) error {
indexPath := filepath.Join(distDir, "index.html")
if st, err := os.Stat(indexPath); err == nil && !st.IsDir() {
return ctx.SendFile(indexPath)
}
return fiber.ErrNotFound
}
func sendAssetOrIndex(ctx fiber.Ctx, distDir, rel string) error {
rel = filepath.Clean(strings.TrimSpace(rel))
if rel == "." || rel == "/" {
rel = ""
}
if strings.HasPrefix(rel, "..") {
return fiber.ErrBadRequest
}
if rel != "" {
assetPath := filepath.Join(distDir, rel)
if st, err := os.Stat(assetPath); err == nil && !st.IsDir() {
return ctx.SendFile(assetPath)
}
}
return sendIndex(ctx, distDir)
}
// AdminIndex
//
// @Router /admin [get]
func (w *WebController) AdminIndex(ctx fiber.Ctx) error {
adminDist := resolveDistDir("frontend/admin/dist", "../frontend/admin/dist")
return sendIndex(ctx, adminDist)
}
// AdminWildcard
//
// @Router /admin/* [get]
func (w *WebController) AdminWildcard(ctx fiber.Ctx) error {
adminDist := resolveDistDir("frontend/admin/dist", "../frontend/admin/dist")
return sendAssetOrIndex(ctx, adminDist, ctx.Params("*"))
}
// UserIndex
//
// @Router / [get]
func (w *WebController) UserIndex(ctx fiber.Ctx) error {
userDist := resolveDistDir("frontend/user/dist", "../frontend/user/dist")
return sendIndex(ctx, userDist)
}
// UserWildcard
//
// @Router /* [get]
func (w *WebController) UserWildcard(ctx fiber.Ctx) error {
userDist := resolveDistDir("frontend/user/dist", "../frontend/user/dist")
return sendAssetOrIndex(ctx, userDist, ctx.Params("*"))
}

View File

@@ -1,33 +0,0 @@
package web
import (
"go.ipao.vip/atom"
"go.ipao.vip/atom/container"
"go.ipao.vip/atom/contracts"
"go.ipao.vip/atom/opt"
)
func Provide(opts ...opt.Option) error {
if err := container.Container.Provide(func() (*WebController, error) {
obj := &WebController{}
return obj, nil
}); err != nil {
return err
}
if err := container.Container.Provide(func(
webController *WebController,
) (contracts.HttpRoute, error) {
obj := &Routes{
webController: webController,
}
if err := obj.Prepare(); err != nil {
return nil, err
}
return obj, nil
}, atom.GroupRoutes); err != nil {
return err
}
return nil
}

View File

@@ -1,59 +0,0 @@
// Code generated by atomctl. DO NOT EDIT.
// Package web provides HTTP route definitions and registration
// for the quyun/v2 application.
package web
import (
"github.com/gofiber/fiber/v3"
log "github.com/sirupsen/logrus"
_ "go.ipao.vip/atom"
_ "go.ipao.vip/atom/contracts"
. "go.ipao.vip/atom/fen"
)
// Routes implements the HttpRoute contract and provides route registration
// for all controllers in the web module.
//
// @provider contracts.HttpRoute atom.GroupRoutes
type Routes struct {
log *log.Entry `inject:"false"`
// Controller instances
webController *WebController
}
// Prepare initializes the routes provider with logging configuration.
func (r *Routes) Prepare() error {
r.log = log.WithField("module", "routes.web")
r.log.Info("Initializing routes module")
return nil
}
// Name returns the unique identifier for this routes provider.
func (r *Routes) Name() string {
return "web"
}
// Register registers all HTTP routes with the provided fiber router.
// Each route is registered with its corresponding controller action and parameter bindings.
func (r *Routes) Register(router fiber.Router) {
// Register routes for controller: WebController
r.log.Debugf("Registering route: Get / -> webController.UserIndex")
router.Get("/", Func0(
r.webController.UserIndex,
))
r.log.Debugf("Registering route: Get /* -> webController.UserWildcard")
router.Get("/*", Func0(
r.webController.UserWildcard,
))
r.log.Debugf("Registering route: Get /admin -> webController.AdminIndex")
router.Get("/admin", Func0(
r.webController.AdminIndex,
))
r.log.Debugf("Registering route: Get /admin/* -> webController.AdminWildcard")
router.Get("/admin/*", Func0(
r.webController.AdminWildcard,
))
r.log.Info("Successfully registered all routes")
}

View File

@@ -24,6 +24,133 @@ const docTemplate = `{
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {
"/super/v1/auth/login": {
"post": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Super"
],
"parameters": [
{
"description": "form",
"name": "form",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.LoginForm"
}
}
],
"responses": {
"200": {
"description": "成功",
"schema": {
"$ref": "#/definitions/dto.LoginResponse"
}
}
}
}
},
"/super/v1/tenants": {
"get": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Super"
],
"summary": "租户列表",
"parameters": [
{
"type": "string",
"name": "asc",
"in": "query"
},
{
"type": "string",
"name": "desc",
"in": "query"
},
{
"type": "integer",
"name": "limit",
"in": "query"
},
{
"type": "string",
"name": "name",
"in": "query"
},
{
"type": "integer",
"name": "page",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/requests.Pager"
},
{
"type": "object",
"properties": {
"items": {
"$ref": "#/definitions/dto.TenantItem"
}
}
}
]
}
}
}
}
},
"/super/v1/tenants/{tenantID}": {
"patch": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Super"
],
"summary": "更新过期时间",
"parameters": [
{
"type": "integer",
"format": "int64",
"description": "TenantID",
"name": "tenantID",
"in": "path",
"required": true
},
{
"description": "Form",
"name": "form",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.TenantExpireUpdateForm"
}
}
],
"responses": {}
}
},
"/v1/medias/{id}": {
"post": {
"description": "Test",
@@ -92,6 +219,238 @@ const docTemplate = `{
}
},
"definitions": {
"consts.Role": {
"type": "string",
"enum": [
"user",
"super_admin"
],
"x-enum-varnames": [
"RoleUser",
"RoleSuperAdmin"
]
},
"consts.TenantStatus": {
"type": "string",
"enum": [
"pending_verify",
"verified",
"banned"
],
"x-enum-varnames": [
"TenantStatusPendingVerify",
"TenantStatusVerified",
"TenantStatusBanned"
]
},
"consts.UserStatus": {
"type": "string",
"enum": [
"pending_verify",
"verified",
"banned"
],
"x-enum-varnames": [
"UserStatusPendingVerify",
"UserStatusVerified",
"UserStatusBanned"
]
},
"dto.LoginForm": {
"type": "object",
"properties": {
"password": {
"type": "string"
},
"username": {
"type": "string"
}
}
},
"dto.LoginResponse": {
"type": "object",
"properties": {
"token": {
"type": "string"
}
}
},
"dto.TenantExpireUpdateForm": {
"type": "object",
"required": [
"duration"
],
"properties": {
"duration": {
"type": "integer",
"enum": [
7,
30,
90,
180,
365
]
}
}
},
"dto.TenantItem": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"config": {
"type": "array",
"items": {
"type": "integer"
}
},
"created_at": {
"type": "string"
},
"expired_at": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"status": {
"$ref": "#/definitions/consts.TenantStatus"
},
"updated_at": {
"type": "string"
},
"userBalance": {
"type": "integer",
"format": "int64"
},
"userCount": {
"type": "integer",
"format": "int64"
},
"user_id": {
"type": "integer"
},
"users": {
"type": "array",
"items": {
"$ref": "#/definitions/models.User"
}
},
"uuid": {
"type": "string"
}
}
},
"gorm.DeletedAt": {
"type": "object",
"properties": {
"time": {
"type": "string"
},
"valid": {
"description": "Valid is true if Time is not NULL",
"type": "boolean"
}
}
},
"models.Tenant": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"config": {
"type": "array",
"items": {
"type": "integer"
}
},
"created_at": {
"type": "string"
},
"expired_at": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"status": {
"$ref": "#/definitions/consts.TenantStatus"
},
"updated_at": {
"type": "string"
},
"user_id": {
"type": "integer"
},
"users": {
"type": "array",
"items": {
"$ref": "#/definitions/models.User"
}
},
"uuid": {
"type": "string"
}
}
},
"models.User": {
"type": "object",
"properties": {
"created_at": {
"type": "string"
},
"deleted_at": {
"$ref": "#/definitions/gorm.DeletedAt"
},
"id": {
"type": "integer"
},
"metas": {
"type": "array",
"items": {
"type": "integer"
}
},
"owned": {
"$ref": "#/definitions/models.Tenant"
},
"password": {
"type": "string"
},
"roles": {
"type": "array",
"items": {
"$ref": "#/definitions/consts.Role"
}
},
"status": {
"$ref": "#/definitions/consts.UserStatus"
},
"tenants": {
"type": "array",
"items": {
"$ref": "#/definitions/models.Tenant"
}
},
"updated_at": {
"type": "string"
},
"username": {
"type": "string"
},
"verified_at": {
"type": "string"
}
}
},
"requests.Pager": {
"type": "object",
"properties": {
@@ -126,7 +485,7 @@ const docTemplate = `{
var SwaggerInfo = &swag.Spec{
Version: "1.0",
Host: "localhost:8080",
BasePath: "/api/v1",
BasePath: "/t/{tenant_code}/v1",
Schemes: []string{},
Title: "ApiDoc",
Description: "This is a sample server celler server.",

View File

@@ -16,8 +16,135 @@
"version": "1.0"
},
"host": "localhost:8080",
"basePath": "/api/v1",
"basePath": "/t/{tenant_code}/v1",
"paths": {
"/super/v1/auth/login": {
"post": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Super"
],
"parameters": [
{
"description": "form",
"name": "form",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.LoginForm"
}
}
],
"responses": {
"200": {
"description": "成功",
"schema": {
"$ref": "#/definitions/dto.LoginResponse"
}
}
}
}
},
"/super/v1/tenants": {
"get": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Super"
],
"summary": "租户列表",
"parameters": [
{
"type": "string",
"name": "asc",
"in": "query"
},
{
"type": "string",
"name": "desc",
"in": "query"
},
{
"type": "integer",
"name": "limit",
"in": "query"
},
{
"type": "string",
"name": "name",
"in": "query"
},
{
"type": "integer",
"name": "page",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/requests.Pager"
},
{
"type": "object",
"properties": {
"items": {
"$ref": "#/definitions/dto.TenantItem"
}
}
}
]
}
}
}
}
},
"/super/v1/tenants/{tenantID}": {
"patch": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Super"
],
"summary": "更新过期时间",
"parameters": [
{
"type": "integer",
"format": "int64",
"description": "TenantID",
"name": "tenantID",
"in": "path",
"required": true
},
{
"description": "Form",
"name": "form",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.TenantExpireUpdateForm"
}
}
],
"responses": {}
}
},
"/v1/medias/{id}": {
"post": {
"description": "Test",
@@ -86,6 +213,238 @@
}
},
"definitions": {
"consts.Role": {
"type": "string",
"enum": [
"user",
"super_admin"
],
"x-enum-varnames": [
"RoleUser",
"RoleSuperAdmin"
]
},
"consts.TenantStatus": {
"type": "string",
"enum": [
"pending_verify",
"verified",
"banned"
],
"x-enum-varnames": [
"TenantStatusPendingVerify",
"TenantStatusVerified",
"TenantStatusBanned"
]
},
"consts.UserStatus": {
"type": "string",
"enum": [
"pending_verify",
"verified",
"banned"
],
"x-enum-varnames": [
"UserStatusPendingVerify",
"UserStatusVerified",
"UserStatusBanned"
]
},
"dto.LoginForm": {
"type": "object",
"properties": {
"password": {
"type": "string"
},
"username": {
"type": "string"
}
}
},
"dto.LoginResponse": {
"type": "object",
"properties": {
"token": {
"type": "string"
}
}
},
"dto.TenantExpireUpdateForm": {
"type": "object",
"required": [
"duration"
],
"properties": {
"duration": {
"type": "integer",
"enum": [
7,
30,
90,
180,
365
]
}
}
},
"dto.TenantItem": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"config": {
"type": "array",
"items": {
"type": "integer"
}
},
"created_at": {
"type": "string"
},
"expired_at": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"status": {
"$ref": "#/definitions/consts.TenantStatus"
},
"updated_at": {
"type": "string"
},
"userBalance": {
"type": "integer",
"format": "int64"
},
"userCount": {
"type": "integer",
"format": "int64"
},
"user_id": {
"type": "integer"
},
"users": {
"type": "array",
"items": {
"$ref": "#/definitions/models.User"
}
},
"uuid": {
"type": "string"
}
}
},
"gorm.DeletedAt": {
"type": "object",
"properties": {
"time": {
"type": "string"
},
"valid": {
"description": "Valid is true if Time is not NULL",
"type": "boolean"
}
}
},
"models.Tenant": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"config": {
"type": "array",
"items": {
"type": "integer"
}
},
"created_at": {
"type": "string"
},
"expired_at": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"status": {
"$ref": "#/definitions/consts.TenantStatus"
},
"updated_at": {
"type": "string"
},
"user_id": {
"type": "integer"
},
"users": {
"type": "array",
"items": {
"$ref": "#/definitions/models.User"
}
},
"uuid": {
"type": "string"
}
}
},
"models.User": {
"type": "object",
"properties": {
"created_at": {
"type": "string"
},
"deleted_at": {
"$ref": "#/definitions/gorm.DeletedAt"
},
"id": {
"type": "integer"
},
"metas": {
"type": "array",
"items": {
"type": "integer"
}
},
"owned": {
"$ref": "#/definitions/models.Tenant"
},
"password": {
"type": "string"
},
"roles": {
"type": "array",
"items": {
"$ref": "#/definitions/consts.Role"
}
},
"status": {
"$ref": "#/definitions/consts.UserStatus"
},
"tenants": {
"type": "array",
"items": {
"$ref": "#/definitions/models.Tenant"
}
},
"updated_at": {
"type": "string"
},
"username": {
"type": "string"
},
"verified_at": {
"type": "string"
}
}
},
"requests.Pager": {
"type": "object",
"properties": {

View File

@@ -1,5 +1,163 @@
basePath: /api/v1
basePath: /t/{tenant_code}/v1
definitions:
consts.Role:
enum:
- user
- super_admin
type: string
x-enum-varnames:
- RoleUser
- RoleSuperAdmin
consts.TenantStatus:
enum:
- pending_verify
- verified
- banned
type: string
x-enum-varnames:
- TenantStatusPendingVerify
- TenantStatusVerified
- TenantStatusBanned
consts.UserStatus:
enum:
- pending_verify
- verified
- banned
type: string
x-enum-varnames:
- UserStatusPendingVerify
- UserStatusVerified
- UserStatusBanned
dto.LoginForm:
properties:
password:
type: string
username:
type: string
type: object
dto.LoginResponse:
properties:
token:
type: string
type: object
dto.TenantExpireUpdateForm:
properties:
duration:
enum:
- 7
- 30
- 90
- 180
- 365
type: integer
required:
- duration
type: object
dto.TenantItem:
properties:
code:
type: string
config:
items:
type: integer
type: array
created_at:
type: string
expired_at:
type: string
id:
type: integer
name:
type: string
status:
$ref: '#/definitions/consts.TenantStatus'
updated_at:
type: string
user_id:
type: integer
userBalance:
format: int64
type: integer
userCount:
format: int64
type: integer
users:
items:
$ref: '#/definitions/models.User'
type: array
uuid:
type: string
type: object
gorm.DeletedAt:
properties:
time:
type: string
valid:
description: Valid is true if Time is not NULL
type: boolean
type: object
models.Tenant:
properties:
code:
type: string
config:
items:
type: integer
type: array
created_at:
type: string
expired_at:
type: string
id:
type: integer
name:
type: string
status:
$ref: '#/definitions/consts.TenantStatus'
updated_at:
type: string
user_id:
type: integer
users:
items:
$ref: '#/definitions/models.User'
type: array
uuid:
type: string
type: object
models.User:
properties:
created_at:
type: string
deleted_at:
$ref: '#/definitions/gorm.DeletedAt'
id:
type: integer
metas:
items:
type: integer
type: array
owned:
$ref: '#/definitions/models.Tenant'
password:
type: string
roles:
items:
$ref: '#/definitions/consts.Role'
type: array
status:
$ref: '#/definitions/consts.UserStatus'
tenants:
items:
$ref: '#/definitions/models.Tenant'
type: array
updated_at:
type: string
username:
type: string
verified_at:
type: string
type: object
requests.Pager:
properties:
items: {}
@@ -29,6 +187,84 @@ info:
title: ApiDoc
version: "1.0"
paths:
/super/v1/auth/login:
post:
consumes:
- application/json
parameters:
- description: form
in: body
name: form
required: true
schema:
$ref: '#/definitions/dto.LoginForm'
produces:
- application/json
responses:
"200":
description: 成功
schema:
$ref: '#/definitions/dto.LoginResponse'
tags:
- Super
/super/v1/tenants:
get:
consumes:
- application/json
parameters:
- in: query
name: asc
type: string
- in: query
name: desc
type: string
- in: query
name: limit
type: integer
- in: query
name: name
type: string
- in: query
name: page
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/requests.Pager'
- properties:
items:
$ref: '#/definitions/dto.TenantItem'
type: object
summary: 租户列表
tags:
- Super
/super/v1/tenants/{tenantID}:
patch:
consumes:
- application/json
parameters:
- description: TenantID
format: int64
in: path
name: tenantID
required: true
type: integer
- description: Form
in: body
name: form
required: true
schema:
$ref: '#/definitions/dto.TenantExpireUpdateForm'
produces:
- application/json
responses: {}
summary: 更新过期时间
tags:
- Super
/v1/medias/{id}:
post:
consumes: