diff --git a/backend/app/http/tenants/controller.go b/backend/app/http/tenants/controller.go index 9b4a890..7250e9c 100644 --- a/backend/app/http/tenants/controller.go +++ b/backend/app/http/tenants/controller.go @@ -1,6 +1,10 @@ package tenants import ( + "backend/providers/jwt" + "backend/providers/otel" + + "github.com/gofiber/fiber/v3" log "github.com/sirupsen/logrus" ) @@ -28,3 +32,23 @@ func (c *Controller) Prepare() error { // @Param sortFilter query common.SortQueryFilter true "SortQueryFilter" // @Success 200 {object} common.PageDataResponse{list=dto.AlarmItem} // @Router /v1/test/:id [get] + +// @Router /t/:tenant [get] +// +// @Bind claim local +// @Bind tenant query +func (c *Controller) Index(ctx fiber.Ctx, tenant string, claim *jwt.Claims) error { + _ctx, span := otel.Start(ctx.Context(), "tenants.controller.index") + defer span.End() + + tenantModel, err := c.svc.GetTenantBySlug(_ctx, tenant) + if err != nil { + return err + } + + if err := c.svc.BindUserToTenantIfNotExists(_ctx, tenantModel.ID, claim.UserID); err != nil { + return err + } + + return nil +} diff --git a/backend/app/http/tenants/provider.gen.go b/backend/app/http/tenants/provider.gen.go index c626c17..bade9d4 100755 --- a/backend/app/http/tenants/provider.gen.go +++ b/backend/app/http/tenants/provider.gen.go @@ -3,7 +3,9 @@ package tenants import ( "database/sql" + "git.ipao.vip/rogeecn/atom" "git.ipao.vip/rogeecn/atom/container" + "git.ipao.vip/rogeecn/atom/contracts" "git.ipao.vip/rogeecn/atom/utils/opt" ) @@ -22,6 +24,20 @@ func Provide(opts ...opt.Option) error { }); err != nil { return err } + if err := container.Container.Provide(func( + controller *Controller, + ) (contracts.HttpRoute, error) { + obj := &Routes{ + controller: controller, + } + if err := obj.Prepare(); err != nil { + return nil, err + } + + return obj, nil + }, atom.GroupRoutes); err != nil { + return err + } if err := container.Container.Provide(func( db *sql.DB, ) (*Service, error) { diff --git a/backend/app/http/tenants/routes.gen.go b/backend/app/http/tenants/routes.gen.go new file mode 100644 index 0000000..8ee87cd --- /dev/null +++ b/backend/app/http/tenants/routes.gen.go @@ -0,0 +1,38 @@ +// Code generated by the atomctl ; DO NOT EDIT. + +package tenants + +import ( + . "backend/pkg/f" + "backend/providers/jwt" + + _ "git.ipao.vip/rogeecn/atom" + _ "git.ipao.vip/rogeecn/atom/contracts" + "github.com/gofiber/fiber/v3" + log "github.com/sirupsen/logrus" +) + +// @provider contracts.HttpRoute atom.GroupRoutes +type Routes struct { + log *log.Entry `inject:"false"` + controller *Controller +} + +func (r *Routes) Prepare() error { + r.log = log.WithField("module", "routes.tenants") + return nil +} + +func (r *Routes) Name() string { + return "tenants" +} + +func (r *Routes) Register(router fiber.Router) { + // 注册路由组: Controller + router.Get("/t/:tenant", Func2( + r.controller.Index, + QueryParam[string]("tenant"), + Local[*jwt.Claims]("claim"), + )) + +} diff --git a/backend/app/http/tenants/service.go b/backend/app/http/tenants/service.go index da443bb..2e72974 100644 --- a/backend/app/http/tenants/service.go +++ b/backend/app/http/tenants/service.go @@ -1,10 +1,16 @@ package tenants import ( + "context" "database/sql" + "backend/database/models/qvyun_v2/public/model" + "backend/database/models/qvyun_v2/public/table" + "backend/providers/otel" + . "github.com/go-jet/jet/v2/postgres" log "github.com/sirupsen/logrus" + semconv "go.opentelemetry.io/otel/semconv/v1.15.0" ) // @provider:except @@ -18,3 +24,80 @@ func (svc *Service) Prepare() error { _ = Int(1) return nil } + +// GetTenantBySlug +func (svc *Service) GetTenantBySlug(ctx context.Context, slug string) (*model.Tenants, error) { + ctx, span := otel.Start(ctx, "tenants.service.GetTenantBySlug") + defer span.End() + + tbl := table.Tenants + stmt := tbl. + SELECT(tbl.AllColumns). + WHERE(tbl.Slug.EQ(String(slug))) + + var tenant model.Tenants + if err := stmt.QueryContext(ctx, svc.db, &tenant); err != nil { + return nil, err + } + + return &tenant, nil +} + +// TenantHasUser +func (svc *Service) TenantHasUser(ctx context.Context, tenantID, userID int64) (bool, error) { + ctx, span := otel.Start(ctx, "tenants.service.TenantHasUser") + defer span.End() + + tbl := table.TenantUsers + stmt := tbl. + SELECT(COUNT(tbl.ID).AS("cnt")). + WHERE(tbl.TenantID.EQ(Int(tenantID))). + WHERE(tbl.UserID.EQ(Int(userID))) + span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) + + var count struct { + Cnt int64 + } + + if err := stmt.QueryContext(ctx, svc.db, &count); err != nil { + return false, err + } + + return count.Cnt > 0, nil +} + +// BindUserToTenant +func (svc *Service) BindUserToTenant(ctx context.Context, tenantID, userID int64) error { + ctx, span := otel.Start(ctx, "tenants.service.BindUserToTenant") + defer span.End() + + tbl := table.TenantUsers + stmt := tbl. + INSERT(tbl.TenantID, tbl.UserID). + VALUES(Int(tenantID), Int(userID)). + ON_CONFLICT(). + DO_NOTHING() + span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) + + if _, err := stmt.ExecContext(ctx, svc.db); err != nil { + return err + } + + return nil +} + +// BindUserToTenantIfNotExists +func (svc *Service) BindUserToTenantIfNotExists(ctx context.Context, tenantID, userID int64) error { + ctx, span := otel.Start(ctx, "tenants.service.BindUserToTenantIfNotExists") + defer span.End() + + has, err := svc.TenantHasUser(ctx, tenantID, userID) + if err != nil { + return err + } + + if has { + return nil + } + return svc.BindUserToTenant(ctx, tenantID, userID) +} diff --git a/backend/pkg/f/bind.go b/backend/pkg/f/bind.go index 7a92fdd..5a3713a 100644 --- a/backend/pkg/f/bind.go +++ b/backend/pkg/f/bind.go @@ -5,6 +5,13 @@ import ( "github.com/pkg/errors" ) +func Local[T any](key string) func(fiber.Ctx) (T, error) { + return func(ctx fiber.Ctx) (T, error) { + v := fiber.Locals[T](ctx, key) + return v, nil + } +} + func Path[T fiber.GenericType](key string) func(fiber.Ctx) (T, error) { return func(ctx fiber.Ctx) (T, error) { v := fiber.Params[T](ctx, key)