From 9bc21550084d53426dc7b91aa68552aaaf02d2d0 Mon Sep 17 00:00:00 2001 From: Rogee Date: Tue, 16 Dec 2025 17:11:49 +0800 Subject: [PATCH] fix: swagger --- backend/app/http/api/controller.go | 207 --------------- backend/app/http/api/provider.gen.go | 33 --- backend/app/http/api/routes.gen.go | 114 --------- backend/app/http/super/auth.go | 17 +- backend/app/http/super/dto/tenant.go | 2 +- backend/app/http/super/routes.gen.go | 5 +- backend/app/http/super/tenant.go | 28 ++- backend/app/http/v1/demo.go | 76 ------ backend/app/http/v1/provider.gen.go | 33 --- backend/app/http/v1/routes.gen.go | 57 ----- backend/app/http/web/controller.go | 78 ------ backend/app/http/web/provider.gen.go | 33 --- backend/app/http/web/routes.gen.go | 59 ----- backend/docs/docs.go | 361 ++++++++++++++++++++++++++- backend/docs/swagger.json | 361 ++++++++++++++++++++++++++- backend/docs/swagger.yaml | 238 +++++++++++++++++- 16 files changed, 998 insertions(+), 704 deletions(-) delete mode 100644 backend/app/http/api/controller.go delete mode 100755 backend/app/http/api/provider.gen.go delete mode 100644 backend/app/http/api/routes.gen.go delete mode 100644 backend/app/http/v1/demo.go delete mode 100755 backend/app/http/v1/provider.gen.go delete mode 100644 backend/app/http/v1/routes.gen.go delete mode 100644 backend/app/http/web/controller.go delete mode 100755 backend/app/http/web/provider.gen.go delete mode 100644 backend/app/http/web/routes.gen.go diff --git a/backend/app/http/api/controller.go b/backend/app/http/api/controller.go deleted file mode 100644 index ca9f224..0000000 --- a/backend/app/http/api/controller.go +++ /dev/null @@ -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"}) -} diff --git a/backend/app/http/api/provider.gen.go b/backend/app/http/api/provider.gen.go deleted file mode 100755 index 20e718a..0000000 --- a/backend/app/http/api/provider.gen.go +++ /dev/null @@ -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 -} diff --git a/backend/app/http/api/routes.gen.go b/backend/app/http/api/routes.gen.go deleted file mode 100644 index d791eaf..0000000 --- a/backend/app/http/api/routes.gen.go +++ /dev/null @@ -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") -} diff --git a/backend/app/http/super/auth.go b/backend/app/http/super/auth.go index 3729a28..8af3dca 100644 --- a/backend/app/http/super/auth.go +++ b/backend/app/http/super/auth.go @@ -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, })) diff --git a/backend/app/http/super/dto/tenant.go b/backend/app/http/super/dto/tenant.go index a51ec8a..295c4d9 100644 --- a/backend/app/http/super/dto/tenant.go +++ b/backend/app/http/super/dto/tenant.go @@ -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 { diff --git a/backend/app/http/super/routes.gen.go b/backend/app/http/super/routes.gen.go index a93ca97..d5ed439 100644 --- a/backend/app/http/super/routes.gen.go +++ b/backend/app/http/super/routes.gen.go @@ -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 diff --git a/backend/app/http/super/tenant.go b/backend/app/http/super/tenant.go index a84fef6..d04c437 100644 --- a/backend/app/http/super/tenant.go +++ b/backend/app/http/super/tenant.go @@ -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 { diff --git a/backend/app/http/v1/demo.go b/backend/app/http/v1/demo.go deleted file mode 100644 index a176b60..0000000 --- a/backend/app/http/v1/demo.go +++ /dev/null @@ -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 -} diff --git a/backend/app/http/v1/provider.gen.go b/backend/app/http/v1/provider.gen.go deleted file mode 100755 index 1504210..0000000 --- a/backend/app/http/v1/provider.gen.go +++ /dev/null @@ -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 -} diff --git a/backend/app/http/v1/routes.gen.go b/backend/app/http/v1/routes.gen.go deleted file mode 100644 index c6e3825..0000000 --- a/backend/app/http/v1/routes.gen.go +++ /dev/null @@ -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") -} diff --git a/backend/app/http/web/controller.go b/backend/app/http/web/controller.go deleted file mode 100644 index 2f2c76b..0000000 --- a/backend/app/http/web/controller.go +++ /dev/null @@ -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("*")) -} diff --git a/backend/app/http/web/provider.gen.go b/backend/app/http/web/provider.gen.go deleted file mode 100755 index 32f254b..0000000 --- a/backend/app/http/web/provider.gen.go +++ /dev/null @@ -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 -} diff --git a/backend/app/http/web/routes.gen.go b/backend/app/http/web/routes.gen.go deleted file mode 100644 index 64ddb79..0000000 --- a/backend/app/http/web/routes.gen.go +++ /dev/null @@ -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") -} diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 8c35c88..3e43970 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -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.", diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index c1e57c5..d5dc66f 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -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": { diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index f9f7516..1040948 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -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: