调整模块化结构

main
熊二 1 year ago
parent fa896b66b6
commit 973d88e77c
  1. 9
      go.mod
  2. 12
      go.sum
  3. 4
      internal/services/company/controller/company_controller.go
  4. 4
      internal/services/company/controller/company_department_controller.go
  5. 4
      internal/services/company/controller/company_staff_controller.go
  6. 6
      internal/services/config/controller/config_controller.go
  7. 4
      internal/services/config/controller/config_group_controller.go
  8. 4
      internal/services/feature/controller/feature_category_controller.go
  9. 4
      internal/services/feature/controller/feature_config_controller.go
  10. 4
      internal/services/feature/controller/feature_content_chapter_controller.go
  11. 4
      internal/services/feature/controller/feature_content_controller.go
  12. 4
      internal/services/feature/controller/feature_content_detail_controller.go
  13. 4
      internal/services/feature/controller/feature_controller.go
  14. 4
      internal/services/resource/controller/resource_category_controller.go
  15. 4
      internal/services/resource/controller/resource_controller.go
  16. 49
      internal/services/service.go
  17. 4
      internal/services/system/controller/system_log_controller.go
  18. 4
      internal/services/system/controller/system_menu_controller.go
  19. 4
      internal/services/system/controller/system_permission_controller.go
  20. 4
      internal/services/system/controller/system_role_controller.go
  21. 4
      internal/services/system/controller/system_role_power_controller.go
  22. 4
      internal/services/system/controller/system_user_controller.go
  23. 43
      internal/util/echo_bind.go
  24. 2
      pkg/app/applet.go
  25. 14
      pkg/app/context.go
  26. 151
      pkg/app/controller.go
  27. 15
      pkg/app/echo.go
  28. 239
      pkg/app/echo_utils.go

@ -6,15 +6,12 @@ require (
github.com/go-resty/resty/v2 v2.7.0 github.com/go-resty/resty/v2 v2.7.0
github.com/golang-jwt/jwt/v5 v5.0.0 github.com/golang-jwt/jwt/v5 v5.0.0
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/labstack/echo-jwt/v4 v4.2.0
github.com/labstack/echo/v4 v4.11.1 github.com/labstack/echo/v4 v4.11.1
github.com/labstack/gommon v0.4.0 github.com/labstack/gommon v0.4.0
github.com/mattn/go-isatty v0.0.19 github.com/mattn/go-isatty v0.0.19
github.com/mattn/go-sqlite3 v1.14.17
github.com/mitchellh/mapstructure v1.5.0
github.com/rs/xid v1.5.0 github.com/rs/xid v1.5.0
github.com/spf13/cobra v1.7.0
github.com/swaggo/echo-swagger v1.4.1 github.com/swaggo/echo-swagger v1.4.1
github.com/swaggo/swag v1.16.2
golang.org/x/time v0.3.0 golang.org/x/time v0.3.0
gorm.io/driver/mysql v1.5.1 gorm.io/driver/mysql v1.5.1
gorm.io/driver/postgres v1.5.2 gorm.io/driver/postgres v1.5.2
@ -37,6 +34,7 @@ require (
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.3.1 // indirect github.com/jackc/pgx/v5 v5.3.1 // indirect
@ -45,10 +43,13 @@ require (
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/microsoft/go-mssqldb v1.1.0 // indirect github.com/microsoft/go-mssqldb v1.1.0 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.8.2 // indirect github.com/stretchr/testify v1.8.2 // indirect
github.com/swaggo/files/v2 v2.0.0 // indirect github.com/swaggo/files/v2 v2.0.0 // indirect
github.com/swaggo/swag v1.16.2 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/crypto v0.11.0 // indirect golang.org/x/crypto v0.11.0 // indirect

@ -8,6 +8,7 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -46,6 +47,8 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
@ -74,8 +77,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/labstack/echo-jwt/v4 v4.2.0 h1:odSISV9JgcSCuhgQSV/6Io3i7nUmfM/QkBeR5GVJj5c=
github.com/labstack/echo-jwt/v4 v4.2.0/go.mod h1:MA2RqdXdEn4/uEglx0HcUOgQSyBaTh5JcaHIan3biwU=
github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4=
github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
@ -96,8 +97,6 @@ github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/microsoft/go-mssqldb v1.1.0 h1:jsV+tpvcPTbNNKW0o3kiCD69kOHICsfjZ2VcVu2lKYc= github.com/microsoft/go-mssqldb v1.1.0 h1:jsV+tpvcPTbNNKW0o3kiCD69kOHICsfjZ2VcVu2lKYc=
github.com/microsoft/go-mssqldb v1.1.0/go.mod h1:LzkFdl4z2Ck+Hi+ycGOTbL56VEfgoyA2DvYejrNGbRk= github.com/microsoft/go-mssqldb v1.1.0/go.mod h1:LzkFdl4z2Ck+Hi+ycGOTbL56VEfgoyA2DvYejrNGbRk=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
@ -108,6 +107,11 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/company/request" "sorbet/internal/services/company/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type CompanyController struct { type CompanyController struct {
util.Controller[entities.Company, request.CompanyUpsertRequest] app.Controller[entities.Company, request.CompanyUpsertRequest]
} }
func (ctr *CompanyController) InitRoutes(r *echo.Group) { func (ctr *CompanyController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/company/request" "sorbet/internal/services/company/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type CompanyDepartmentController struct { type CompanyDepartmentController struct {
util.Controller[entities.CompanyDepartment, request.CompanyDepartmentUpsertRequest] app.Controller[entities.CompanyDepartment, request.CompanyDepartmentUpsertRequest]
} }
func (c *CompanyDepartmentController) InitRoutes(r *echo.Group) { func (c *CompanyDepartmentController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/company/request" "sorbet/internal/services/company/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type CompanyStaffController struct { type CompanyStaffController struct {
util.Controller[entities.CompanyStaff, request.CompanyStaffUpsertRequest] app.Controller[entities.CompanyStaff, request.CompanyStaffUpsertRequest]
} }
func (c *CompanyStaffController) InitRoutes(r *echo.Group) { func (c *CompanyStaffController) InitRoutes(r *echo.Group) {

@ -4,13 +4,13 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/config/request" "sorbet/internal/services/config/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type ConfigController struct { type ConfigController struct {
util.Controller[entities.Config, request.ConfigUpsertRequest] app.Controller[entities.Config, request.ConfigUpsertRequest]
} }
func (ctr *ConfigController) InitRoutes(r *echo.Group) { func (ctr *ConfigController) InitRoutes(r *echo.Group) {
ctr.RegisterRoutes("/config", r) ctr.RegisterRoutes("/configs", r)
} }

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/config/request" "sorbet/internal/services/config/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type ConfigGroupController struct { type ConfigGroupController struct {
util.Controller[entities.ConfigGroup, request.ConfigGroupUpsertRequest] app.Controller[entities.ConfigGroup, request.ConfigGroupUpsertRequest]
} }
// InitRoutes 实现路由注册接口 // InitRoutes 实现路由注册接口

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/feature/request" "sorbet/internal/services/feature/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type FeatureCategoryController struct { type FeatureCategoryController struct {
util.Controller[entities.FeatureCategory, request.FeatureCategoryUpsertRequest] app.Controller[entities.FeatureCategory, request.FeatureCategoryUpsertRequest]
} }
func (f *FeatureCategoryController) InitRoutes(r *echo.Group) { func (f *FeatureCategoryController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/feature/request" "sorbet/internal/services/feature/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type FeatureConfigController struct { type FeatureConfigController struct {
util.Controller[entities.FeatureConfig, request.FeatureConfigUpsertRequest] app.Controller[entities.FeatureConfig, request.FeatureConfigUpsertRequest]
} }
func (f *FeatureConfigController) InitRoutes(r *echo.Group) { func (f *FeatureConfigController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/feature/request" "sorbet/internal/services/feature/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type FeatureContentChapterController struct { type FeatureContentChapterController struct {
util.Controller[entities.FeatureContentChapter, request.FeatureContentChapterUpsertRequest] app.Controller[entities.FeatureContentChapter, request.FeatureContentChapterUpsertRequest]
} }
func (f *FeatureContentChapterController) InitRoutes(r *echo.Group) { func (f *FeatureContentChapterController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/feature/request" "sorbet/internal/services/feature/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type FeatureContentController struct { type FeatureContentController struct {
util.Controller[entities.FeatureContent, request.FeatureContentUpsertRequest] app.Controller[entities.FeatureContent, request.FeatureContentUpsertRequest]
} }
func (f *FeatureContentController) InitRoutes(r *echo.Group) { func (f *FeatureContentController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/feature/request" "sorbet/internal/services/feature/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type FeatureContentDetailController struct { type FeatureContentDetailController struct {
util.Controller[entities.FeatureContentDetail, request.FeatureContentDetailUpsertRequest] app.Controller[entities.FeatureContentDetail, request.FeatureContentDetailUpsertRequest]
} }
func (f *FeatureContentDetailController) InitRoutes(r *echo.Group) { func (f *FeatureContentDetailController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/feature/request" "sorbet/internal/services/feature/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type FeatureController struct { type FeatureController struct {
util.Controller[entities.Feature, request.FeatureUpsertRequest] app.Controller[entities.Feature, request.FeatureUpsertRequest]
} }
func (f *FeatureController) InitRoutes(r *echo.Group) { func (f *FeatureController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/resource/request" "sorbet/internal/services/resource/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type ResourceCategoryController struct { type ResourceCategoryController struct {
util.Controller[entities.Resource, request.ResourceCategoryUpsertRequest] app.Controller[entities.Resource, request.ResourceCategoryUpsertRequest]
} }
func (ctr *ResourceCategoryController) InitRoutes(r *echo.Group) { func (ctr *ResourceCategoryController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/resource/request" "sorbet/internal/services/resource/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type ResourceController struct { type ResourceController struct {
util.Controller[entities.Resource, request.ResourceUpsertRequest] app.Controller[entities.Resource, request.ResourceUpsertRequest]
} }
func (ctr *ResourceController) InitRoutes(r *echo.Group) { func (ctr *ResourceController) InitRoutes(r *echo.Group) {

@ -1,24 +1,49 @@
package services package services
import ( import (
"context"
"github.com/labstack/echo/v4"
"sorbet/internal/services/company"
"sorbet/internal/services/config"
"sorbet/internal/services/feature"
"sorbet/internal/services/resource"
"sorbet/internal/services/system"
"sorbet/pkg/app" "sorbet/pkg/app"
) )
type Service struct { var applets []app.Applet
inners []Service
}
func (s Service) Init(ctx *app.Context) error { func Init() {
//TODO implement me applets = []app.Applet{
panic("implement me") &config.Service{},
&company.Service{},
&resource.Service{},
&feature.Service{},
&system.Service{},
}
} }
func (s Service) Start() error { func Start(ctx context.Context) error {
//TODO implement me e := ctx.Value("echo_framework").(*echo.Echo)
panic("implement me") for _, service := range applets {
err := service.Init(app.NewContext(ctx, e.Group("")))
if err != nil {
return err
}
err = service.Start()
if err != nil {
return err
}
}
return nil
} }
func (s Service) Stop() error { func Stop() error {
//TODO implement me for _, service := range applets {
panic("implement me") err := service.Stop()
if err != nil {
return err
}
}
return nil
} }

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/system/request" "sorbet/internal/services/system/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type SystemLogController struct { type SystemLogController struct {
util.Controller[entities.SystemLog, request.SystemLogUpsertRequest] app.Controller[entities.SystemLog, request.SystemLogUpsertRequest]
} }
func (s *SystemLogController) InitRoutes(r *echo.Group) { func (s *SystemLogController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/system/request" "sorbet/internal/services/system/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type SystemMenuController struct { type SystemMenuController struct {
util.Controller[entities.SystemMenu, request.SystemMenuUpsertRequest] app.Controller[entities.SystemMenu, request.SystemMenuUpsertRequest]
} }
func (s *SystemMenuController) InitRoutes(r *echo.Group) { func (s *SystemMenuController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/system/request" "sorbet/internal/services/system/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type SystemPermissionController struct { type SystemPermissionController struct {
util.Controller[entities.SystemPermission, request.SystemPermissionUpsertRequest] app.Controller[entities.SystemPermission, request.SystemPermissionUpsertRequest]
} }
func (s *SystemPermissionController) InitRoutes(r *echo.Group) { func (s *SystemPermissionController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/system/request" "sorbet/internal/services/system/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type SystemRoleController struct { type SystemRoleController struct {
util.Controller[entities.SystemRole, request.SystemRoleUpsertRequest] app.Controller[entities.SystemRole, request.SystemRoleUpsertRequest]
} }
func (s *SystemRoleController) InitRoutes(r *echo.Group) { func (s *SystemRoleController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/system/request" "sorbet/internal/services/system/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type SystemRolePowerController struct { type SystemRolePowerController struct {
util.Controller[entities.SystemRolePower, request.SystemRolePowerUpsertRequest] app.Controller[entities.SystemRolePower, request.SystemRolePowerUpsertRequest]
} }
func (s *SystemRolePowerController) InitRoutes(r *echo.Group) { func (s *SystemRolePowerController) InitRoutes(r *echo.Group) {

@ -4,11 +4,11 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"sorbet/internal/entities" "sorbet/internal/entities"
"sorbet/internal/services/system/request" "sorbet/internal/services/system/request"
"sorbet/internal/util" "sorbet/pkg/app"
) )
type SystemUserController struct { type SystemUserController struct {
util.Controller[entities.SystemUser, request.SystemUserUpsertRequest] app.Controller[entities.SystemUser, request.SystemUserUpsertRequest]
} }
func (s *SystemUserController) InitRoutes(r *echo.Group) { func (s *SystemUserController) InitRoutes(r *echo.Group) {

@ -1,43 +0,0 @@
package util
import (
"github.com/labstack/echo/v4"
"sorbet/pkg/rsp"
)
// RequestGuarder 参数守卫函数签名
type RequestGuarder[T any] func(c echo.Context, req *T) error
// Bind 将提交的参数绑定到泛型 T 的实例上
func Bind[T any](c echo.Context, guards ...RequestGuarder[T]) (*T, error) {
var req T
if err := c.Bind(&req); err != nil {
return nil, err
}
if err := c.Validate(&req); err != nil {
return nil, err
}
for _, guard := range guards {
if err := guard(c, &req); err != nil {
return nil, err
}
}
return &req, nil
}
func BindId(c echo.Context, must bool) (uint, error) {
request, err := Bind[struct {
ID uint `json:"id" xml:"id" path:"id"`
}](c)
if err != nil {
return 0, err
}
if must {
if request.ID <= 0 {
return 0, rsp.ErrBadParams
}
} else if request.ID < 0 {
return 0, rsp.ErrBadParams
}
return request.ID, err
}

@ -2,7 +2,7 @@ package app
import "github.com/labstack/echo/v4" import "github.com/labstack/echo/v4"
type Service interface { type Applet interface {
// Init 初始化服务 // Init 初始化服务
Init(ctx *Context) error Init(ctx *Context) error
// Start 启动服务 // Start 启动服务

@ -8,20 +8,18 @@ import (
type Context struct { type Context struct {
context.Context context.Context
prefix string
store map[any]any store map[any]any
router *echo.Group router *echo.Group
mu sync.RWMutex mu sync.RWMutex
} }
// Prefix 设置路由前缀 func NewContext(ctx context.Context, router *echo.Group) *Context {
func (c *Context) Prefix(prefix string) { return &Context{
c.mu.Lock() Context: ctx,
defer c.mu.Unlock() store: make(map[any]any),
if c.prefix != "" { router: router,
panic("already prefixed") mu: sync.RWMutex{},
} }
c.prefix = prefix
} }
// Routes 注册路由 // Routes 注册路由

@ -1,148 +1,35 @@
package util package app
import ( import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"gorm.io/gorm" "gorm.io/gorm"
"net/url"
"reflect" "reflect"
"sorbet/pkg/db" "sorbet/pkg/db"
"sorbet/pkg/ioc" "sorbet/pkg/ioc"
"sorbet/pkg/rsp" "sorbet/pkg/rsp"
"strconv"
"strings"
) )
type GetID interface { // Upsertable 数据创建和更新需要接口
// 用于控制器 Create、Update 方法
type Upsertable interface {
// GetID 用于 Controller.Update 方法,
// 定位被更新的数据编号
GetID() any GetID() any
} // ToMap 用于 Controller.Update 方法,
// 返回被更新的数据,支持零值
type ToMap interface {
ToMap() map[string]any ToMap() map[string]any
} // ToEntity 用于 Controller.Create 方法,
// 返回被创建的实体的数据
type ToEntity interface {
ToEntity() any ToEntity() any
} }
type ControllerRequest interface {
GetID
ToMap
ToEntity
}
func ParseQuery[T any](query url.Values, qb *db.QueryBuilder[T]) (page, limit int, err error) {
var paginating bool
for key, values := range query {
switch key {
case "sortby":
for _, s := range values {
if s[0] == '+' {
qb.AscentBy(s[1:])
} else if s[0] == '-' {
qb.DescentBy(s[1:])
} else {
qb.AscentBy(s)
}
}
case "limit", "page":
var v int
if values[0] != "" {
v, err = strconv.Atoi(values[0])
if err != nil {
return
}
}
if v <= 0 {
return 0, 0, rsp.ErrInternal
}
if key == "limit" {
qb.Limit(v)
limit = v
} else {
paginating = true
page = max(v, 1)
}
default:
v := values[0]
i := strings.IndexByte(key, '#')
if i == -1 {
qb.Eq(key, v)
continue
}
switch k, op := key[:i], key[i+1:]; op {
case "=":
qb.Eq(k, v)
case "!=":
qb.Neq(k, v)
case "<":
qb.Lt(k, v)
case "<=":
qb.Lte(k, v)
case ">":
qb.Gt(k, v)
case ">=":
qb.Gte(k, v)
case "<>", "><":
var less, more any
switch len(values) {
case 2:
less, more = values[0], values[1]
case 1:
vs := strings.Split(v, ",")
if len(vs) != 2 || vs[0] == "" || vs[1] == "" {
return 0, 0, rsp.ErrBadParams
}
less, more = vs[0], vs[1]
}
if op == "<>" {
qb.Between(k, less, more)
} else {
qb.NotBetween(k, key, more)
}
case "nil":
qb.IsNull(k)
case "!nil":
qb.NotNull(k)
case "~":
qb.Like(k, v)
case "!~":
qb.NotLike(k, v)
case "in", "!in":
if len(values) == 1 {
values = strings.Split(v, ",")
}
vs := make([]any, len(values))
for i, value := range values {
vs[i] = value
}
if op == "in" {
qb.In(k, vs...)
} else {
qb.NotIn(k, vs...)
}
default:
qb.Eq(key, v)
}
}
}
if paginating {
return
}
if limit == 0 {
limit = 30
qb.Limit(limit)
}
qb.Offset((page - 1) * limit)
return
}
func getID(req any) (val any) { func getID(req any) (val any) {
defer func() { defer func() {
if recover() != nil { if recover() != nil {
val = nil val = nil
} }
}() }()
val = req.(GetID).GetID() val = req.(Upsertable).GetID()
rv := reflect.ValueOf(val) rv := reflect.ValueOf(val)
if rv.IsZero() || rv.IsNil() { if rv.IsZero() || rv.IsNil() {
val = nil val = nil
@ -151,19 +38,18 @@ func getID(req any) (val any) {
} }
func getValues(req any) map[string]any { func getValues(req any) map[string]any {
if v, ok := req.(ToMap); ok { if v, ok := req.(Upsertable); ok {
return v.ToMap() return v.ToMap()
} }
return nil return nil
} }
func getEntity[T any](request any) *T { func getEntity[T any](request any) *T {
v, ok := request.(ToEntity) v, ok := request.(Upsertable)
if !ok { if !ok {
return nil return nil
} }
ent, ok := v.ToEntity().(*T) if ent, ok := v.ToEntity().(*T); ok {
if ok {
return ent return ent
} }
return nil return nil
@ -175,6 +61,7 @@ func getEntity[T any](request any) *T {
// 泛型 [Upsert] 表示创建或更新时需要的数据。 // 泛型 [Upsert] 表示创建或更新时需要的数据。
type Controller[Entity any, Upsert any] struct{} type Controller[Entity any, Upsert any] struct{}
// RegisterRoutes 注册路由
func (ctr *Controller[Entity, Upsert]) RegisterRoutes(path string, r *echo.Group) { func (ctr *Controller[Entity, Upsert]) RegisterRoutes(path string, r *echo.Group) {
r.PUT(path, ctr.Create) r.PUT(path, ctr.Create)
r.DELETE(path+"/:id", ctr.Delete) r.DELETE(path+"/:id", ctr.Delete)
@ -183,6 +70,7 @@ func (ctr *Controller[Entity, Upsert]) RegisterRoutes(path string, r *echo.Group
r.GET(path, ctr.List) r.GET(path, ctr.List)
} }
// ORM 获取 gorm.DB 实例
func (ctr *Controller[Entity, Upsert]) ORM(c echo.Context) (*gorm.DB, error) { func (ctr *Controller[Entity, Upsert]) ORM(c echo.Context) (*gorm.DB, error) {
orm, err := ioc.Get[gorm.DB]() orm, err := ioc.Get[gorm.DB]()
if err != nil { if err != nil {
@ -191,6 +79,7 @@ func (ctr *Controller[Entity, Upsert]) ORM(c echo.Context) (*gorm.DB, error) {
return orm.WithContext(c.Request().Context()), nil return orm.WithContext(c.Request().Context()), nil
} }
// Repository 获取 Repository 实例
func (ctr *Controller[Entity, Upsert]) Repository() (*db.Repository[Entity], error) { func (ctr *Controller[Entity, Upsert]) Repository() (*db.Repository[Entity], error) {
orm, err := ioc.Get[gorm.DB]() orm, err := ioc.Get[gorm.DB]()
if err != nil { if err != nil {
@ -249,7 +138,7 @@ func (ctr *Controller[Entity, Upsert]) upsert(c echo.Context, isCreate bool) err
// Delete 通过ID删除数据 // Delete 通过ID删除数据
func (ctr *Controller[Entity, Upsert]) Delete(c echo.Context) error { func (ctr *Controller[Entity, Upsert]) Delete(c echo.Context) error {
id, err := BindId(c, true) id, err := BindID(c)
if err != nil { if err != nil {
return err return err
} }
@ -266,7 +155,7 @@ func (ctr *Controller[Entity, Upsert]) Delete(c echo.Context) error {
// Get 通过ID获取数据 // Get 通过ID获取数据
func (ctr *Controller[Entity, Upsert]) Get(c echo.Context) error { func (ctr *Controller[Entity, Upsert]) Get(c echo.Context) error {
id, err := BindId(c, true) id, err := BindID(c)
if err != nil { if err != nil {
return err return err
} }
@ -288,7 +177,7 @@ func (ctr *Controller[Entity, Upsert]) List(c echo.Context) error {
return err return err
} }
qb := repo.NewQueryBuilder(c.Request().Context()) qb := repo.NewQueryBuilder(c.Request().Context())
_, _, err = ParseQuery[Entity](c.QueryParams(), qb) _, _, err = BindQuery[Entity](c, qb)
if err != nil { if err != nil {
return err return err
} }

@ -1,15 +0,0 @@
package app
import "github.com/labstack/echo/v4"
type echoContext struct {
echo.Context
ctx *Context
}
func (e *echoContext) Get(key string) any {
if val, ok := e.ctx.Get(key); ok && val != nil {
return val
}
return e.Context.Get(key)
}

@ -0,0 +1,239 @@
package app
import (
"github.com/labstack/echo/v4"
"net/http"
"reflect"
"sorbet/pkg/db"
"sorbet/pkg/rsp"
"strconv"
"strings"
)
type (
// RequestGuarder 参数守卫函数签名
RequestGuarder func(c echo.Context, req any) error
// BodyBinder 将请求体绑定到结构体上
BodyBinder interface {
BindBody(c echo.Context, i any) (err error)
}
)
// 使用内置数据绑定函数
// 默认使用 echo.DefaultBinder
var binder BodyBinder
// Validate 验证数据
func Validate(c echo.Context, t any, guards ...RequestGuarder) error {
err := c.Validate(t)
if err != nil {
return err
}
for _, guard := range guards {
err = guard(c, t)
if err != nil {
return err
}
}
return nil
}
// Bind 将提交的参数绑定到泛型 T 的实例上
func Bind[T any](c echo.Context, guards ...RequestGuarder) (*T, error) {
var req T
if err := c.Bind(&req); err != nil {
return nil, err
}
if err := Validate(c, &req, guards...); err != nil {
return nil, err
}
return &req, nil
}
// BindBody 将提交请求体绑定到泛型 T 的实例上
func BindBody[T any](c echo.Context, guards ...RequestGuarder) (*T, error) {
b, ok := c.Echo().Binder.(BodyBinder)
if !ok || b == nil {
if binder == nil {
binder = &echo.DefaultBinder{}
}
b = binder
}
var req T
if err := b.BindBody(c, &req); err != nil {
return nil, err
}
if err := Validate(c, &req, guards...); err != nil {
return nil, err
}
return &req, nil
}
type identifier struct {
ID any `json:"id" xml:"id"`
}
// BindID 自请求中获取需要的数据编号
// 查找的是名称为 `id` 的数据,查找顺序如下
// 1. 查看路由中是否定义,比如:`/configs/:id`
// 2. 查看查询字符串中是否存在,比如:`?id=123`
// 3. 查看请求体中是否存在,支持 json 和 xml 两种格式。
func BindID(c echo.Context) (id any, err error) {
defer func() {
if recovered := recover(); recovered != nil {
c.Logger().Debugf("%#v", recovered)
id = nil
err = rsp.ErrBadParams
}
}()
for i, name := range c.ParamNames() {
if name == "id" {
id = c.ParamValues()[i]
if id != "" {
return
}
break
}
}
switch c.Request().Method {
case http.MethodGet, http.MethodDelete, http.MethodHead:
for key, values := range c.QueryParams() {
if key == "id" {
id = values[0]
if id != "" {
return
}
break
}
}
}
if c.Request().ContentLength == 0 {
err = rsp.ErrBadParams
return
}
var data *identifier
data, err = BindBody[identifier](c)
if err != nil {
return nil, err
}
if data.ID == nil {
return nil, rsp.ErrBadParams
}
rv := reflect.ValueOf(data.ID)
if rv.IsZero() || rv.IsNil() {
return nil, rsp.ErrBadParams
}
return data.ID, nil
}
func BindQuery[T any](c echo.Context, qb *db.QueryBuilder[T]) (page, limit int, err error) {
query := c.QueryParams()
var paginating bool
for key, values := range query {
switch key {
case "sortby":
for _, s := range values {
if s[0] == '+' {
qb.AscentBy(s[1:])
} else if s[0] == '-' {
qb.DescentBy(s[1:])
} else {
qb.AscentBy(s)
}
}
case "limit", "page":
var v int
if values[0] != "" {
v, err = strconv.Atoi(values[0])
if err != nil {
return
}
}
if v <= 0 {
err = rsp.ErrInternal
return
}
if key == "limit" {
qb.Limit(v)
limit = v
} else {
paginating = true
page = max(v, 1)
}
default:
v := values[0]
i := strings.IndexByte(key, '#')
if i == -1 {
qb.Eq(key, v)
continue
}
switch k, op := key[:i], key[i+1:]; op {
case "=":
qb.Eq(k, v)
case "!=":
qb.Neq(k, v)
case "<":
qb.Lt(k, v)
case "<=":
qb.Lte(k, v)
case ">":
qb.Gt(k, v)
case ">=":
qb.Gte(k, v)
case "<>", "><":
var less, more any
switch len(values) {
case 2:
less, more = values[0], values[1]
case 1:
vs := strings.Split(v, ",")
if len(vs) != 2 || vs[0] == "" || vs[1] == "" {
err = rsp.ErrBadParams
return
}
less, more = vs[0], vs[1]
default:
err = rsp.ErrBadParams
return
}
if op == "<>" {
qb.Between(k, less, more)
} else {
qb.NotBetween(k, key, more)
}
case "nil":
qb.IsNull(k)
case "!nil":
qb.NotNull(k)
case "~":
qb.Like(k, v)
case "!~":
qb.NotLike(k, v)
case "in", "!in":
if len(values) == 1 {
values = strings.Split(v, ",")
}
vs := make([]any, len(values))
for i, value := range values {
vs[i] = value
}
if op == "in" {
qb.In(k, vs...)
} else {
qb.NotIn(k, vs...)
}
default:
qb.Eq(key, v)
}
}
}
if paginating {
if limit == 0 {
limit = 30
qb.Limit(limit)
}
qb.Offset((page - 1) * limit)
}
return
}
Loading…
Cancel
Save