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
|
package events
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"backend/providers/events"
|
"backend/providers/event"
|
||||||
|
|
||||||
"git.ipao.vip/rogeecn/atom"
|
"git.ipao.vip/rogeecn/atom"
|
||||||
"git.ipao.vip/rogeecn/atom/container"
|
"git.ipao.vip/rogeecn/atom/container"
|
||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
func Provide(opts ...opt.Option) error {
|
func Provide(opts ...opt.Option) error {
|
||||||
if err := container.Container.Provide(func(
|
if err := container.Container.Provide(func(
|
||||||
__event *events.PubSub,
|
__event *event.PubSub,
|
||||||
) (contracts.Initial, error) {
|
) (contracts.Initial, error) {
|
||||||
obj := &UserRegister{}
|
obj := &UserRegister{}
|
||||||
if err := obj.Prepare(); err != nil {
|
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
|
package middlewares
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"backend/providers/app"
|
||||||
|
"backend/providers/jwt"
|
||||||
|
"backend/providers/storage"
|
||||||
|
"backend/providers/wechat"
|
||||||
|
|
||||||
"git.ipao.vip/rogeecn/atom/container"
|
"git.ipao.vip/rogeecn/atom/container"
|
||||||
"git.ipao.vip/rogeecn/atom/utils/opt"
|
"git.ipao.vip/rogeecn/atom/utils/opt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Provide(opts ...opt.Option) error {
|
func Provide(opts ...opt.Option) error {
|
||||||
if err := container.Container.Provide(func() (*Middlewares, error) {
|
if err := container.Container.Provide(func(
|
||||||
obj := &Middlewares{}
|
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 {
|
if err := obj.Prepare(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"backend/app/events"
|
"backend/app/events"
|
||||||
"backend/app/service"
|
"backend/app/service"
|
||||||
"backend/providers/app"
|
"backend/providers/app"
|
||||||
providerEvents "backend/providers/events"
|
"backend/providers/event"
|
||||||
"backend/providers/postgres"
|
"backend/providers/postgres"
|
||||||
|
|
||||||
"git.ipao.vip/rogeecn/atom"
|
"git.ipao.vip/rogeecn/atom"
|
||||||
@@ -41,7 +41,7 @@ type Service struct {
|
|||||||
dig.In
|
dig.In
|
||||||
|
|
||||||
App *app.Config
|
App *app.Config
|
||||||
PubSub *providerEvents.PubSub
|
PubSub *event.PubSub
|
||||||
Initials []contracts.Initial `group:"initials"`
|
Initials []contracts.Initial `group:"initials"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
"git.ipao.vip/rogeecn/atom"
|
"git.ipao.vip/rogeecn/atom"
|
||||||
"git.ipao.vip/rogeecn/atom/container"
|
"git.ipao.vip/rogeecn/atom/container"
|
||||||
"git.ipao.vip/rogeecn/atom/contracts"
|
"git.ipao.vip/rogeecn/atom/contracts"
|
||||||
|
"github.com/gofiber/fiber/v3"
|
||||||
"github.com/gofiber/fiber/v3/middleware/favicon"
|
"github.com/gofiber/fiber/v3/middleware/favicon"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"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("/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(svc.Middlewares.WeChatVerify)
|
||||||
svc.Http.Engine.Use(errorx.Middleware)
|
svc.Http.Engine.Use(errorx.Middleware)
|
||||||
svc.Http.Engine.Use(favicon.New(favicon.Config{
|
svc.Http.Engine.Use(favicon.New(favicon.Config{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"backend/providers/app"
|
"backend/providers/app"
|
||||||
"backend/providers/events"
|
"backend/providers/event"
|
||||||
|
|
||||||
"git.ipao.vip/rogeecn/atom/container"
|
"git.ipao.vip/rogeecn/atom/container"
|
||||||
)
|
)
|
||||||
@@ -10,6 +10,6 @@ import (
|
|||||||
func Default(providers ...container.ProviderContainer) container.Providers {
|
func Default(providers ...container.ProviderContainer) container.Providers {
|
||||||
return append(container.Providers{
|
return append(container.Providers{
|
||||||
app.DefaultProvider(),
|
app.DefaultProvider(),
|
||||||
events.DefaultProvider(),
|
event.DefaultProvider(),
|
||||||
}, providers...)
|
}, providers...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,27 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"backend/providers/otel"
|
||||||
|
"backend/providers/postgres"
|
||||||
|
|
||||||
"git.ipao.vip/rogeecn/atom"
|
"git.ipao.vip/rogeecn/atom"
|
||||||
"git.ipao.vip/rogeecn/atom/container"
|
"git.ipao.vip/rogeecn/atom/container"
|
||||||
"github.com/rogeecn/fabfile"
|
"github.com/rogeecn/fabfile"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Default(providers ...container.ProviderContainer) container.Providers {
|
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) {
|
func Serve(providers container.Providers, t *testing.T, invoke any) {
|
||||||
Convey("tests boot up", t, func() {
|
Convey("tests boot up", t, func() {
|
||||||
|
log.SetLevel(log.DebugLevel)
|
||||||
|
|
||||||
file := fabfile.MustFind("config.toml")
|
file := fabfile.MustFind("config.toml")
|
||||||
|
|
||||||
localEnv := os.Getenv("ENV_LOCAL")
|
localEnv := os.Getenv("ENV_LOCAL")
|
||||||
|
|||||||
277
backend/database/fields/user_oauths.gen.go
Normal file
277
backend/database/fields/user_oauths.gen.go
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
// Code generated by go-enum DO NOT EDIT.
|
||||||
|
// Version: -
|
||||||
|
// Revision: -
|
||||||
|
// Build Date: -
|
||||||
|
// Built By: -
|
||||||
|
|
||||||
|
package fields
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AuthChannelWeChat is a AuthChannel of type WeChat.
|
||||||
|
AuthChannelWeChat AuthChannel = iota + 1
|
||||||
|
// AuthChannelWeiBo is a AuthChannel of type WeiBo.
|
||||||
|
AuthChannelWeiBo
|
||||||
|
// AuthChannelQQ is a AuthChannel of type QQ.
|
||||||
|
AuthChannelQQ
|
||||||
|
// AuthChannelGithub is a AuthChannel of type Github.
|
||||||
|
AuthChannelGithub
|
||||||
|
// AuthChannelGoogle is a AuthChannel of type Google.
|
||||||
|
AuthChannelGoogle
|
||||||
|
// AuthChannelFacebook is a AuthChannel of type Facebook.
|
||||||
|
AuthChannelFacebook
|
||||||
|
// AuthChannelTwitter is a AuthChannel of type Twitter.
|
||||||
|
AuthChannelTwitter
|
||||||
|
// AuthChannelLinkedIn is a AuthChannel of type LinkedIn.
|
||||||
|
AuthChannelLinkedIn
|
||||||
|
// AuthChannelApple is a AuthChannel of type Apple.
|
||||||
|
AuthChannelApple
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrInvalidAuthChannel = fmt.Errorf("not a valid AuthChannel, try [%s]", strings.Join(_AuthChannelNames, ", "))
|
||||||
|
|
||||||
|
const _AuthChannelName = "WeChatWeiBoQQGithubGoogleFacebookTwitterLinkedInApple"
|
||||||
|
|
||||||
|
var _AuthChannelNames = []string{
|
||||||
|
_AuthChannelName[0:6],
|
||||||
|
_AuthChannelName[6:11],
|
||||||
|
_AuthChannelName[11:13],
|
||||||
|
_AuthChannelName[13:19],
|
||||||
|
_AuthChannelName[19:25],
|
||||||
|
_AuthChannelName[25:33],
|
||||||
|
_AuthChannelName[33:40],
|
||||||
|
_AuthChannelName[40:48],
|
||||||
|
_AuthChannelName[48:53],
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthChannelNames returns a list of possible string values of AuthChannel.
|
||||||
|
func AuthChannelNames() []string {
|
||||||
|
tmp := make([]string, len(_AuthChannelNames))
|
||||||
|
copy(tmp, _AuthChannelNames)
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthChannelValues returns a list of the values for AuthChannel
|
||||||
|
func AuthChannelValues() []AuthChannel {
|
||||||
|
return []AuthChannel{
|
||||||
|
AuthChannelWeChat,
|
||||||
|
AuthChannelWeiBo,
|
||||||
|
AuthChannelQQ,
|
||||||
|
AuthChannelGithub,
|
||||||
|
AuthChannelGoogle,
|
||||||
|
AuthChannelFacebook,
|
||||||
|
AuthChannelTwitter,
|
||||||
|
AuthChannelLinkedIn,
|
||||||
|
AuthChannelApple,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _AuthChannelMap = map[AuthChannel]string{
|
||||||
|
AuthChannelWeChat: _AuthChannelName[0:6],
|
||||||
|
AuthChannelWeiBo: _AuthChannelName[6:11],
|
||||||
|
AuthChannelQQ: _AuthChannelName[11:13],
|
||||||
|
AuthChannelGithub: _AuthChannelName[13:19],
|
||||||
|
AuthChannelGoogle: _AuthChannelName[19:25],
|
||||||
|
AuthChannelFacebook: _AuthChannelName[25:33],
|
||||||
|
AuthChannelTwitter: _AuthChannelName[33:40],
|
||||||
|
AuthChannelLinkedIn: _AuthChannelName[40:48],
|
||||||
|
AuthChannelApple: _AuthChannelName[48:53],
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the Stringer interface.
|
||||||
|
func (x AuthChannel) String() string {
|
||||||
|
if str, ok := _AuthChannelMap[x]; ok {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("AuthChannel(%d)", x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid provides a quick way to determine if the typed value is
|
||||||
|
// part of the allowed enumerated values
|
||||||
|
func (x AuthChannel) IsValid() bool {
|
||||||
|
_, ok := _AuthChannelMap[x]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
var _AuthChannelValue = map[string]AuthChannel{
|
||||||
|
_AuthChannelName[0:6]: AuthChannelWeChat,
|
||||||
|
_AuthChannelName[6:11]: AuthChannelWeiBo,
|
||||||
|
_AuthChannelName[11:13]: AuthChannelQQ,
|
||||||
|
_AuthChannelName[13:19]: AuthChannelGithub,
|
||||||
|
_AuthChannelName[19:25]: AuthChannelGoogle,
|
||||||
|
_AuthChannelName[25:33]: AuthChannelFacebook,
|
||||||
|
_AuthChannelName[33:40]: AuthChannelTwitter,
|
||||||
|
_AuthChannelName[40:48]: AuthChannelLinkedIn,
|
||||||
|
_AuthChannelName[48:53]: AuthChannelApple,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseAuthChannel attempts to convert a string to a AuthChannel.
|
||||||
|
func ParseAuthChannel(name string) (AuthChannel, error) {
|
||||||
|
if x, ok := _AuthChannelValue[name]; ok {
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
return AuthChannel(0), fmt.Errorf("%s is %w", name, ErrInvalidAuthChannel)
|
||||||
|
}
|
||||||
|
|
||||||
|
var errAuthChannelNilPtr = errors.New("value pointer is nil") // one per type for package clashes
|
||||||
|
|
||||||
|
// Scan implements the Scanner interface.
|
||||||
|
func (x *AuthChannel) Scan(value interface{}) (err error) {
|
||||||
|
if value == nil {
|
||||||
|
*x = AuthChannel(0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// A wider range of scannable types.
|
||||||
|
// driver.Value values at the top of the list for expediency
|
||||||
|
switch v := value.(type) {
|
||||||
|
case int64:
|
||||||
|
*x = AuthChannel(v)
|
||||||
|
case string:
|
||||||
|
*x, err = ParseAuthChannel(v)
|
||||||
|
if err != nil {
|
||||||
|
// try parsing the integer value as a string
|
||||||
|
if val, verr := strconv.Atoi(v); verr == nil {
|
||||||
|
*x, err = AuthChannel(val), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case []byte:
|
||||||
|
*x, err = ParseAuthChannel(string(v))
|
||||||
|
if err != nil {
|
||||||
|
// try parsing the integer value as a string
|
||||||
|
if val, verr := strconv.Atoi(string(v)); verr == nil {
|
||||||
|
*x, err = AuthChannel(val), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case AuthChannel:
|
||||||
|
*x = v
|
||||||
|
case int:
|
||||||
|
*x = AuthChannel(v)
|
||||||
|
case *AuthChannel:
|
||||||
|
if v == nil {
|
||||||
|
return errAuthChannelNilPtr
|
||||||
|
}
|
||||||
|
*x = *v
|
||||||
|
case uint:
|
||||||
|
*x = AuthChannel(v)
|
||||||
|
case uint64:
|
||||||
|
*x = AuthChannel(v)
|
||||||
|
case *int:
|
||||||
|
if v == nil {
|
||||||
|
return errAuthChannelNilPtr
|
||||||
|
}
|
||||||
|
*x = AuthChannel(*v)
|
||||||
|
case *int64:
|
||||||
|
if v == nil {
|
||||||
|
return errAuthChannelNilPtr
|
||||||
|
}
|
||||||
|
*x = AuthChannel(*v)
|
||||||
|
case float64: // json marshals everything as a float64 if it's a number
|
||||||
|
*x = AuthChannel(v)
|
||||||
|
case *float64: // json marshals everything as a float64 if it's a number
|
||||||
|
if v == nil {
|
||||||
|
return errAuthChannelNilPtr
|
||||||
|
}
|
||||||
|
*x = AuthChannel(*v)
|
||||||
|
case *uint:
|
||||||
|
if v == nil {
|
||||||
|
return errAuthChannelNilPtr
|
||||||
|
}
|
||||||
|
*x = AuthChannel(*v)
|
||||||
|
case *uint64:
|
||||||
|
if v == nil {
|
||||||
|
return errAuthChannelNilPtr
|
||||||
|
}
|
||||||
|
*x = AuthChannel(*v)
|
||||||
|
case *string:
|
||||||
|
if v == nil {
|
||||||
|
return errAuthChannelNilPtr
|
||||||
|
}
|
||||||
|
*x, err = ParseAuthChannel(*v)
|
||||||
|
if err != nil {
|
||||||
|
// try parsing the integer value as a string
|
||||||
|
if val, verr := strconv.Atoi(*v); verr == nil {
|
||||||
|
*x, err = AuthChannel(val), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver Valuer interface.
|
||||||
|
func (x AuthChannel) Value() (driver.Value, error) {
|
||||||
|
return int64(x), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set implements the Golang flag.Value interface func.
|
||||||
|
func (x *AuthChannel) Set(val string) error {
|
||||||
|
v, err := ParseAuthChannel(val)
|
||||||
|
*x = v
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get implements the Golang flag.Getter interface func.
|
||||||
|
func (x *AuthChannel) Get() interface{} {
|
||||||
|
return *x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type implements the github.com/spf13/pFlag Value interface.
|
||||||
|
func (x *AuthChannel) Type() string {
|
||||||
|
return "AuthChannel"
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullAuthChannel struct {
|
||||||
|
AuthChannel AuthChannel
|
||||||
|
Valid bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullAuthChannel(val interface{}) (x NullAuthChannel) {
|
||||||
|
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the Scanner interface.
|
||||||
|
func (x *NullAuthChannel) Scan(value interface{}) (err error) {
|
||||||
|
if value == nil {
|
||||||
|
x.AuthChannel, x.Valid = AuthChannel(0), false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = x.AuthChannel.Scan(value)
|
||||||
|
x.Valid = (err == nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver Valuer interface.
|
||||||
|
func (x NullAuthChannel) Value() (driver.Value, error) {
|
||||||
|
if !x.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
// driver.Value accepts int64 for int values.
|
||||||
|
return int64(x.AuthChannel), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullAuthChannelStr struct {
|
||||||
|
NullAuthChannel
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullAuthChannelStr(val interface{}) (x NullAuthChannelStr) {
|
||||||
|
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver Valuer interface.
|
||||||
|
func (x NullAuthChannelStr) Value() (driver.Value, error) {
|
||||||
|
if !x.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return x.AuthChannel.String(), nil
|
||||||
|
}
|
||||||
5
backend/database/fields/user_oauths.go
Normal file
5
backend/database/fields/user_oauths.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package fields
|
||||||
|
|
||||||
|
// swagger:enum AuthChannel
|
||||||
|
// ENUM( WeChat = 1 , WeiBo, QQ, Github, Google, Facebook, Twitter, LinkedIn, Apple)
|
||||||
|
type AuthChannel int16
|
||||||
241
backend/database/fields/users.gen.go
Normal file
241
backend/database/fields/users.gen.go
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
// Code generated by go-enum DO NOT EDIT.
|
||||||
|
// Version: -
|
||||||
|
// Revision: -
|
||||||
|
// Build Date: -
|
||||||
|
// Built By: -
|
||||||
|
|
||||||
|
package fields
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UserStatusPending is a UserStatus of type Pending.
|
||||||
|
UserStatusPending UserStatus = iota
|
||||||
|
// UserStatusVerified is a UserStatus of type Verified.
|
||||||
|
UserStatusVerified
|
||||||
|
// UserStatusBlocked is a UserStatus of type Blocked.
|
||||||
|
UserStatusBlocked
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrInvalidUserStatus = fmt.Errorf("not a valid UserStatus, try [%s]", strings.Join(_UserStatusNames, ", "))
|
||||||
|
|
||||||
|
const _UserStatusName = "PendingVerifiedBlocked"
|
||||||
|
|
||||||
|
var _UserStatusNames = []string{
|
||||||
|
_UserStatusName[0:7],
|
||||||
|
_UserStatusName[7:15],
|
||||||
|
_UserStatusName[15:22],
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserStatusNames returns a list of possible string values of UserStatus.
|
||||||
|
func UserStatusNames() []string {
|
||||||
|
tmp := make([]string, len(_UserStatusNames))
|
||||||
|
copy(tmp, _UserStatusNames)
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserStatusValues returns a list of the values for UserStatus
|
||||||
|
func UserStatusValues() []UserStatus {
|
||||||
|
return []UserStatus{
|
||||||
|
UserStatusPending,
|
||||||
|
UserStatusVerified,
|
||||||
|
UserStatusBlocked,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _UserStatusMap = map[UserStatus]string{
|
||||||
|
UserStatusPending: _UserStatusName[0:7],
|
||||||
|
UserStatusVerified: _UserStatusName[7:15],
|
||||||
|
UserStatusBlocked: _UserStatusName[15:22],
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the Stringer interface.
|
||||||
|
func (x UserStatus) String() string {
|
||||||
|
if str, ok := _UserStatusMap[x]; ok {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("UserStatus(%d)", x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid provides a quick way to determine if the typed value is
|
||||||
|
// part of the allowed enumerated values
|
||||||
|
func (x UserStatus) IsValid() bool {
|
||||||
|
_, ok := _UserStatusMap[x]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
var _UserStatusValue = map[string]UserStatus{
|
||||||
|
_UserStatusName[0:7]: UserStatusPending,
|
||||||
|
_UserStatusName[7:15]: UserStatusVerified,
|
||||||
|
_UserStatusName[15:22]: UserStatusBlocked,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseUserStatus attempts to convert a string to a UserStatus.
|
||||||
|
func ParseUserStatus(name string) (UserStatus, error) {
|
||||||
|
if x, ok := _UserStatusValue[name]; ok {
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
return UserStatus(0), fmt.Errorf("%s is %w", name, ErrInvalidUserStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
var errUserStatusNilPtr = errors.New("value pointer is nil") // one per type for package clashes
|
||||||
|
|
||||||
|
// Scan implements the Scanner interface.
|
||||||
|
func (x *UserStatus) Scan(value interface{}) (err error) {
|
||||||
|
if value == nil {
|
||||||
|
*x = UserStatus(0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// A wider range of scannable types.
|
||||||
|
// driver.Value values at the top of the list for expediency
|
||||||
|
switch v := value.(type) {
|
||||||
|
case int64:
|
||||||
|
*x = UserStatus(v)
|
||||||
|
case string:
|
||||||
|
*x, err = ParseUserStatus(v)
|
||||||
|
if err != nil {
|
||||||
|
// try parsing the integer value as a string
|
||||||
|
if val, verr := strconv.Atoi(v); verr == nil {
|
||||||
|
*x, err = UserStatus(val), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case []byte:
|
||||||
|
*x, err = ParseUserStatus(string(v))
|
||||||
|
if err != nil {
|
||||||
|
// try parsing the integer value as a string
|
||||||
|
if val, verr := strconv.Atoi(string(v)); verr == nil {
|
||||||
|
*x, err = UserStatus(val), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case UserStatus:
|
||||||
|
*x = v
|
||||||
|
case int:
|
||||||
|
*x = UserStatus(v)
|
||||||
|
case *UserStatus:
|
||||||
|
if v == nil {
|
||||||
|
return errUserStatusNilPtr
|
||||||
|
}
|
||||||
|
*x = *v
|
||||||
|
case uint:
|
||||||
|
*x = UserStatus(v)
|
||||||
|
case uint64:
|
||||||
|
*x = UserStatus(v)
|
||||||
|
case *int:
|
||||||
|
if v == nil {
|
||||||
|
return errUserStatusNilPtr
|
||||||
|
}
|
||||||
|
*x = UserStatus(*v)
|
||||||
|
case *int64:
|
||||||
|
if v == nil {
|
||||||
|
return errUserStatusNilPtr
|
||||||
|
}
|
||||||
|
*x = UserStatus(*v)
|
||||||
|
case float64: // json marshals everything as a float64 if it's a number
|
||||||
|
*x = UserStatus(v)
|
||||||
|
case *float64: // json marshals everything as a float64 if it's a number
|
||||||
|
if v == nil {
|
||||||
|
return errUserStatusNilPtr
|
||||||
|
}
|
||||||
|
*x = UserStatus(*v)
|
||||||
|
case *uint:
|
||||||
|
if v == nil {
|
||||||
|
return errUserStatusNilPtr
|
||||||
|
}
|
||||||
|
*x = UserStatus(*v)
|
||||||
|
case *uint64:
|
||||||
|
if v == nil {
|
||||||
|
return errUserStatusNilPtr
|
||||||
|
}
|
||||||
|
*x = UserStatus(*v)
|
||||||
|
case *string:
|
||||||
|
if v == nil {
|
||||||
|
return errUserStatusNilPtr
|
||||||
|
}
|
||||||
|
*x, err = ParseUserStatus(*v)
|
||||||
|
if err != nil {
|
||||||
|
// try parsing the integer value as a string
|
||||||
|
if val, verr := strconv.Atoi(*v); verr == nil {
|
||||||
|
*x, err = UserStatus(val), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver Valuer interface.
|
||||||
|
func (x UserStatus) Value() (driver.Value, error) {
|
||||||
|
return int64(x), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set implements the Golang flag.Value interface func.
|
||||||
|
func (x *UserStatus) Set(val string) error {
|
||||||
|
v, err := ParseUserStatus(val)
|
||||||
|
*x = v
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get implements the Golang flag.Getter interface func.
|
||||||
|
func (x *UserStatus) Get() interface{} {
|
||||||
|
return *x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type implements the github.com/spf13/pFlag Value interface.
|
||||||
|
func (x *UserStatus) Type() string {
|
||||||
|
return "UserStatus"
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullUserStatus struct {
|
||||||
|
UserStatus UserStatus
|
||||||
|
Valid bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullUserStatus(val interface{}) (x NullUserStatus) {
|
||||||
|
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the Scanner interface.
|
||||||
|
func (x *NullUserStatus) Scan(value interface{}) (err error) {
|
||||||
|
if value == nil {
|
||||||
|
x.UserStatus, x.Valid = UserStatus(0), false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = x.UserStatus.Scan(value)
|
||||||
|
x.Valid = (err == nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver Valuer interface.
|
||||||
|
func (x NullUserStatus) Value() (driver.Value, error) {
|
||||||
|
if !x.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
// driver.Value accepts int64 for int values.
|
||||||
|
return int64(x.UserStatus), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullUserStatusStr struct {
|
||||||
|
NullUserStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNullUserStatusStr(val interface{}) (x NullUserStatusStr) {
|
||||||
|
x.Scan(val) // yes, we ignore this error, it will just be an invalid value.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver Valuer interface.
|
||||||
|
func (x NullUserStatusStr) Value() (driver.Value, error) {
|
||||||
|
if !x.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return x.UserStatus.String(), nil
|
||||||
|
}
|
||||||
5
backend/database/fields/users.go
Normal file
5
backend/database/fields/users.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package fields
|
||||||
|
|
||||||
|
// swagger:enum UserStatus
|
||||||
|
// ENUM( Pending, Verified, Blocked)
|
||||||
|
type UserStatus int16
|
||||||
@@ -33,7 +33,6 @@ CREATE TABLE
|
|||||||
user_id INT8 NOT NULL,
|
user_id INT8 NOT NULL,
|
||||||
union_id VARCHAR(128),
|
union_id VARCHAR(128),
|
||||||
open_id VARCHAR(128) NOT NULL UNIQUE,
|
open_id VARCHAR(128) NOT NULL UNIQUE,
|
||||||
access_key VARCHAR(256) NOT NULL default '',
|
|
||||||
access_token VARCHAR(256) NOT NULL default '',
|
access_token VARCHAR(256) NOT NULL default '',
|
||||||
refresh_token VARCHAR(256) NOT NULL default '',
|
refresh_token VARCHAR(256) NOT NULL default '',
|
||||||
expire_at timestamp NOT NULL,
|
expire_at timestamp NOT NULL,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"backend/database/fields"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ type UserOauths struct {
|
|||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
DeletedAt *time.Time `json:"deleted_at"`
|
DeletedAt *time.Time `json:"deleted_at"`
|
||||||
Channel int16 `json:"channel"`
|
Channel fields.AuthChannel `json:"channel"`
|
||||||
UserID int64 `json:"user_id"`
|
UserID int64 `json:"user_id"`
|
||||||
UnionID *string `json:"union_id"`
|
UnionID *string `json:"union_id"`
|
||||||
OpenID string `json:"open_id"`
|
OpenID string `json:"open_id"`
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ ignores:
|
|||||||
- river_job
|
- river_job
|
||||||
- river_leader
|
- river_leader
|
||||||
- river_queue
|
- river_queue
|
||||||
# types:
|
types:
|
||||||
# users: # table name
|
users: # table name
|
||||||
# meta: UserMeta
|
status: UserStatus
|
||||||
# meta: Json[UserMeta]
|
|
||||||
|
user_oauths:
|
||||||
|
channel: AuthChannel
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// Format
|
|
||||||
//
|
|
||||||
// // swagger:enum CacheKey
|
|
||||||
// // ENUM(
|
|
||||||
// // VerifyCode = "code:__CHANNEL__:%s",
|
|
||||||
// // )
|
|
||||||
11
backend/pkg/oauth/contracts.go
Normal file
11
backend/pkg/oauth/contracts.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package oauth
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type OAuthInfo interface {
|
||||||
|
GetOpenID() string
|
||||||
|
GetUnionID() string
|
||||||
|
GetAccessToken() string
|
||||||
|
GetRefreshToken() string
|
||||||
|
GetExpiredAt() time.Time
|
||||||
|
}
|
||||||
39
backend/pkg/oauth/wechat.go
Normal file
39
backend/pkg/oauth/wechat.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package oauth
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
var _ OAuthInfo = (*WechatOAuthInfo)(nil)
|
||||||
|
|
||||||
|
type WechatOAuthInfo struct {
|
||||||
|
Scope string `json:"scope,omitempty"`
|
||||||
|
OpenID string `json:"openid,omitempty"`
|
||||||
|
UnionID string `json:"unionid,omitempty"`
|
||||||
|
AccessToken string `json:"access_token,omitempty"`
|
||||||
|
RefreshToken string `json:"refresh_token,omitempty"`
|
||||||
|
ExpiresIn int64 `json:"expires_in,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccessToken implements OAuthInfo.
|
||||||
|
func (w *WechatOAuthInfo) GetAccessToken() string {
|
||||||
|
return w.AccessToken
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExpiredAt implements OAuthInfo.
|
||||||
|
func (w *WechatOAuthInfo) GetExpiredAt() time.Time {
|
||||||
|
return time.Now().Add(time.Duration(w.ExpiresIn) * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOpenID implements OAuthInfo.
|
||||||
|
func (w *WechatOAuthInfo) GetOpenID() string {
|
||||||
|
return w.OpenID
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRefreshToken implements OAuthInfo.
|
||||||
|
func (w *WechatOAuthInfo) GetRefreshToken() string {
|
||||||
|
return w.RefreshToken
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUnionID implements OAuthInfo.
|
||||||
|
func (w *WechatOAuthInfo) GetUnionID() string {
|
||||||
|
return w.UnionID
|
||||||
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package events
|
package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.ipao.vip/rogeecn/atom/container"
|
"git.ipao.vip/rogeecn/atom/container"
|
||||||
|
"git.ipao.vip/rogeecn/atom/contracts"
|
||||||
"git.ipao.vip/rogeecn/atom/utils/opt"
|
"git.ipao.vip/rogeecn/atom/utils/opt"
|
||||||
|
"github.com/ThreeDotsLabs/watermill"
|
||||||
"github.com/ThreeDotsLabs/watermill/message"
|
"github.com/ThreeDotsLabs/watermill/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -46,3 +48,18 @@ func (ps *PubSub) Handle(
|
|||||||
) {
|
) {
|
||||||
ps.Router.AddHandler(handlerName, consumerTopic, ps.Subscriber, publisherTopic, ps.Publisher, handler)
|
ps.Router.AddHandler(handlerName, consumerTopic, ps.Subscriber, publisherTopic, ps.Publisher, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// publish
|
||||||
|
func (ps *PubSub) Publish(e contracts.EventPublisher) error {
|
||||||
|
if e == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, err := e.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := message.NewMessage(watermill.NewUUID(), payload)
|
||||||
|
return ps.Publisher.Publish(e.Topic(), msg)
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package events
|
package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ThreeDotsLabs/watermill"
|
"github.com/ThreeDotsLabs/watermill"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package events
|
package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.ipao.vip/rogeecn/atom/container"
|
"git.ipao.vip/rogeecn/atom/container"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package events
|
package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.ipao.vip/rogeecn/atom/container"
|
"git.ipao.vip/rogeecn/atom/container"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package events
|
package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.ipao.vip/rogeecn/atom/container"
|
"git.ipao.vip/rogeecn/atom/container"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package events
|
package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
sqlDB "database/sql"
|
sqlDB "database/sql"
|
||||||
@@ -51,4 +51,11 @@ func (c *Config) format() {
|
|||||||
c.Env = "unknown"
|
c.Env = "unknown"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.EndpointGRPC == "" {
|
||||||
|
c.EndpointGRPC = os.Getenv("OTEL_ENDPOINT_GRPC")
|
||||||
|
if c.EndpointGRPC == "" {
|
||||||
|
c.EndpointGRPC = "localhost:4317"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
|
func Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
|
||||||
return tracer.Start(ctx, spanName, opts...)
|
return tracer.Start(ctx, spanName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Int64Counter(name string, options ...metric.Int64CounterOption) (metric.Int64Counter, error) {
|
func Int64Counter(name string, options ...metric.Int64CounterOption) (metric.Int64Counter, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user