feat: add tenant commands
This commit is contained in:
BIN
backend/__debug_bin1551459525
Executable file
BIN
backend/__debug_bin1551459525
Executable file
Binary file not shown.
BIN
backend/backend
BIN
backend/backend
Binary file not shown.
@@ -18,8 +18,8 @@ const (
|
|||||||
CtxKeyTx CtxKey = "__ctx_db:"
|
CtxKeyTx CtxKey = "__ctx_db:"
|
||||||
// CtxKeyJwt is a CtxKey of type Jwt.
|
// CtxKeyJwt is a CtxKey of type Jwt.
|
||||||
CtxKeyJwt CtxKey = "__jwt_token:"
|
CtxKeyJwt CtxKey = "__jwt_token:"
|
||||||
// CtxKeySession is a CtxKey of type Session.
|
// CtxKeyClaim is a CtxKey of type Claim.
|
||||||
CtxKeySession CtxKey = "__session_user:"
|
CtxKeyClaim CtxKey = "__jwt_claim:"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrInvalidCtxKey = fmt.Errorf("not a valid CtxKey, try [%s]", strings.Join(_CtxKeyNames, ", "))
|
var ErrInvalidCtxKey = fmt.Errorf("not a valid CtxKey, try [%s]", strings.Join(_CtxKeyNames, ", "))
|
||||||
@@ -27,7 +27,7 @@ var ErrInvalidCtxKey = fmt.Errorf("not a valid CtxKey, try [%s]", strings.Join(_
|
|||||||
var _CtxKeyNames = []string{
|
var _CtxKeyNames = []string{
|
||||||
string(CtxKeyTx),
|
string(CtxKeyTx),
|
||||||
string(CtxKeyJwt),
|
string(CtxKeyJwt),
|
||||||
string(CtxKeySession),
|
string(CtxKeyClaim),
|
||||||
}
|
}
|
||||||
|
|
||||||
// CtxKeyNames returns a list of possible string values of CtxKey.
|
// CtxKeyNames returns a list of possible string values of CtxKey.
|
||||||
@@ -42,7 +42,7 @@ func CtxKeyValues() []CtxKey {
|
|||||||
return []CtxKey{
|
return []CtxKey{
|
||||||
CtxKeyTx,
|
CtxKeyTx,
|
||||||
CtxKeyJwt,
|
CtxKeyJwt,
|
||||||
CtxKeySession,
|
CtxKeyClaim,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,9 +59,9 @@ func (x CtxKey) IsValid() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var _CtxKeyValue = map[string]CtxKey{
|
var _CtxKeyValue = map[string]CtxKey{
|
||||||
"__ctx_db:": CtxKeyTx,
|
"__ctx_db:": CtxKeyTx,
|
||||||
"__jwt_token:": CtxKeyJwt,
|
"__jwt_token:": CtxKeyJwt,
|
||||||
"__session_user:": CtxKeySession,
|
"__jwt_claim:": CtxKeyClaim,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseCtxKey attempts to convert a string to a CtxKey.
|
// ParseCtxKey attempts to convert a string to a CtxKey.
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ package consts
|
|||||||
// ENUM(
|
// ENUM(
|
||||||
// Tx = "__ctx_db:",
|
// Tx = "__ctx_db:",
|
||||||
// Jwt = "__jwt_token:",
|
// Jwt = "__jwt_token:",
|
||||||
// Session = "__session_user:",
|
// Claim = "__jwt_claim:",
|
||||||
// )
|
// )
|
||||||
type CtxKey string
|
type CtxKey string
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
package jwt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"backend/providers/jwt"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetJwtToken(ctx fiber.Ctx) (string, error) {
|
|
||||||
headers, ok := ctx.GetReqHeaders()[jwt.HttpHeader]
|
|
||||||
if !ok {
|
|
||||||
return "", ctx.SendStatus(fiber.StatusUnauthorized)
|
|
||||||
}
|
|
||||||
if len(headers) == 0 {
|
|
||||||
return "", ctx.SendStatus(fiber.StatusUnauthorized)
|
|
||||||
}
|
|
||||||
token := headers[0]
|
|
||||||
|
|
||||||
token = token[len(jwt.TokenPrefix):]
|
|
||||||
return token, nil
|
|
||||||
}
|
|
||||||
@@ -64,7 +64,7 @@ func Serve(cmd *cobra.Command, args []string) error {
|
|||||||
http.Service.Engine.Use(mid.WeChatVerify)
|
http.Service.Engine.Use(mid.WeChatVerify)
|
||||||
http.Service.Engine.Use(mid.WeChatAuthUserInfo)
|
http.Service.Engine.Use(mid.WeChatAuthUserInfo)
|
||||||
http.Service.Engine.Use(mid.WeChatSilentAuth)
|
http.Service.Engine.Use(mid.WeChatSilentAuth)
|
||||||
http.Service.Engine.Use(mid.JwtParse)
|
http.Service.Engine.Use(mid.ParseJWT)
|
||||||
|
|
||||||
mounts := map[string][]string{
|
mounts := map[string][]string{
|
||||||
"/t/{tenant}": {"users", "medias"},
|
"/t/{tenant}": {"users", "medias"},
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package tasks
|
package tasks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"backend/modules/commands/discover"
|
||||||
|
"backend/modules/commands/store"
|
||||||
"backend/modules/medias"
|
"backend/modules/medias"
|
||||||
"backend/modules/tasks/discover"
|
|
||||||
"backend/modules/tasks/store"
|
|
||||||
"backend/providers/app"
|
"backend/providers/app"
|
||||||
"backend/providers/postgres"
|
"backend/providers/postgres"
|
||||||
"backend/providers/storage"
|
"backend/providers/storage"
|
||||||
|
|||||||
73
backend/common/service/tenants/tenants.go
Normal file
73
backend/common/service/tenants/tenants.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package tenants
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"backend/modules/commands/tenant"
|
||||||
|
"backend/modules/medias"
|
||||||
|
"backend/modules/users"
|
||||||
|
"backend/providers/app"
|
||||||
|
"backend/providers/postgres"
|
||||||
|
"backend/providers/storage"
|
||||||
|
|
||||||
|
"git.ipao.vip/rogeecn/atom"
|
||||||
|
"git.ipao.vip/rogeecn/atom/container"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func defaultProviders(providers ...container.ProviderContainer) container.Providers {
|
||||||
|
return append(container.Providers{
|
||||||
|
app.DefaultProvider(),
|
||||||
|
storage.DefaultProvider(),
|
||||||
|
postgres.DefaultProvider(),
|
||||||
|
}, providers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Command() atom.Option {
|
||||||
|
return atom.Command(
|
||||||
|
atom.Name("tenants"),
|
||||||
|
atom.Short("run tenants"),
|
||||||
|
atom.Command(
|
||||||
|
atom.Name("create"),
|
||||||
|
atom.Providers(defaultProviders().With(
|
||||||
|
medias.Provide,
|
||||||
|
users.Provide,
|
||||||
|
tenant.Provide,
|
||||||
|
)),
|
||||||
|
atom.Arguments(func(cmd *cobra.Command) {
|
||||||
|
cmd.Flags().String("slug", "", "slug")
|
||||||
|
}),
|
||||||
|
atom.RunE(func(cmd *cobra.Command, args []string) error {
|
||||||
|
return container.Container.Invoke(func(t *tenant.Create) error {
|
||||||
|
slug := cmd.Flag("slug").Value.String()
|
||||||
|
return t.RunE(args[0], slug)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
atom.Command(
|
||||||
|
atom.Name("expire"),
|
||||||
|
atom.Long("expire [slug] [2024-01-01]"),
|
||||||
|
atom.Providers(defaultProviders().With(
|
||||||
|
medias.Provide,
|
||||||
|
users.Provide,
|
||||||
|
tenant.Provide,
|
||||||
|
)),
|
||||||
|
atom.Arguments(func(cmd *cobra.Command) {
|
||||||
|
}),
|
||||||
|
atom.RunE(func(cmd *cobra.Command, args []string) error {
|
||||||
|
return container.Container.Invoke(func(t *tenant.Expire) error {
|
||||||
|
slug := args[0]
|
||||||
|
expireStr := args[1] // format 2024-01-01
|
||||||
|
// parse expire string as time.Time
|
||||||
|
expire, err := time.Parse("2006-01-02", expireStr)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "parse expire time failed: %s", expireStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.RunE(slug, expire)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
1
backend/common/session.go
Normal file
1
backend/common/session.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package common
|
||||||
@@ -20,7 +20,7 @@ CREATE TABLE
|
|||||||
tenants (
|
tenants (
|
||||||
id SERIAL8 PRIMARY KEY,
|
id SERIAL8 PRIMARY KEY,
|
||||||
name VARCHAR(128) NOT NULL,
|
name VARCHAR(128) NOT NULL,
|
||||||
slug VARCHAR(128) NOT NULL,
|
slug VARCHAR(128) NOT NULL UNIQUE,
|
||||||
description VARCHAR(128),
|
description VARCHAR(128),
|
||||||
expire_at timestamp NOT NULL,
|
expire_at timestamp NOT NULL,
|
||||||
created_at timestamp NOT NULL default now(),
|
created_at timestamp NOT NULL default now(),
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"backend/common/service/migrate"
|
"backend/common/service/migrate"
|
||||||
"backend/common/service/model"
|
"backend/common/service/model"
|
||||||
"backend/common/service/tasks"
|
"backend/common/service/tasks"
|
||||||
|
"backend/common/service/tenants"
|
||||||
|
|
||||||
"git.ipao.vip/rogeecn/atom"
|
"git.ipao.vip/rogeecn/atom"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -20,6 +21,7 @@ func main() {
|
|||||||
migrate.Command(),
|
migrate.Command(),
|
||||||
model.Command(),
|
model.Command(),
|
||||||
tasks.Command(),
|
tasks.Command(),
|
||||||
|
tenants.Command(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := atom.Serve(opts...); err != nil {
|
if err := atom.Serve(opts...); err != nil {
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ func (d *DiscoverMedias) RunE(from, to string) error {
|
|||||||
return errors.Wrapf(err, "glob videos: %s", from)
|
return errors.Wrapf(err, "glob videos: %s", from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := d.ensureDirectory(to); err != nil {
|
||||||
|
return errors.Wrapf(err, "ensure directory: %s", to)
|
||||||
|
}
|
||||||
|
|
||||||
store, err := media_store.NewStore(to)
|
store, err := media_store.NewStore(to)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "new store: %s", to)
|
return errors.Wrapf(err, "new store: %s", to)
|
||||||
@@ -271,7 +275,7 @@ func (d *DiscoverMedias) ffmpegVideoToPoster(video string, output string) error
|
|||||||
// ffmpeg -i input_video.mp4 -ss N -vframes 1 -vf "scale=width:height" output_image.jpg
|
// ffmpeg -i input_video.mp4 -ss N -vframes 1 -vf "scale=width:height" output_image.jpg
|
||||||
args := []string{
|
args := []string{
|
||||||
"-i", video,
|
"-i", video,
|
||||||
"-ss", "00:01:00",
|
"-ss", "00:00:01",
|
||||||
"-vframes", "1",
|
"-vframes", "1",
|
||||||
"-vf", "scale=640:360",
|
"-vf", "scale=640:360",
|
||||||
output,
|
output,
|
||||||
34
backend/modules/commands/tenant/create.go
Normal file
34
backend/modules/commands/tenant/create.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package tenant
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"backend/modules/users"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @provider
|
||||||
|
type Create struct {
|
||||||
|
userSvc *users.Service
|
||||||
|
log *log.Entry `inject:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare
|
||||||
|
func (d *Create) Prepare() error {
|
||||||
|
d.log = log.WithField("module", "tenants.create")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Create) RunE(name, slug string) error {
|
||||||
|
d.log.Infof("create tenant %s(%s)", name, slug)
|
||||||
|
|
||||||
|
err := d.userSvc.CreateTenant(context.Background(), name, slug)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "create tenant: %s(%s)", name, slug)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.log.Infof("create tenant success: %s(%s)", name, slug)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
35
backend/modules/commands/tenant/expire.go
Normal file
35
backend/modules/commands/tenant/expire.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package tenant
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"backend/modules/users"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @provider
|
||||||
|
type Expire struct {
|
||||||
|
userSvc *users.Service
|
||||||
|
log *log.Entry `inject:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare
|
||||||
|
func (d *Expire) Prepare() error {
|
||||||
|
d.log = log.WithField("module", "tenants.create")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Expire) RunE(slug string, expire time.Time) error {
|
||||||
|
d.log.Infof("renew tenant %s expire at s %s", slug, expire)
|
||||||
|
|
||||||
|
err := d.userSvc.SetTenantExpireAtBySlug(context.Background(), slug, expire)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "renew tenant: %s expire at %s", slug, expire)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.log.Infof("renew tenant success: %s expire at %s", slug, expire)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
40
backend/modules/commands/tenant/provider.gen.go
Executable file
40
backend/modules/commands/tenant/provider.gen.go
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
package tenant
|
||||||
|
|
||||||
|
import (
|
||||||
|
"backend/modules/users"
|
||||||
|
|
||||||
|
"git.ipao.vip/rogeecn/atom/container"
|
||||||
|
"git.ipao.vip/rogeecn/atom/utils/opt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Provide(opts ...opt.Option) error {
|
||||||
|
if err := container.Container.Provide(func(
|
||||||
|
userSvc *users.Service,
|
||||||
|
) (*Create, error) {
|
||||||
|
obj := &Create{
|
||||||
|
userSvc: userSvc,
|
||||||
|
}
|
||||||
|
if err := obj.Prepare(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj, nil
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := container.Container.Provide(func(
|
||||||
|
userSvc *users.Service,
|
||||||
|
) (*Expire, error) {
|
||||||
|
obj := &Expire{
|
||||||
|
userSvc: userSvc,
|
||||||
|
}
|
||||||
|
if err := obj.Prepare(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj, nil
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package medias
|
package medias
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"backend/common/consts"
|
||||||
"backend/common/errorx"
|
"backend/common/errorx"
|
||||||
|
"backend/providers/jwt"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
. "github.com/spf13/cast"
|
. "github.com/spf13/cast"
|
||||||
@@ -18,10 +20,9 @@ func (c *Controller) List(ctx fiber.Ctx) error {
|
|||||||
if err := ctx.Bind().Body(&filter); err != nil {
|
if err := ctx.Bind().Body(&filter); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).JSON(errorx.RequestParseError)
|
return ctx.Status(fiber.StatusBadRequest).JSON(errorx.RequestParseError)
|
||||||
}
|
}
|
||||||
|
claim := ctx.Locals(consts.CtxKeyClaim).(*jwt.Claims)
|
||||||
|
|
||||||
tenantId, userId := ToInt64(ctx.Locals("tenantId")), ToInt64(ctx.Locals("userId"))
|
items, err := c.svc.List(ctx.Context(), claim.TenantID, claim.UserID, &filter)
|
||||||
|
|
||||||
items, err := c.svc.List(ctx.Context(), tenantId, userId, &filter)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).JSON(errorx.InternalError)
|
return ctx.Status(fiber.StatusInternalServerError).JSON(errorx.InternalError)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ func (r *Router) Prepare() error {
|
|||||||
|
|
||||||
func (r *Router) Register() any {
|
func (r *Router) Register() any {
|
||||||
r.group.Get("", r.controller.List)
|
r.group.Get("", r.controller.List)
|
||||||
r.group.Get("{id}", r.controller.Show)
|
|
||||||
|
|
||||||
return r.app
|
return r.app
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
package middlewares
|
package middlewares
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"backend/common/consts"
|
"backend/common/consts"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f *Middlewares) JwtParse(c fiber.Ctx) error {
|
func (f *Middlewares) ParseJWT(c fiber.Ctx) error {
|
||||||
tokens := c.GetReqHeaders()["Authorization"]
|
tokens := c.GetReqHeaders()["Authorization"]
|
||||||
if len(tokens) == 0 {
|
if len(tokens) == 0 {
|
||||||
return c.Next()
|
return c.Next()
|
||||||
@@ -22,13 +20,20 @@ func (f *Middlewares) JwtParse(c fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// query user
|
// query user
|
||||||
user, err := f.userSvc.GetByOpenID(c.Context(), claim.ID)
|
user, err := f.userSvc.GetByOpenID(c.Context(), claim.OpenID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to get user")
|
return errors.Wrap(err, "failed to get user")
|
||||||
}
|
}
|
||||||
|
claim.UserID = user.ID
|
||||||
|
|
||||||
c.SetUserContext(context.WithValue(c.UserContext(), consts.CtxKeyJwt, token))
|
tenantId, err := f.userSvc.GetTenantIDBySlug(c.Context(), claim.Tenant)
|
||||||
c.SetUserContext(context.WithValue(c.UserContext(), consts.CtxKeySession, user))
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to get tenant")
|
||||||
|
}
|
||||||
|
claim.TenantID = tenantId
|
||||||
|
|
||||||
|
c.Locals(consts.CtxKeyJwt, token)
|
||||||
|
c.Locals(consts.CtxKeyClaim, claim)
|
||||||
|
|
||||||
return c.Next()
|
return c.Next()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (f *Middlewares) WeChatAuthUserInfo(c fiber.Ctx) error {
|
func (f *Middlewares) WeChatAuthUserInfo(c fiber.Ctx) error {
|
||||||
|
if len(c.GetReqHeaders()["Authorization"]) != 0 {
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
|
||||||
state := c.Query("state")
|
state := c.Query("state")
|
||||||
code := c.Query("code")
|
code := c.Query("code")
|
||||||
|
|
||||||
@@ -40,13 +44,16 @@ func (f *Middlewares) WeChatAuthUserInfo(c fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var oauthInfo pg.UserOAuth
|
var oauthInfo pg.UserOAuth
|
||||||
copier.Copy(&oauthInfo, token)
|
if err := copier.Copy(&oauthInfo, token); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to copy oauth info")
|
||||||
|
}
|
||||||
|
|
||||||
user, err := f.userSvc.GetOrNew(c.Context(), tenantId, token.Openid, oauthInfo)
|
user, err := f.userSvc.GetOrNew(c.Context(), tenantId, token.Openid, oauthInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to get user")
|
return errors.Wrap(err, "failed to get user")
|
||||||
}
|
}
|
||||||
|
|
||||||
claim := f.jwt.CreateClaims(jwt.BaseClaims{UID: uint64(user.ID)})
|
claim := f.jwt.CreateClaims(jwt.BaseClaims{OpenID: user.OpenID})
|
||||||
claim.ID = user.OpenID
|
claim.ID = user.OpenID
|
||||||
jwtToken, err := f.jwt.CreateToken(claim)
|
jwtToken, err := f.jwt.CreateToken(claim)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -208,3 +208,44 @@ func (svc *Service) GetTenantIDBySlug(ctx context.Context, slug string) (int64,
|
|||||||
}
|
}
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateTenant
|
||||||
|
func (svc *Service) CreateTenant(ctx context.Context, name, slug string) error {
|
||||||
|
log := svc.log.WithField("method", "CreateTenant")
|
||||||
|
|
||||||
|
expireAt := time.Now().Add(time.Hour * 24 * 366)
|
||||||
|
// 仅保留天数
|
||||||
|
expireAt = time.Date(expireAt.Year(), expireAt.Month(), expireAt.Day(), 0, 0, 0, 0, expireAt.Location())
|
||||||
|
|
||||||
|
tbl := table.Tenants
|
||||||
|
stmt := tbl.
|
||||||
|
INSERT(tbl.Name, tbl.Slug, tbl.ExpireAt).
|
||||||
|
VALUES(String(name), String(slug), TimestampT(expireAt)).
|
||||||
|
ON_CONFLICT(tbl.Slug).
|
||||||
|
DO_NOTHING()
|
||||||
|
log.Debug(stmt.DebugSql())
|
||||||
|
|
||||||
|
if _, err := stmt.ExecContext(ctx, svc.db); err != nil {
|
||||||
|
return errors.Wrapf(err, "create tenant: %s(%s)", name, slug)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTenantExpireAtBySlug
|
||||||
|
func (svc *Service) SetTenantExpireAtBySlug(ctx context.Context, slug string, expire time.Time) error {
|
||||||
|
log := svc.log.WithField("method", "SetTenantExpireAtBySlug")
|
||||||
|
|
||||||
|
tbl := table.Tenants
|
||||||
|
stmt := tbl.
|
||||||
|
UPDATE(tbl.ExpireAt).
|
||||||
|
SET(TimestampT(expire)).
|
||||||
|
WHERE(tbl.Slug.EQ(String(slug)))
|
||||||
|
log.Debug(stmt.DebugSql())
|
||||||
|
|
||||||
|
if _, err := stmt.ExecContext(ctx, svc.db); err != nil {
|
||||||
|
return errors.Wrapf(err, "renew tenant: %s expire at %s", slug, expire)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type BaseClaims struct {
|
type BaseClaims struct {
|
||||||
UID uint64 `json:"uid,omitempty"`
|
OpenID string `json:"open_id,omitempty"`
|
||||||
Role uint64 `json:"role,omitempty"`
|
Tenant string `json:"tenant,omitempty"`
|
||||||
|
UserID int64 `json:"user_id,omitempty"`
|
||||||
|
TenantID int64 `json:"tenant_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom claims structure
|
// Custom claims structure
|
||||||
|
|||||||
Reference in New Issue
Block a user