fix: issues
This commit is contained in:
174
backend/app/consts/consts.gen.go
Normal file
174
backend/app/consts/consts.gen.go
Normal file
@@ -0,0 +1,174 @@
|
||||
// Code generated by go-enum DO NOT EDIT.
|
||||
// Version: -
|
||||
// Revision: -
|
||||
// Build Date: -
|
||||
// Built By: -
|
||||
|
||||
package consts
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// TokenTypeUser is a TokenType of type User.
|
||||
TokenTypeUser TokenType = "__tu"
|
||||
// TokenTypeTenant is a TokenType of type Tenant.
|
||||
TokenTypeTenant TokenType = "__tt"
|
||||
)
|
||||
|
||||
var ErrInvalidTokenType = fmt.Errorf("not a valid TokenType, try [%s]", strings.Join(_TokenTypeNames, ", "))
|
||||
|
||||
var _TokenTypeNames = []string{
|
||||
string(TokenTypeUser),
|
||||
string(TokenTypeTenant),
|
||||
}
|
||||
|
||||
// TokenTypeNames returns a list of possible string values of TokenType.
|
||||
func TokenTypeNames() []string {
|
||||
tmp := make([]string, len(_TokenTypeNames))
|
||||
copy(tmp, _TokenTypeNames)
|
||||
return tmp
|
||||
}
|
||||
|
||||
// TokenTypeValues returns a list of the values for TokenType
|
||||
func TokenTypeValues() []TokenType {
|
||||
return []TokenType{
|
||||
TokenTypeUser,
|
||||
TokenTypeTenant,
|
||||
}
|
||||
}
|
||||
|
||||
// String implements the Stringer interface.
|
||||
func (x TokenType) String() string {
|
||||
return string(x)
|
||||
}
|
||||
|
||||
// IsValid provides a quick way to determine if the typed value is
|
||||
// part of the allowed enumerated values
|
||||
func (x TokenType) IsValid() bool {
|
||||
_, err := ParseTokenType(string(x))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
var _TokenTypeValue = map[string]TokenType{
|
||||
"__tu": TokenTypeUser,
|
||||
"__tt": TokenTypeTenant,
|
||||
}
|
||||
|
||||
// ParseTokenType attempts to convert a string to a TokenType.
|
||||
func ParseTokenType(name string) (TokenType, error) {
|
||||
if x, ok := _TokenTypeValue[name]; ok {
|
||||
return x, nil
|
||||
}
|
||||
return TokenType(""), fmt.Errorf("%s is %w", name, ErrInvalidTokenType)
|
||||
}
|
||||
|
||||
var errTokenTypeNilPtr = errors.New("value pointer is nil") // one per type for package clashes
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (x *TokenType) Scan(value interface{}) (err error) {
|
||||
if value == nil {
|
||||
*x = TokenType("")
|
||||
return
|
||||
}
|
||||
|
||||
// A wider range of scannable types.
|
||||
// driver.Value values at the top of the list for expediency
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
*x, err = ParseTokenType(v)
|
||||
case []byte:
|
||||
*x, err = ParseTokenType(string(v))
|
||||
case TokenType:
|
||||
*x = v
|
||||
case *TokenType:
|
||||
if v == nil {
|
||||
return errTokenTypeNilPtr
|
||||
}
|
||||
*x = *v
|
||||
case *string:
|
||||
if v == nil {
|
||||
return errTokenTypeNilPtr
|
||||
}
|
||||
*x, err = ParseTokenType(*v)
|
||||
default:
|
||||
return errors.New("invalid type for TokenType")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (x TokenType) Value() (driver.Value, error) {
|
||||
return x.String(), nil
|
||||
}
|
||||
|
||||
// Set implements the Golang flag.Value interface func.
|
||||
func (x *TokenType) Set(val string) error {
|
||||
v, err := ParseTokenType(val)
|
||||
*x = v
|
||||
return err
|
||||
}
|
||||
|
||||
// Get implements the Golang flag.Getter interface func.
|
||||
func (x *TokenType) Get() interface{} {
|
||||
return *x
|
||||
}
|
||||
|
||||
// Type implements the github.com/spf13/pFlag Value interface.
|
||||
func (x *TokenType) Type() string {
|
||||
return "TokenType"
|
||||
}
|
||||
|
||||
type NullTokenType struct {
|
||||
TokenType TokenType
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func NewNullTokenType(val interface{}) (x NullTokenType) {
|
||||
err := x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
|
||||
_ = err // make any errcheck linters happy
|
||||
return
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (x *NullTokenType) Scan(value interface{}) (err error) {
|
||||
if value == nil {
|
||||
x.TokenType, x.Valid = TokenType(""), false
|
||||
return
|
||||
}
|
||||
|
||||
err = x.TokenType.Scan(value)
|
||||
x.Valid = (err == nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (x NullTokenType) Value() (driver.Value, error) {
|
||||
if !x.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
// driver.Value accepts int64 for int values.
|
||||
return string(x.TokenType), nil
|
||||
}
|
||||
|
||||
type NullTokenTypeStr struct {
|
||||
NullTokenType
|
||||
}
|
||||
|
||||
func NewNullTokenTypeStr(val interface{}) (x NullTokenTypeStr) {
|
||||
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
|
||||
return
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (x NullTokenTypeStr) Value() (driver.Value, error) {
|
||||
if !x.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return x.TokenType.String(), nil
|
||||
}
|
||||
7
backend/app/consts/consts.go
Normal file
7
backend/app/consts/consts.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package consts
|
||||
|
||||
// swagger:enum TokenType
|
||||
// ENUM(
|
||||
// User = "__tu", Tenant = "__tt"
|
||||
// )
|
||||
type TokenType string
|
||||
@@ -1,71 +0,0 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.ipao.vip/rogeecn/atom/contracts"
|
||||
"github.com/ThreeDotsLabs/watermill"
|
||||
"github.com/ThreeDotsLabs/watermill/message"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var _ contracts.EventHandler = (*UserRegister)(nil)
|
||||
|
||||
type Event struct {
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
type ProcessedEvent struct {
|
||||
ProcessedID int `json:"processed_id"`
|
||||
Time time.Time `json:"time"`
|
||||
}
|
||||
|
||||
// @provider(event)
|
||||
type UserRegister struct {
|
||||
log *logrus.Entry `inject:"false"`
|
||||
}
|
||||
|
||||
func (u *UserRegister) Prepare() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handler implements contracts.EventHandler.
|
||||
func (u *UserRegister) Handler(msg *message.Message) ([]*message.Message, error) {
|
||||
consumedPayload := Event{}
|
||||
err := json.Unmarshal(msg.Payload, &consumedPayload)
|
||||
if err != nil {
|
||||
// When a handler returns an error, the default behavior is to send a Nack (negative-acknowledgement).
|
||||
// The message will be processed again.
|
||||
//
|
||||
// You can change the default behaviour by using middlewares, like Retry or PoisonQueue.
|
||||
// You can also implement your own middleware.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Printf("received event %+v\n", consumedPayload)
|
||||
|
||||
newPayload, err := json.Marshal(ProcessedEvent{
|
||||
ProcessedID: consumedPayload.ID,
|
||||
Time: time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newMessage := message.NewMessage(watermill.NewUUID(), newPayload)
|
||||
|
||||
return nil, nil
|
||||
return []*message.Message{newMessage}, nil
|
||||
}
|
||||
|
||||
// PublishToTopic implements contracts.EventHandler.
|
||||
func (u *UserRegister) PublishToTopic() string {
|
||||
return "event:processed"
|
||||
}
|
||||
|
||||
// Topic implements contracts.EventHandler.
|
||||
func (u *UserRegister) Topic() string {
|
||||
return "event:user-register"
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"backend/providers/events"
|
||||
"backend/providers/event"
|
||||
|
||||
"git.ipao.vip/rogeecn/atom"
|
||||
"git.ipao.vip/rogeecn/atom/container"
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
func Provide(opts ...opt.Option) error {
|
||||
if err := container.Container.Provide(func(
|
||||
__event *events.PubSub,
|
||||
__event *event.PubSub,
|
||||
) (contracts.Initial, error) {
|
||||
obj := &UserRegister{}
|
||||
if err := obj.Prepare(); err != nil {
|
||||
|
||||
174
backend/app/events/topics.gen.go
Normal file
174
backend/app/events/topics.gen.go
Normal file
@@ -0,0 +1,174 @@
|
||||
// Code generated by go-enum DO NOT EDIT.
|
||||
// Version: -
|
||||
// Revision: -
|
||||
// Build Date: -
|
||||
// Built By: -
|
||||
|
||||
package events
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// TopicProcessed is a Topic of type Processed.
|
||||
TopicProcessed Topic = "event:processed"
|
||||
// TopicUserRegister is a Topic of type UserRegister.
|
||||
TopicUserRegister Topic = "user:register"
|
||||
)
|
||||
|
||||
var ErrInvalidTopic = fmt.Errorf("not a valid Topic, try [%s]", strings.Join(_TopicNames, ", "))
|
||||
|
||||
var _TopicNames = []string{
|
||||
string(TopicProcessed),
|
||||
string(TopicUserRegister),
|
||||
}
|
||||
|
||||
// TopicNames returns a list of possible string values of Topic.
|
||||
func TopicNames() []string {
|
||||
tmp := make([]string, len(_TopicNames))
|
||||
copy(tmp, _TopicNames)
|
||||
return tmp
|
||||
}
|
||||
|
||||
// TopicValues returns a list of the values for Topic
|
||||
func TopicValues() []Topic {
|
||||
return []Topic{
|
||||
TopicProcessed,
|
||||
TopicUserRegister,
|
||||
}
|
||||
}
|
||||
|
||||
// String implements the Stringer interface.
|
||||
func (x Topic) String() string {
|
||||
return string(x)
|
||||
}
|
||||
|
||||
// IsValid provides a quick way to determine if the typed value is
|
||||
// part of the allowed enumerated values
|
||||
func (x Topic) IsValid() bool {
|
||||
_, err := ParseTopic(string(x))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
var _TopicValue = map[string]Topic{
|
||||
"event:processed": TopicProcessed,
|
||||
"user:register": TopicUserRegister,
|
||||
}
|
||||
|
||||
// ParseTopic attempts to convert a string to a Topic.
|
||||
func ParseTopic(name string) (Topic, error) {
|
||||
if x, ok := _TopicValue[name]; ok {
|
||||
return x, nil
|
||||
}
|
||||
return Topic(""), fmt.Errorf("%s is %w", name, ErrInvalidTopic)
|
||||
}
|
||||
|
||||
var errTopicNilPtr = errors.New("value pointer is nil") // one per type for package clashes
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (x *Topic) Scan(value interface{}) (err error) {
|
||||
if value == nil {
|
||||
*x = Topic("")
|
||||
return
|
||||
}
|
||||
|
||||
// A wider range of scannable types.
|
||||
// driver.Value values at the top of the list for expediency
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
*x, err = ParseTopic(v)
|
||||
case []byte:
|
||||
*x, err = ParseTopic(string(v))
|
||||
case Topic:
|
||||
*x = v
|
||||
case *Topic:
|
||||
if v == nil {
|
||||
return errTopicNilPtr
|
||||
}
|
||||
*x = *v
|
||||
case *string:
|
||||
if v == nil {
|
||||
return errTopicNilPtr
|
||||
}
|
||||
*x, err = ParseTopic(*v)
|
||||
default:
|
||||
return errors.New("invalid type for Topic")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (x Topic) Value() (driver.Value, error) {
|
||||
return x.String(), nil
|
||||
}
|
||||
|
||||
// Set implements the Golang flag.Value interface func.
|
||||
func (x *Topic) Set(val string) error {
|
||||
v, err := ParseTopic(val)
|
||||
*x = v
|
||||
return err
|
||||
}
|
||||
|
||||
// Get implements the Golang flag.Getter interface func.
|
||||
func (x *Topic) Get() interface{} {
|
||||
return *x
|
||||
}
|
||||
|
||||
// Type implements the github.com/spf13/pFlag Value interface.
|
||||
func (x *Topic) Type() string {
|
||||
return "Topic"
|
||||
}
|
||||
|
||||
type NullTopic struct {
|
||||
Topic Topic
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func NewNullTopic(val interface{}) (x NullTopic) {
|
||||
err := x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
|
||||
_ = err // make any errcheck linters happy
|
||||
return
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (x *NullTopic) Scan(value interface{}) (err error) {
|
||||
if value == nil {
|
||||
x.Topic, x.Valid = Topic(""), false
|
||||
return
|
||||
}
|
||||
|
||||
err = x.Topic.Scan(value)
|
||||
x.Valid = (err == nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (x NullTopic) Value() (driver.Value, error) {
|
||||
if !x.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
// driver.Value accepts int64 for int values.
|
||||
return string(x.Topic), nil
|
||||
}
|
||||
|
||||
type NullTopicStr struct {
|
||||
NullTopic
|
||||
}
|
||||
|
||||
func NewNullTopicStr(val interface{}) (x NullTopicStr) {
|
||||
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
|
||||
return
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (x NullTopicStr) Value() (driver.Value, error) {
|
||||
if !x.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return x.Topic.String(), nil
|
||||
}
|
||||
10
backend/app/events/topics.go
Normal file
10
backend/app/events/topics.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package events
|
||||
|
||||
// swagger:enum Topic
|
||||
// ENUM(
|
||||
//
|
||||
// Processed = "event:processed"
|
||||
// UserRegister = "user:register"
|
||||
//
|
||||
// )
|
||||
type Topic string
|
||||
52
backend/app/events/user_register.go
Normal file
52
backend/app/events/user_register.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"git.ipao.vip/rogeecn/atom/contracts"
|
||||
"github.com/ThreeDotsLabs/watermill/message"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
_ contracts.EventHandler = (*UserRegister)(nil)
|
||||
_ contracts.EventPublisher = (*UserRegister)(nil)
|
||||
)
|
||||
|
||||
// @provider(event)
|
||||
type UserRegister struct {
|
||||
log *logrus.Entry `inject:"false" json:"-"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (e *UserRegister) Prepare() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marshal implements contracts.EventPublisher.
|
||||
func (e *UserRegister) Marshal() ([]byte, error) {
|
||||
return json.Marshal(e)
|
||||
}
|
||||
|
||||
// PublishToTopic implements contracts.EventHandler.
|
||||
func (e *UserRegister) PublishToTopic() string {
|
||||
return TopicProcessed.String()
|
||||
}
|
||||
|
||||
// Topic implements contracts.EventHandler.
|
||||
func (e *UserRegister) Topic() string {
|
||||
return TopicUserRegister.String()
|
||||
}
|
||||
|
||||
// Handler implements contracts.EventHandler.
|
||||
func (e *UserRegister) Handler(msg *message.Message) ([]*message.Message, error) {
|
||||
var payload UserRegister
|
||||
err := json.Unmarshal(msg.Payload, &payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e.log.Infof("received event %+v\n", payload)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
120
backend/app/http/auth/controller_wechat.go
Normal file
120
backend/app/http/auth/controller_wechat.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"backend/app/consts"
|
||||
"backend/app/http/users"
|
||||
"backend/providers/jwt"
|
||||
"backend/providers/otel"
|
||||
"backend/providers/wechat"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const StatePrefix = "sns_basic_auth"
|
||||
|
||||
// @provider
|
||||
type Controller struct {
|
||||
svc *Service
|
||||
userSvc *users.Service
|
||||
jwt *jwt.JWT
|
||||
wechat *wechat.Client
|
||||
log *log.Entry `inject:"false"`
|
||||
}
|
||||
|
||||
func (ctl *Controller) Prepare() error {
|
||||
ctl.log = log.WithField("module", "auth.Controller")
|
||||
return nil
|
||||
}
|
||||
|
||||
// @Router /v1/auth/wechat/jump/:tenant [get]
|
||||
// @Bind tenant path
|
||||
// @Bind redirectUri query
|
||||
func (ctl *Controller) JumpToAuth(ctx fiber.Ctx, tenant, redirectUri string) error {
|
||||
_, span := otel.Start(ctx.Context(), "auth.controller.wechat")
|
||||
defer span.End()
|
||||
|
||||
ctl.log.Debugf("%s, query: %v", ctx.OriginalURL(), ctx.Queries())
|
||||
|
||||
paramRedirect := ctx.Query("redirect")
|
||||
|
||||
// 添加 redirect 参数
|
||||
u, err := url.Parse(string(ctx.Request().URI().FullURI()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
query := u.Query()
|
||||
query.Set("redirect", paramRedirect)
|
||||
u.RawQuery = query.Encode()
|
||||
u.Path = "/v1/auth/wechat/login/" + tenant
|
||||
fullUrl := u.String()
|
||||
|
||||
ctl.log.WithField("module", "middleware.SilentAuth").Debug("redirect_uri: ", fullUrl)
|
||||
|
||||
to, err := ctl.wechat.ScopeAuthorizeURL(
|
||||
wechat.ScopeAuthorizeURLWithRedirectURI(fullUrl),
|
||||
wechat.ScopeAuthorizeURLWithState(fmt.Sprintf("%s-%d", StatePrefix, time.Now().UnixNano())),
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get wechat auth url")
|
||||
}
|
||||
|
||||
return ctx.Redirect().To(to.String())
|
||||
}
|
||||
|
||||
// @Router /v1/auth/login/:tenant [get]
|
||||
// @Bind tenant path
|
||||
// @Bind code query
|
||||
// @Bind state query
|
||||
// @Bind redirectUri query
|
||||
func (ctl *Controller) Login(ctx fiber.Ctx, code, state, tenant, redirectUri string) error {
|
||||
ctl.log.Debugf("code: %s, state: %s", code, state)
|
||||
|
||||
ctx.Cookie(&fiber.Cookie{
|
||||
Name: consts.TokenTypeUser.String(),
|
||||
Value: "",
|
||||
Expires: time.Now().Add(12 * time.Hour),
|
||||
HTTPOnly: true,
|
||||
})
|
||||
|
||||
// get the openid
|
||||
token, err := ctl.wechat.AuthorizeCode2Token(code)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get openid")
|
||||
}
|
||||
ctl.log.Debugf("tokenInfo %+v", token)
|
||||
|
||||
user, err := ctl.userSvc.GetOrNewFromChannel(ctx.Context(), consts.AuthChannelWeChat, token.OpenID, tenant)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get user")
|
||||
}
|
||||
|
||||
claim := c.jwt.CreateClaims(jwt.BaseClaims{
|
||||
OpenID: user.OpenID,
|
||||
Tenant: tenantSlug,
|
||||
UserID: user.ID,
|
||||
TenantID: tenant.ID,
|
||||
})
|
||||
jwtToken, err = c.jwt.CreateToken(claim)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create token")
|
||||
}
|
||||
|
||||
ctx.Cookie(&fiber.Cookie{
|
||||
Name: "token",
|
||||
Value: jwtToken,
|
||||
Expires: time.Now().Add(6 * time.Hour),
|
||||
HTTPOnly: true,
|
||||
})
|
||||
|
||||
html := strings.ReplaceAll(string(b), "{{JWT}}", jwtToken)
|
||||
return ctx.SendString(html)
|
||||
|
||||
return ctx.Redirect().To(paramRedirect)
|
||||
}
|
||||
1
backend/app/http/auth/dto.go
Normal file
1
backend/app/http/auth/dto.go
Normal file
@@ -0,0 +1 @@
|
||||
package auth
|
||||
50
backend/app/http/auth/provider.gen.go
Executable file
50
backend/app/http/auth/provider.gen.go
Executable file
@@ -0,0 +1,50 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"backend/app/http/users"
|
||||
"backend/providers/jwt"
|
||||
"backend/providers/wechat"
|
||||
|
||||
"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(
|
||||
jwt *jwt.JWT,
|
||||
svc *Service,
|
||||
userSvc *users.Service,
|
||||
wechat *wechat.Client,
|
||||
) (*Controller, error) {
|
||||
obj := &Controller{
|
||||
jwt: jwt,
|
||||
svc: svc,
|
||||
userSvc: userSvc,
|
||||
wechat: wechat,
|
||||
}
|
||||
if err := obj.Prepare(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func(
|
||||
db *sql.DB,
|
||||
) (*Service, error) {
|
||||
obj := &Service{
|
||||
db: db,
|
||||
}
|
||||
if err := obj.Prepare(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
20
backend/app/http/auth/service.go
Normal file
20
backend/app/http/auth/service.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
. "github.com/go-jet/jet/v2/postgres"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// @provider:except
|
||||
type Service struct {
|
||||
db *sql.DB
|
||||
log *log.Entry `inject:"false"`
|
||||
}
|
||||
|
||||
func (svc *Service) Prepare() error {
|
||||
svc.log = log.WithField("module", "auth.service")
|
||||
_ = Int(1)
|
||||
return nil
|
||||
}
|
||||
37
backend/app/http/auth/service_test.go
Normal file
37
backend/app/http/auth/service_test.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"backend/app/service/testx"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"go.uber.org/dig"
|
||||
)
|
||||
|
||||
type ServiceInjectParams struct {
|
||||
dig.In
|
||||
Svc *Service
|
||||
}
|
||||
|
||||
type ServiceTestSuite struct {
|
||||
suite.Suite
|
||||
ServiceInjectParams
|
||||
}
|
||||
|
||||
func Test_DiscoverMedias(t *testing.T) {
|
||||
providers := testx.Default().With(
|
||||
Provide,
|
||||
)
|
||||
|
||||
testx.Serve(providers, t, func(params ServiceInjectParams) {
|
||||
suite.Run(t, &ServiceTestSuite{ServiceInjectParams: params})
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ServiceTestSuite) Test_Service() {
|
||||
Convey("Test Service", s.T(), func() {
|
||||
So(s.Svc, ShouldNotBeNil)
|
||||
})
|
||||
}
|
||||
30
backend/app/http/tenants/controller.go
Normal file
30
backend/app/http/tenants/controller.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package tenants
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// @provider
|
||||
type Controller struct {
|
||||
svc *Service
|
||||
log *log.Entry `inject:"false"`
|
||||
}
|
||||
|
||||
func (c *Controller) Prepare() error {
|
||||
c.log = log.WithField("module", "tenants.Controller")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Test godoc
|
||||
//
|
||||
// @Summary Test
|
||||
// @Description Test
|
||||
// @Tags Test
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "AccountID"
|
||||
// @Param queryFilter query dto.AlarmListQuery true "AlarmListQueryFilter"
|
||||
// @Param pageFilter query common.PageQueryFilter true "PageQueryFilter"
|
||||
// @Param sortFilter query common.SortQueryFilter true "SortQueryFilter"
|
||||
// @Success 200 {object} common.PageDataResponse{list=dto.AlarmItem}
|
||||
// @Router /v1/test/:id<int> [get]
|
||||
1
backend/app/http/tenants/dto.go
Normal file
1
backend/app/http/tenants/dto.go
Normal file
@@ -0,0 +1 @@
|
||||
package tenants
|
||||
40
backend/app/http/tenants/provider.gen.go
Executable file
40
backend/app/http/tenants/provider.gen.go
Executable file
@@ -0,0 +1,40 @@
|
||||
package tenants
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"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(
|
||||
svc *Service,
|
||||
) (*Controller, error) {
|
||||
obj := &Controller{
|
||||
svc: svc,
|
||||
}
|
||||
if err := obj.Prepare(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func(
|
||||
db *sql.DB,
|
||||
) (*Service, error) {
|
||||
obj := &Service{
|
||||
db: db,
|
||||
}
|
||||
if err := obj.Prepare(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
20
backend/app/http/tenants/service.go
Normal file
20
backend/app/http/tenants/service.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package tenants
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
. "github.com/go-jet/jet/v2/postgres"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// @provider:except
|
||||
type Service struct {
|
||||
db *sql.DB
|
||||
log *log.Entry `inject:"false"`
|
||||
}
|
||||
|
||||
func (svc *Service) Prepare() error {
|
||||
svc.log = log.WithField("module", "tenants.service")
|
||||
_ = Int(1)
|
||||
return nil
|
||||
}
|
||||
37
backend/app/http/tenants/service_test.go
Normal file
37
backend/app/http/tenants/service_test.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package tenants
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"backend/app/service/testx"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"go.uber.org/dig"
|
||||
)
|
||||
|
||||
type ServiceInjectParams struct {
|
||||
dig.In
|
||||
Svc *Service
|
||||
}
|
||||
|
||||
type ServiceTestSuite struct {
|
||||
suite.Suite
|
||||
ServiceInjectParams
|
||||
}
|
||||
|
||||
func Test_DiscoverMedias(t *testing.T) {
|
||||
providers := testx.Default().With(
|
||||
Provide,
|
||||
)
|
||||
|
||||
testx.Serve(providers, t, func(params ServiceInjectParams) {
|
||||
suite.Run(t, &ServiceTestSuite{ServiceInjectParams: params})
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ServiceTestSuite) Test_Service() {
|
||||
Convey("Test Service", s.T(), func() {
|
||||
So(s.Svc, ShouldNotBeNil)
|
||||
})
|
||||
}
|
||||
30
backend/app/http/users/controller.go
Normal file
30
backend/app/http/users/controller.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// @provider
|
||||
type Controller struct {
|
||||
svc *Service
|
||||
log *log.Entry `inject:"false"`
|
||||
}
|
||||
|
||||
func (c *Controller) Prepare() error {
|
||||
c.log = log.WithField("module", "users.Controller")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Test godoc
|
||||
//
|
||||
// @Summary Test
|
||||
// @Description Test
|
||||
// @Tags Test
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "AccountID"
|
||||
// @Param queryFilter query dto.AlarmListQuery true "AlarmListQueryFilter"
|
||||
// @Param pageFilter query common.PageQueryFilter true "PageQueryFilter"
|
||||
// @Param sortFilter query common.SortQueryFilter true "SortQueryFilter"
|
||||
// @Success 200 {object} common.PageDataResponse{list=dto.AlarmItem}
|
||||
// @Router /v1/test/:id<int> [get]
|
||||
1
backend/app/http/users/dto.go
Normal file
1
backend/app/http/users/dto.go
Normal file
@@ -0,0 +1 @@
|
||||
package users
|
||||
40
backend/app/http/users/provider.gen.go
Executable file
40
backend/app/http/users/provider.gen.go
Executable file
@@ -0,0 +1,40 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"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(
|
||||
svc *Service,
|
||||
) (*Controller, error) {
|
||||
obj := &Controller{
|
||||
svc: svc,
|
||||
}
|
||||
if err := obj.Prepare(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func(
|
||||
db *sql.DB,
|
||||
) (*Service, error) {
|
||||
obj := &Service{
|
||||
db: db,
|
||||
}
|
||||
if err := obj.Prepare(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
201
backend/app/http/users/service.go
Normal file
201
backend/app/http/users/service.go
Normal file
@@ -0,0 +1,201 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"backend/app/events"
|
||||
"backend/database/fields"
|
||||
"backend/database/models/qvyun_v2/public/model"
|
||||
"backend/database/models/qvyun_v2/public/table"
|
||||
"backend/pkg/oauth"
|
||||
"backend/providers/event"
|
||||
"backend/providers/otel"
|
||||
|
||||
. "github.com/go-jet/jet/v2/postgres"
|
||||
"github.com/samber/lo"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.15.0"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// @provider:except
|
||||
type Service struct {
|
||||
db *sql.DB
|
||||
event *event.PubSub
|
||||
log *log.Entry `inject:"false"`
|
||||
}
|
||||
|
||||
func (svc *Service) Prepare() error {
|
||||
svc.log = log.WithField("module", "users.service")
|
||||
_ = Int(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUsersByOpenID Get user by open id
|
||||
func (svc *Service) GetUserByOpenID(ctx context.Context, channel fields.AuthChannel, openID string) (*model.Users, error) {
|
||||
_, span := otel.Start(ctx, "users.service.GetUsersByOpenID")
|
||||
defer span.End()
|
||||
|
||||
userId, err := svc.GetUserIDByOpenID(ctx, channel, openID)
|
||||
if err != nil {
|
||||
// span 添加用户不存在事件
|
||||
span.AddEvent("user not found")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tbl := table.Users
|
||||
stmt := tbl.SELECT(tbl.AllColumns).WHERE(tbl.ID.EQ(Int64(userId)))
|
||||
span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql()))
|
||||
|
||||
var user model.Users
|
||||
if err := stmt.QueryContext(ctx, svc.db, &user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (svc *Service) GetUserIDByOpenID(ctx context.Context, channel fields.AuthChannel, openID string) (int64, error) {
|
||||
_, span := otel.Start(ctx, "users.service.GetUserIDByOpenID")
|
||||
defer span.End()
|
||||
|
||||
span.SetAttributes(
|
||||
attribute.String("channel", channel.String()),
|
||||
attribute.String("openID", openID),
|
||||
)
|
||||
|
||||
tbl := table.UserOauths
|
||||
|
||||
stmt := tbl.
|
||||
SELECT(tbl.UserID.AS("user_id")).
|
||||
WHERE(
|
||||
tbl.Channel.EQ(Int16(int16(channel))).
|
||||
AND(tbl.OpenID.EQ(String(openID))),
|
||||
)
|
||||
span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql()))
|
||||
|
||||
var result struct {
|
||||
UserID int64
|
||||
}
|
||||
|
||||
if err := stmt.QueryContext(ctx, svc.db, &result); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return result.UserID, nil
|
||||
}
|
||||
|
||||
// CreateUser
|
||||
func (svc *Service) CreateUser(ctx context.Context, user *model.Users) (*model.Users, error) {
|
||||
_, span := otel.Start(ctx, "users.service.CreateUser")
|
||||
defer span.End()
|
||||
span.SetAttributes(
|
||||
attribute.String("user.username", user.Username),
|
||||
attribute.String("user.email", user.Email),
|
||||
attribute.String("user.phone", user.Phone),
|
||||
)
|
||||
|
||||
if user.CreatedAt.IsZero() {
|
||||
user.CreatedAt = time.Now()
|
||||
}
|
||||
|
||||
if user.UpdatedAt.IsZero() {
|
||||
user.UpdatedAt = time.Now()
|
||||
}
|
||||
|
||||
user.Status = int16(fields.UserStatusPending)
|
||||
|
||||
// use bcrypt to hash password
|
||||
pwd, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.Password = string(pwd)
|
||||
|
||||
tbl := table.Users
|
||||
stmt := tbl.INSERT(tbl.MutableColumns).MODEL(user).ON_CONFLICT(tbl.Email, tbl.Phone, tbl.Username).DO_NOTHING().RETURNING(tbl.AllColumns)
|
||||
span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql()))
|
||||
|
||||
var m model.Users
|
||||
if err = stmt.QueryContext(ctx, svc.db, &m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if user created successfully, trigger event
|
||||
span.AddEvent("user created")
|
||||
svc.event.Publish(&events.UserRegister{ID: m.ID})
|
||||
|
||||
return &m, err
|
||||
}
|
||||
|
||||
// GetUserByID
|
||||
func (svc *Service) GetUserByID(ctx context.Context, userID int64) (*model.Users, error) {
|
||||
_, span := otel.Start(ctx, "users.service.GetUserByID")
|
||||
defer span.End()
|
||||
span.SetAttributes(
|
||||
attribute.Int64("user.id", userID),
|
||||
)
|
||||
|
||||
tbl := table.Users
|
||||
stmt := tbl.SELECT(tbl.AllColumns).WHERE(tbl.ID.EQ(Int64(userID)))
|
||||
span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql()))
|
||||
|
||||
var user model.Users
|
||||
if err := stmt.QueryContext(ctx, svc.db, &user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// AttachUserOAuth
|
||||
func (svc *Service) AttachUserOAuth(ctx context.Context, user *model.Users, channel fields.AuthChannel, oauthInfo oauth.OAuthInfo) error {
|
||||
_, span := otel.Start(ctx, "users.service.AttachUserOAuth")
|
||||
defer span.End()
|
||||
span.SetAttributes(
|
||||
attribute.Int64("user.id", user.ID),
|
||||
attribute.String("channel", channel.String()),
|
||||
attribute.String("openID", oauthInfo.GetOpenID()),
|
||||
)
|
||||
|
||||
m := &model.UserOauths{
|
||||
ID: 0,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
DeletedAt: nil,
|
||||
Channel: channel,
|
||||
UserID: user.ID,
|
||||
UnionID: lo.ToPtr(oauthInfo.GetUnionID()),
|
||||
OpenID: oauthInfo.GetOpenID(),
|
||||
AccessToken: oauthInfo.GetAccessToken(),
|
||||
RefreshToken: oauthInfo.GetRefreshToken(),
|
||||
ExpireAt: oauthInfo.GetExpiredAt(),
|
||||
Meta: new(string),
|
||||
}
|
||||
|
||||
tbl := table.UserOauths
|
||||
stmt := tbl.
|
||||
INSERT(tbl.MutableColumns).
|
||||
MODEL(m).
|
||||
ON_CONFLICT(tbl.Channel, tbl.UserID).
|
||||
DO_UPDATE(
|
||||
SET(
|
||||
tbl.UnionID.SET(String(oauthInfo.GetUnionID())),
|
||||
tbl.OpenID.SET(String(oauthInfo.GetOpenID())),
|
||||
tbl.AccessToken.SET(String(oauthInfo.GetAccessToken())),
|
||||
tbl.RefreshToken.SET(String(oauthInfo.GetRefreshToken())),
|
||||
tbl.ExpireAt.SET(TimestampT(oauthInfo.GetExpiredAt())),
|
||||
),
|
||||
)
|
||||
|
||||
span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql()))
|
||||
|
||||
if _, err := stmt.ExecContext(ctx, svc.db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
109
backend/app/http/users/service_test.go
Normal file
109
backend/app/http/users/service_test.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"backend/app/service/testx"
|
||||
"backend/database"
|
||||
"backend/database/fields"
|
||||
"backend/database/models/qvyun_v2/public/model"
|
||||
"backend/database/models/qvyun_v2/public/table"
|
||||
|
||||
"git.ipao.vip/rogeecn/atom/contracts"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"go.uber.org/dig"
|
||||
)
|
||||
|
||||
type ServiceInjectParams struct {
|
||||
dig.In
|
||||
Initials []contracts.Initial `group:"initials"`
|
||||
|
||||
Svc *Service
|
||||
}
|
||||
|
||||
type ServiceTestSuite struct {
|
||||
suite.Suite
|
||||
ServiceInjectParams
|
||||
}
|
||||
|
||||
func Test_DiscoverMedias(t *testing.T) {
|
||||
providers := testx.Default().With(
|
||||
Provide,
|
||||
)
|
||||
|
||||
testx.Serve(providers, t, func(params ServiceInjectParams) {
|
||||
suite.Run(t, &ServiceTestSuite{ServiceInjectParams: params})
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ServiceTestSuite) Test_GetUserIDByOpenID() {
|
||||
Convey("Test GetUserIDByOpenID", s.T(), func() {
|
||||
v, err := fields.AuthChannelWeChat.Value()
|
||||
So(err, ShouldBeNil)
|
||||
So(v, ShouldEqual, 1)
|
||||
|
||||
Convey("truncate tables", func() {
|
||||
err := database.Truncate(context.Background(), s.Svc.db, table.UserOauths.TableName())
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("insert data", func() {
|
||||
m := model.UserOauths{
|
||||
Channel: fields.AuthChannelWeChat,
|
||||
UserID: 1,
|
||||
OpenID: "test_open_id",
|
||||
AccessKey: "test_access_key",
|
||||
AccessToken: "test_access_token",
|
||||
RefreshToken: "test_refresh_token",
|
||||
ExpireAt: time.Now().Add(time.Hour),
|
||||
}
|
||||
|
||||
tbl := table.UserOauths
|
||||
stmt := tbl.INSERT(
|
||||
tbl.MutableColumns.Except(
|
||||
tbl.CreatedAt,
|
||||
tbl.UpdatedAt,
|
||||
tbl.DeletedAt,
|
||||
tbl.UnionID,
|
||||
tbl.Meta,
|
||||
),
|
||||
).MODEL(m)
|
||||
s.T().Log(stmt.Sql())
|
||||
|
||||
_, err := stmt.ExecContext(context.Background(), s.Svc.db)
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("get user id by open id", func() {
|
||||
userID, err := s.Svc.GetUserIDByOpenID(context.Background(), fields.AuthChannelWeChat, "test_open_id")
|
||||
So(err, ShouldBeNil)
|
||||
So(userID, ShouldEqual, 1)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// CreateUser
|
||||
func (s *ServiceTestSuite) Test_CreateUser() {
|
||||
Convey("Test CreateUser", s.T(), func() {
|
||||
Convey("truncate tables", func() {
|
||||
err := database.Truncate(context.Background(), s.Svc.db, table.Users.TableName())
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("create user", func() {
|
||||
user := &model.Users{
|
||||
Email: "test@qq.com",
|
||||
Phone: "12345678901",
|
||||
Username: "test",
|
||||
Password: "test",
|
||||
Age: 18,
|
||||
}
|
||||
|
||||
_, err := s.Svc.CreateUser(context.Background(), user)
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -1,13 +1,28 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"backend/providers/app"
|
||||
"backend/providers/jwt"
|
||||
"backend/providers/storage"
|
||||
"backend/providers/wechat"
|
||||
|
||||
"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() (*Middlewares, error) {
|
||||
obj := &Middlewares{}
|
||||
if err := container.Container.Provide(func(
|
||||
app *app.Config,
|
||||
client *wechat.Client,
|
||||
jwt *jwt.JWT,
|
||||
storagePath *storage.Config,
|
||||
) (*Middlewares, error) {
|
||||
obj := &Middlewares{
|
||||
app: app,
|
||||
client: client,
|
||||
jwt: jwt,
|
||||
storagePath: storagePath,
|
||||
}
|
||||
if err := obj.Prepare(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"backend/app/events"
|
||||
"backend/app/service"
|
||||
"backend/providers/app"
|
||||
providerEvents "backend/providers/events"
|
||||
"backend/providers/event"
|
||||
"backend/providers/postgres"
|
||||
|
||||
"git.ipao.vip/rogeecn/atom"
|
||||
@@ -41,7 +41,7 @@ type Service struct {
|
||||
dig.In
|
||||
|
||||
App *app.Config
|
||||
PubSub *providerEvents.PubSub
|
||||
PubSub *event.PubSub
|
||||
Initials []contracts.Initial `group:"initials"`
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"git.ipao.vip/rogeecn/atom"
|
||||
"git.ipao.vip/rogeecn/atom/container"
|
||||
"git.ipao.vip/rogeecn/atom/contracts"
|
||||
"github.com/gofiber/fiber/v3"
|
||||
"github.com/gofiber/fiber/v3/middleware/favicon"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -69,6 +70,10 @@ func Serve(cmd *cobra.Command, args []string) error {
|
||||
svc.Http.Engine.Get("/swagger/*", swagger.HandlerDefault)
|
||||
}
|
||||
|
||||
svc.Http.Engine.Get("MP_verify_dEF9kn8rJlBsuLKk.txt", func(c fiber.Ctx) error {
|
||||
return c.SendString("dEF9kn8rJlBsuLKk")
|
||||
})
|
||||
|
||||
svc.Http.Engine.Use(svc.Middlewares.WeChatVerify)
|
||||
svc.Http.Engine.Use(errorx.Middleware)
|
||||
svc.Http.Engine.Use(favicon.New(favicon.Config{
|
||||
|
||||
@@ -2,7 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"backend/providers/app"
|
||||
"backend/providers/events"
|
||||
"backend/providers/event"
|
||||
|
||||
"git.ipao.vip/rogeecn/atom/container"
|
||||
)
|
||||
@@ -10,6 +10,6 @@ import (
|
||||
func Default(providers ...container.ProviderContainer) container.Providers {
|
||||
return append(container.Providers{
|
||||
app.DefaultProvider(),
|
||||
events.DefaultProvider(),
|
||||
event.DefaultProvider(),
|
||||
}, providers...)
|
||||
}
|
||||
|
||||
@@ -4,18 +4,27 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"backend/providers/otel"
|
||||
"backend/providers/postgres"
|
||||
|
||||
"git.ipao.vip/rogeecn/atom"
|
||||
"git.ipao.vip/rogeecn/atom/container"
|
||||
"github.com/rogeecn/fabfile"
|
||||
log "github.com/sirupsen/logrus"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Default(providers ...container.ProviderContainer) container.Providers {
|
||||
return append(container.Providers{}, providers...)
|
||||
return append(container.Providers{
|
||||
otel.DefaultProvider(),
|
||||
postgres.DefaultProvider(),
|
||||
}, providers...)
|
||||
}
|
||||
|
||||
func Serve(providers container.Providers, t *testing.T, invoke any) {
|
||||
Convey("tests boot up", t, func() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
file := fabfile.MustFind("config.toml")
|
||||
|
||||
localEnv := os.Getenv("ENV_LOCAL")
|
||||
|
||||
Reference in New Issue
Block a user