feat(oauth): 支持标准OAuth2.0接入

This commit is contained in:
yokowu
2025-07-09 18:13:15 +08:00
parent 230aceb5ba
commit 320aeb2985
23 changed files with 821 additions and 726 deletions

View File

@@ -21,12 +21,14 @@ type UserPlatform string
const (
UserPlatformEmail UserPlatform = "email"
UserPlatformDingTalk UserPlatform = "dingtalk"
UserPlatformCustom UserPlatform = "custom"
)
type OAuthKind string
const (
OAuthKindSignUpOrIn OAuthKind = "signup_or_in"
OAuthKindInvite OAuthKind = "invite"
OAuthKindLogin OAuthKind = "login"
)
type InviteCodeStatus string

View File

@@ -243,9 +243,8 @@ var (
{Name: "enable_sso", Type: field.TypeBool, Default: false},
{Name: "force_two_factor_auth", Type: field.TypeBool, Default: false},
{Name: "disable_password_login", Type: field.TypeBool, Default: false},
{Name: "enable_dingtalk_oauth", Type: field.TypeBool, Default: false},
{Name: "dingtalk_client_id", Type: field.TypeString, Nullable: true},
{Name: "dingtalk_client_secret", Type: field.TypeString, Nullable: true},
{Name: "dingtalk_oauth", Type: field.TypeJSON, Nullable: true},
{Name: "custom_oauth", Type: field.TypeJSON, Nullable: true},
{Name: "created_at", Type: field.TypeTime},
{Name: "updated_at", Type: field.TypeTime},
}

View File

@@ -31,6 +31,7 @@ import (
"github.com/chaitin/MonkeyCode/backend/db/user"
"github.com/chaitin/MonkeyCode/backend/db/useridentity"
"github.com/chaitin/MonkeyCode/backend/db/userloginhistory"
"github.com/chaitin/MonkeyCode/backend/ent/types"
"github.com/google/uuid"
)
@@ -8816,9 +8817,8 @@ type SettingMutation struct {
enable_sso *bool
force_two_factor_auth *bool
disable_password_login *bool
enable_dingtalk_oauth *bool
dingtalk_client_id *string
dingtalk_client_secret *string
dingtalk_oauth **types.DingtalkOAuth
custom_oauth **types.CustomOAuth
created_at *time.Time
updated_at *time.Time
clearedFields map[string]struct{}
@@ -9039,138 +9039,102 @@ func (m *SettingMutation) ResetDisablePasswordLogin() {
m.disable_password_login = nil
}
// SetEnableDingtalkOauth sets the "enable_dingtalk_oauth" field.
func (m *SettingMutation) SetEnableDingtalkOauth(b bool) {
m.enable_dingtalk_oauth = &b
// SetDingtalkOauth sets the "dingtalk_oauth" field.
func (m *SettingMutation) SetDingtalkOauth(to *types.DingtalkOAuth) {
m.dingtalk_oauth = &to
}
// EnableDingtalkOauth returns the value of the "enable_dingtalk_oauth" field in the mutation.
func (m *SettingMutation) EnableDingtalkOauth() (r bool, exists bool) {
v := m.enable_dingtalk_oauth
// DingtalkOauth returns the value of the "dingtalk_oauth" field in the mutation.
func (m *SettingMutation) DingtalkOauth() (r *types.DingtalkOAuth, exists bool) {
v := m.dingtalk_oauth
if v == nil {
return
}
return *v, true
}
// OldEnableDingtalkOauth returns the old "enable_dingtalk_oauth" field's value of the Setting entity.
// OldDingtalkOauth returns the old "dingtalk_oauth" field's value of the Setting entity.
// If the Setting object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *SettingMutation) OldEnableDingtalkOauth(ctx context.Context) (v bool, err error) {
func (m *SettingMutation) OldDingtalkOauth(ctx context.Context) (v *types.DingtalkOAuth, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldEnableDingtalkOauth is only allowed on UpdateOne operations")
return v, errors.New("OldDingtalkOauth is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldEnableDingtalkOauth requires an ID field in the mutation")
return v, errors.New("OldDingtalkOauth requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldEnableDingtalkOauth: %w", err)
return v, fmt.Errorf("querying old value for OldDingtalkOauth: %w", err)
}
return oldValue.EnableDingtalkOauth, nil
return oldValue.DingtalkOauth, nil
}
// ResetEnableDingtalkOauth resets all changes to the "enable_dingtalk_oauth" field.
func (m *SettingMutation) ResetEnableDingtalkOauth() {
m.enable_dingtalk_oauth = nil
// ClearDingtalkOauth clears the value of the "dingtalk_oauth" field.
func (m *SettingMutation) ClearDingtalkOauth() {
m.dingtalk_oauth = nil
m.clearedFields[setting.FieldDingtalkOauth] = struct{}{}
}
// SetDingtalkClientID sets the "dingtalk_client_id" field.
func (m *SettingMutation) SetDingtalkClientID(s string) {
m.dingtalk_client_id = &s
}
// DingtalkClientID returns the value of the "dingtalk_client_id" field in the mutation.
func (m *SettingMutation) DingtalkClientID() (r string, exists bool) {
v := m.dingtalk_client_id
if v == nil {
return
}
return *v, true
}
// OldDingtalkClientID returns the old "dingtalk_client_id" field's value of the Setting entity.
// If the Setting object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *SettingMutation) OldDingtalkClientID(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldDingtalkClientID is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldDingtalkClientID requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldDingtalkClientID: %w", err)
}
return oldValue.DingtalkClientID, nil
}
// ClearDingtalkClientID clears the value of the "dingtalk_client_id" field.
func (m *SettingMutation) ClearDingtalkClientID() {
m.dingtalk_client_id = nil
m.clearedFields[setting.FieldDingtalkClientID] = struct{}{}
}
// DingtalkClientIDCleared returns if the "dingtalk_client_id" field was cleared in this mutation.
func (m *SettingMutation) DingtalkClientIDCleared() bool {
_, ok := m.clearedFields[setting.FieldDingtalkClientID]
// DingtalkOauthCleared returns if the "dingtalk_oauth" field was cleared in this mutation.
func (m *SettingMutation) DingtalkOauthCleared() bool {
_, ok := m.clearedFields[setting.FieldDingtalkOauth]
return ok
}
// ResetDingtalkClientID resets all changes to the "dingtalk_client_id" field.
func (m *SettingMutation) ResetDingtalkClientID() {
m.dingtalk_client_id = nil
delete(m.clearedFields, setting.FieldDingtalkClientID)
// ResetDingtalkOauth resets all changes to the "dingtalk_oauth" field.
func (m *SettingMutation) ResetDingtalkOauth() {
m.dingtalk_oauth = nil
delete(m.clearedFields, setting.FieldDingtalkOauth)
}
// SetDingtalkClientSecret sets the "dingtalk_client_secret" field.
func (m *SettingMutation) SetDingtalkClientSecret(s string) {
m.dingtalk_client_secret = &s
// SetCustomOauth sets the "custom_oauth" field.
func (m *SettingMutation) SetCustomOauth(to *types.CustomOAuth) {
m.custom_oauth = &to
}
// DingtalkClientSecret returns the value of the "dingtalk_client_secret" field in the mutation.
func (m *SettingMutation) DingtalkClientSecret() (r string, exists bool) {
v := m.dingtalk_client_secret
// CustomOauth returns the value of the "custom_oauth" field in the mutation.
func (m *SettingMutation) CustomOauth() (r *types.CustomOAuth, exists bool) {
v := m.custom_oauth
if v == nil {
return
}
return *v, true
}
// OldDingtalkClientSecret returns the old "dingtalk_client_secret" field's value of the Setting entity.
// OldCustomOauth returns the old "custom_oauth" field's value of the Setting entity.
// If the Setting object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *SettingMutation) OldDingtalkClientSecret(ctx context.Context) (v string, err error) {
func (m *SettingMutation) OldCustomOauth(ctx context.Context) (v *types.CustomOAuth, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldDingtalkClientSecret is only allowed on UpdateOne operations")
return v, errors.New("OldCustomOauth is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldDingtalkClientSecret requires an ID field in the mutation")
return v, errors.New("OldCustomOauth requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldDingtalkClientSecret: %w", err)
return v, fmt.Errorf("querying old value for OldCustomOauth: %w", err)
}
return oldValue.DingtalkClientSecret, nil
return oldValue.CustomOauth, nil
}
// ClearDingtalkClientSecret clears the value of the "dingtalk_client_secret" field.
func (m *SettingMutation) ClearDingtalkClientSecret() {
m.dingtalk_client_secret = nil
m.clearedFields[setting.FieldDingtalkClientSecret] = struct{}{}
// ClearCustomOauth clears the value of the "custom_oauth" field.
func (m *SettingMutation) ClearCustomOauth() {
m.custom_oauth = nil
m.clearedFields[setting.FieldCustomOauth] = struct{}{}
}
// DingtalkClientSecretCleared returns if the "dingtalk_client_secret" field was cleared in this mutation.
func (m *SettingMutation) DingtalkClientSecretCleared() bool {
_, ok := m.clearedFields[setting.FieldDingtalkClientSecret]
// CustomOauthCleared returns if the "custom_oauth" field was cleared in this mutation.
func (m *SettingMutation) CustomOauthCleared() bool {
_, ok := m.clearedFields[setting.FieldCustomOauth]
return ok
}
// ResetDingtalkClientSecret resets all changes to the "dingtalk_client_secret" field.
func (m *SettingMutation) ResetDingtalkClientSecret() {
m.dingtalk_client_secret = nil
delete(m.clearedFields, setting.FieldDingtalkClientSecret)
// ResetCustomOauth resets all changes to the "custom_oauth" field.
func (m *SettingMutation) ResetCustomOauth() {
m.custom_oauth = nil
delete(m.clearedFields, setting.FieldCustomOauth)
}
// SetCreatedAt sets the "created_at" field.
@@ -9279,7 +9243,7 @@ func (m *SettingMutation) Type() string {
// order to get all numeric fields that were incremented/decremented, call
// AddedFields().
func (m *SettingMutation) Fields() []string {
fields := make([]string, 0, 8)
fields := make([]string, 0, 7)
if m.enable_sso != nil {
fields = append(fields, setting.FieldEnableSSO)
}
@@ -9289,14 +9253,11 @@ func (m *SettingMutation) Fields() []string {
if m.disable_password_login != nil {
fields = append(fields, setting.FieldDisablePasswordLogin)
}
if m.enable_dingtalk_oauth != nil {
fields = append(fields, setting.FieldEnableDingtalkOauth)
if m.dingtalk_oauth != nil {
fields = append(fields, setting.FieldDingtalkOauth)
}
if m.dingtalk_client_id != nil {
fields = append(fields, setting.FieldDingtalkClientID)
}
if m.dingtalk_client_secret != nil {
fields = append(fields, setting.FieldDingtalkClientSecret)
if m.custom_oauth != nil {
fields = append(fields, setting.FieldCustomOauth)
}
if m.created_at != nil {
fields = append(fields, setting.FieldCreatedAt)
@@ -9318,12 +9279,10 @@ func (m *SettingMutation) Field(name string) (ent.Value, bool) {
return m.ForceTwoFactorAuth()
case setting.FieldDisablePasswordLogin:
return m.DisablePasswordLogin()
case setting.FieldEnableDingtalkOauth:
return m.EnableDingtalkOauth()
case setting.FieldDingtalkClientID:
return m.DingtalkClientID()
case setting.FieldDingtalkClientSecret:
return m.DingtalkClientSecret()
case setting.FieldDingtalkOauth:
return m.DingtalkOauth()
case setting.FieldCustomOauth:
return m.CustomOauth()
case setting.FieldCreatedAt:
return m.CreatedAt()
case setting.FieldUpdatedAt:
@@ -9343,12 +9302,10 @@ func (m *SettingMutation) OldField(ctx context.Context, name string) (ent.Value,
return m.OldForceTwoFactorAuth(ctx)
case setting.FieldDisablePasswordLogin:
return m.OldDisablePasswordLogin(ctx)
case setting.FieldEnableDingtalkOauth:
return m.OldEnableDingtalkOauth(ctx)
case setting.FieldDingtalkClientID:
return m.OldDingtalkClientID(ctx)
case setting.FieldDingtalkClientSecret:
return m.OldDingtalkClientSecret(ctx)
case setting.FieldDingtalkOauth:
return m.OldDingtalkOauth(ctx)
case setting.FieldCustomOauth:
return m.OldCustomOauth(ctx)
case setting.FieldCreatedAt:
return m.OldCreatedAt(ctx)
case setting.FieldUpdatedAt:
@@ -9383,26 +9340,19 @@ func (m *SettingMutation) SetField(name string, value ent.Value) error {
}
m.SetDisablePasswordLogin(v)
return nil
case setting.FieldEnableDingtalkOauth:
v, ok := value.(bool)
case setting.FieldDingtalkOauth:
v, ok := value.(*types.DingtalkOAuth)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetEnableDingtalkOauth(v)
m.SetDingtalkOauth(v)
return nil
case setting.FieldDingtalkClientID:
v, ok := value.(string)
case setting.FieldCustomOauth:
v, ok := value.(*types.CustomOAuth)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetDingtalkClientID(v)
return nil
case setting.FieldDingtalkClientSecret:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetDingtalkClientSecret(v)
m.SetCustomOauth(v)
return nil
case setting.FieldCreatedAt:
v, ok := value.(time.Time)
@@ -9448,11 +9398,11 @@ func (m *SettingMutation) AddField(name string, value ent.Value) error {
// mutation.
func (m *SettingMutation) ClearedFields() []string {
var fields []string
if m.FieldCleared(setting.FieldDingtalkClientID) {
fields = append(fields, setting.FieldDingtalkClientID)
if m.FieldCleared(setting.FieldDingtalkOauth) {
fields = append(fields, setting.FieldDingtalkOauth)
}
if m.FieldCleared(setting.FieldDingtalkClientSecret) {
fields = append(fields, setting.FieldDingtalkClientSecret)
if m.FieldCleared(setting.FieldCustomOauth) {
fields = append(fields, setting.FieldCustomOauth)
}
return fields
}
@@ -9468,11 +9418,11 @@ func (m *SettingMutation) FieldCleared(name string) bool {
// error if the field is not defined in the schema.
func (m *SettingMutation) ClearField(name string) error {
switch name {
case setting.FieldDingtalkClientID:
m.ClearDingtalkClientID()
case setting.FieldDingtalkOauth:
m.ClearDingtalkOauth()
return nil
case setting.FieldDingtalkClientSecret:
m.ClearDingtalkClientSecret()
case setting.FieldCustomOauth:
m.ClearCustomOauth()
return nil
}
return fmt.Errorf("unknown Setting nullable field %s", name)
@@ -9491,14 +9441,11 @@ func (m *SettingMutation) ResetField(name string) error {
case setting.FieldDisablePasswordLogin:
m.ResetDisablePasswordLogin()
return nil
case setting.FieldEnableDingtalkOauth:
m.ResetEnableDingtalkOauth()
case setting.FieldDingtalkOauth:
m.ResetDingtalkOauth()
return nil
case setting.FieldDingtalkClientID:
m.ResetDingtalkClientID()
return nil
case setting.FieldDingtalkClientSecret:
m.ResetDingtalkClientSecret()
case setting.FieldCustomOauth:
m.ResetCustomOauth()
return nil
case setting.FieldCreatedAt:
m.ResetCreatedAt()

View File

@@ -232,16 +232,12 @@ func init() {
settingDescDisablePasswordLogin := settingFields[3].Descriptor()
// setting.DefaultDisablePasswordLogin holds the default value on creation for the disable_password_login field.
setting.DefaultDisablePasswordLogin = settingDescDisablePasswordLogin.Default.(bool)
// settingDescEnableDingtalkOauth is the schema descriptor for enable_dingtalk_oauth field.
settingDescEnableDingtalkOauth := settingFields[4].Descriptor()
// setting.DefaultEnableDingtalkOauth holds the default value on creation for the enable_dingtalk_oauth field.
setting.DefaultEnableDingtalkOauth = settingDescEnableDingtalkOauth.Default.(bool)
// settingDescCreatedAt is the schema descriptor for created_at field.
settingDescCreatedAt := settingFields[7].Descriptor()
settingDescCreatedAt := settingFields[6].Descriptor()
// setting.DefaultCreatedAt holds the default value on creation for the created_at field.
setting.DefaultCreatedAt = settingDescCreatedAt.Default.(func() time.Time)
// settingDescUpdatedAt is the schema descriptor for updated_at field.
settingDescUpdatedAt := settingFields[8].Descriptor()
settingDescUpdatedAt := settingFields[7].Descriptor()
// setting.DefaultUpdatedAt holds the default value on creation for the updated_at field.
setting.DefaultUpdatedAt = settingDescUpdatedAt.Default.(func() time.Time)
// setting.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.

View File

@@ -3,6 +3,7 @@
package db
import (
"encoding/json"
"fmt"
"strings"
"time"
@@ -10,6 +11,7 @@ import (
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"github.com/chaitin/MonkeyCode/backend/db/setting"
"github.com/chaitin/MonkeyCode/backend/ent/types"
"github.com/google/uuid"
)
@@ -24,12 +26,10 @@ type Setting struct {
ForceTwoFactorAuth bool `json:"force_two_factor_auth,omitempty"`
// DisablePasswordLogin holds the value of the "disable_password_login" field.
DisablePasswordLogin bool `json:"disable_password_login,omitempty"`
// EnableDingtalkOauth holds the value of the "enable_dingtalk_oauth" field.
EnableDingtalkOauth bool `json:"enable_dingtalk_oauth,omitempty"`
// DingtalkClientID holds the value of the "dingtalk_client_id" field.
DingtalkClientID string `json:"dingtalk_client_id,omitempty"`
// DingtalkClientSecret holds the value of the "dingtalk_client_secret" field.
DingtalkClientSecret string `json:"dingtalk_client_secret,omitempty"`
// DingtalkOauth holds the value of the "dingtalk_oauth" field.
DingtalkOauth *types.DingtalkOAuth `json:"dingtalk_oauth,omitempty"`
// CustomOauth holds the value of the "custom_oauth" field.
CustomOauth *types.CustomOAuth `json:"custom_oauth,omitempty"`
// CreatedAt holds the value of the "created_at" field.
CreatedAt time.Time `json:"created_at,omitempty"`
// UpdatedAt holds the value of the "updated_at" field.
@@ -42,10 +42,10 @@ func (*Setting) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
for i := range columns {
switch columns[i] {
case setting.FieldEnableSSO, setting.FieldForceTwoFactorAuth, setting.FieldDisablePasswordLogin, setting.FieldEnableDingtalkOauth:
case setting.FieldDingtalkOauth, setting.FieldCustomOauth:
values[i] = new([]byte)
case setting.FieldEnableSSO, setting.FieldForceTwoFactorAuth, setting.FieldDisablePasswordLogin:
values[i] = new(sql.NullBool)
case setting.FieldDingtalkClientID, setting.FieldDingtalkClientSecret:
values[i] = new(sql.NullString)
case setting.FieldCreatedAt, setting.FieldUpdatedAt:
values[i] = new(sql.NullTime)
case setting.FieldID:
@@ -89,23 +89,21 @@ func (s *Setting) assignValues(columns []string, values []any) error {
} else if value.Valid {
s.DisablePasswordLogin = value.Bool
}
case setting.FieldEnableDingtalkOauth:
if value, ok := values[i].(*sql.NullBool); !ok {
return fmt.Errorf("unexpected type %T for field enable_dingtalk_oauth", values[i])
} else if value.Valid {
s.EnableDingtalkOauth = value.Bool
case setting.FieldDingtalkOauth:
if value, ok := values[i].(*[]byte); !ok {
return fmt.Errorf("unexpected type %T for field dingtalk_oauth", values[i])
} else if value != nil && len(*value) > 0 {
if err := json.Unmarshal(*value, &s.DingtalkOauth); err != nil {
return fmt.Errorf("unmarshal field dingtalk_oauth: %w", err)
}
}
case setting.FieldDingtalkClientID:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field dingtalk_client_id", values[i])
} else if value.Valid {
s.DingtalkClientID = value.String
}
case setting.FieldDingtalkClientSecret:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field dingtalk_client_secret", values[i])
} else if value.Valid {
s.DingtalkClientSecret = value.String
case setting.FieldCustomOauth:
if value, ok := values[i].(*[]byte); !ok {
return fmt.Errorf("unexpected type %T for field custom_oauth", values[i])
} else if value != nil && len(*value) > 0 {
if err := json.Unmarshal(*value, &s.CustomOauth); err != nil {
return fmt.Errorf("unmarshal field custom_oauth: %w", err)
}
}
case setting.FieldCreatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
@@ -164,14 +162,11 @@ func (s *Setting) String() string {
builder.WriteString("disable_password_login=")
builder.WriteString(fmt.Sprintf("%v", s.DisablePasswordLogin))
builder.WriteString(", ")
builder.WriteString("enable_dingtalk_oauth=")
builder.WriteString(fmt.Sprintf("%v", s.EnableDingtalkOauth))
builder.WriteString("dingtalk_oauth=")
builder.WriteString(fmt.Sprintf("%v", s.DingtalkOauth))
builder.WriteString(", ")
builder.WriteString("dingtalk_client_id=")
builder.WriteString(s.DingtalkClientID)
builder.WriteString(", ")
builder.WriteString("dingtalk_client_secret=")
builder.WriteString(s.DingtalkClientSecret)
builder.WriteString("custom_oauth=")
builder.WriteString(fmt.Sprintf("%v", s.CustomOauth))
builder.WriteString(", ")
builder.WriteString("created_at=")
builder.WriteString(s.CreatedAt.Format(time.ANSIC))

View File

@@ -19,12 +19,10 @@ const (
FieldForceTwoFactorAuth = "force_two_factor_auth"
// FieldDisablePasswordLogin holds the string denoting the disable_password_login field in the database.
FieldDisablePasswordLogin = "disable_password_login"
// FieldEnableDingtalkOauth holds the string denoting the enable_dingtalk_oauth field in the database.
FieldEnableDingtalkOauth = "enable_dingtalk_oauth"
// FieldDingtalkClientID holds the string denoting the dingtalk_client_id field in the database.
FieldDingtalkClientID = "dingtalk_client_id"
// FieldDingtalkClientSecret holds the string denoting the dingtalk_client_secret field in the database.
FieldDingtalkClientSecret = "dingtalk_client_secret"
// FieldDingtalkOauth holds the string denoting the dingtalk_oauth field in the database.
FieldDingtalkOauth = "dingtalk_oauth"
// FieldCustomOauth holds the string denoting the custom_oauth field in the database.
FieldCustomOauth = "custom_oauth"
// FieldCreatedAt holds the string denoting the created_at field in the database.
FieldCreatedAt = "created_at"
// FieldUpdatedAt holds the string denoting the updated_at field in the database.
@@ -39,9 +37,8 @@ var Columns = []string{
FieldEnableSSO,
FieldForceTwoFactorAuth,
FieldDisablePasswordLogin,
FieldEnableDingtalkOauth,
FieldDingtalkClientID,
FieldDingtalkClientSecret,
FieldDingtalkOauth,
FieldCustomOauth,
FieldCreatedAt,
FieldUpdatedAt,
}
@@ -63,8 +60,6 @@ var (
DefaultForceTwoFactorAuth bool
// DefaultDisablePasswordLogin holds the default value on creation for the "disable_password_login" field.
DefaultDisablePasswordLogin bool
// DefaultEnableDingtalkOauth holds the default value on creation for the "enable_dingtalk_oauth" field.
DefaultEnableDingtalkOauth bool
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
DefaultCreatedAt func() time.Time
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
@@ -96,21 +91,6 @@ func ByDisablePasswordLogin(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDisablePasswordLogin, opts...).ToFunc()
}
// ByEnableDingtalkOauth orders the results by the enable_dingtalk_oauth field.
func ByEnableDingtalkOauth(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldEnableDingtalkOauth, opts...).ToFunc()
}
// ByDingtalkClientID orders the results by the dingtalk_client_id field.
func ByDingtalkClientID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDingtalkClientID, opts...).ToFunc()
}
// ByDingtalkClientSecret orders the results by the dingtalk_client_secret field.
func ByDingtalkClientSecret(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDingtalkClientSecret, opts...).ToFunc()
}
// ByCreatedAt orders the results by the created_at field.
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()

View File

@@ -70,21 +70,6 @@ func DisablePasswordLogin(v bool) predicate.Setting {
return predicate.Setting(sql.FieldEQ(FieldDisablePasswordLogin, v))
}
// EnableDingtalkOauth applies equality check predicate on the "enable_dingtalk_oauth" field. It's identical to EnableDingtalkOauthEQ.
func EnableDingtalkOauth(v bool) predicate.Setting {
return predicate.Setting(sql.FieldEQ(FieldEnableDingtalkOauth, v))
}
// DingtalkClientID applies equality check predicate on the "dingtalk_client_id" field. It's identical to DingtalkClientIDEQ.
func DingtalkClientID(v string) predicate.Setting {
return predicate.Setting(sql.FieldEQ(FieldDingtalkClientID, v))
}
// DingtalkClientSecret applies equality check predicate on the "dingtalk_client_secret" field. It's identical to DingtalkClientSecretEQ.
func DingtalkClientSecret(v string) predicate.Setting {
return predicate.Setting(sql.FieldEQ(FieldDingtalkClientSecret, v))
}
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
func CreatedAt(v time.Time) predicate.Setting {
return predicate.Setting(sql.FieldEQ(FieldCreatedAt, v))
@@ -125,164 +110,24 @@ func DisablePasswordLoginNEQ(v bool) predicate.Setting {
return predicate.Setting(sql.FieldNEQ(FieldDisablePasswordLogin, v))
}
// EnableDingtalkOauthEQ applies the EQ predicate on the "enable_dingtalk_oauth" field.
func EnableDingtalkOauthEQ(v bool) predicate.Setting {
return predicate.Setting(sql.FieldEQ(FieldEnableDingtalkOauth, v))
// DingtalkOauthIsNil applies the IsNil predicate on the "dingtalk_oauth" field.
func DingtalkOauthIsNil() predicate.Setting {
return predicate.Setting(sql.FieldIsNull(FieldDingtalkOauth))
}
// EnableDingtalkOauthNEQ applies the NEQ predicate on the "enable_dingtalk_oauth" field.
func EnableDingtalkOauthNEQ(v bool) predicate.Setting {
return predicate.Setting(sql.FieldNEQ(FieldEnableDingtalkOauth, v))
// DingtalkOauthNotNil applies the NotNil predicate on the "dingtalk_oauth" field.
func DingtalkOauthNotNil() predicate.Setting {
return predicate.Setting(sql.FieldNotNull(FieldDingtalkOauth))
}
// DingtalkClientIDEQ applies the EQ predicate on the "dingtalk_client_id" field.
func DingtalkClientIDEQ(v string) predicate.Setting {
return predicate.Setting(sql.FieldEQ(FieldDingtalkClientID, v))
// CustomOauthIsNil applies the IsNil predicate on the "custom_oauth" field.
func CustomOauthIsNil() predicate.Setting {
return predicate.Setting(sql.FieldIsNull(FieldCustomOauth))
}
// DingtalkClientIDNEQ applies the NEQ predicate on the "dingtalk_client_id" field.
func DingtalkClientIDNEQ(v string) predicate.Setting {
return predicate.Setting(sql.FieldNEQ(FieldDingtalkClientID, v))
}
// DingtalkClientIDIn applies the In predicate on the "dingtalk_client_id" field.
func DingtalkClientIDIn(vs ...string) predicate.Setting {
return predicate.Setting(sql.FieldIn(FieldDingtalkClientID, vs...))
}
// DingtalkClientIDNotIn applies the NotIn predicate on the "dingtalk_client_id" field.
func DingtalkClientIDNotIn(vs ...string) predicate.Setting {
return predicate.Setting(sql.FieldNotIn(FieldDingtalkClientID, vs...))
}
// DingtalkClientIDGT applies the GT predicate on the "dingtalk_client_id" field.
func DingtalkClientIDGT(v string) predicate.Setting {
return predicate.Setting(sql.FieldGT(FieldDingtalkClientID, v))
}
// DingtalkClientIDGTE applies the GTE predicate on the "dingtalk_client_id" field.
func DingtalkClientIDGTE(v string) predicate.Setting {
return predicate.Setting(sql.FieldGTE(FieldDingtalkClientID, v))
}
// DingtalkClientIDLT applies the LT predicate on the "dingtalk_client_id" field.
func DingtalkClientIDLT(v string) predicate.Setting {
return predicate.Setting(sql.FieldLT(FieldDingtalkClientID, v))
}
// DingtalkClientIDLTE applies the LTE predicate on the "dingtalk_client_id" field.
func DingtalkClientIDLTE(v string) predicate.Setting {
return predicate.Setting(sql.FieldLTE(FieldDingtalkClientID, v))
}
// DingtalkClientIDContains applies the Contains predicate on the "dingtalk_client_id" field.
func DingtalkClientIDContains(v string) predicate.Setting {
return predicate.Setting(sql.FieldContains(FieldDingtalkClientID, v))
}
// DingtalkClientIDHasPrefix applies the HasPrefix predicate on the "dingtalk_client_id" field.
func DingtalkClientIDHasPrefix(v string) predicate.Setting {
return predicate.Setting(sql.FieldHasPrefix(FieldDingtalkClientID, v))
}
// DingtalkClientIDHasSuffix applies the HasSuffix predicate on the "dingtalk_client_id" field.
func DingtalkClientIDHasSuffix(v string) predicate.Setting {
return predicate.Setting(sql.FieldHasSuffix(FieldDingtalkClientID, v))
}
// DingtalkClientIDIsNil applies the IsNil predicate on the "dingtalk_client_id" field.
func DingtalkClientIDIsNil() predicate.Setting {
return predicate.Setting(sql.FieldIsNull(FieldDingtalkClientID))
}
// DingtalkClientIDNotNil applies the NotNil predicate on the "dingtalk_client_id" field.
func DingtalkClientIDNotNil() predicate.Setting {
return predicate.Setting(sql.FieldNotNull(FieldDingtalkClientID))
}
// DingtalkClientIDEqualFold applies the EqualFold predicate on the "dingtalk_client_id" field.
func DingtalkClientIDEqualFold(v string) predicate.Setting {
return predicate.Setting(sql.FieldEqualFold(FieldDingtalkClientID, v))
}
// DingtalkClientIDContainsFold applies the ContainsFold predicate on the "dingtalk_client_id" field.
func DingtalkClientIDContainsFold(v string) predicate.Setting {
return predicate.Setting(sql.FieldContainsFold(FieldDingtalkClientID, v))
}
// DingtalkClientSecretEQ applies the EQ predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretEQ(v string) predicate.Setting {
return predicate.Setting(sql.FieldEQ(FieldDingtalkClientSecret, v))
}
// DingtalkClientSecretNEQ applies the NEQ predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretNEQ(v string) predicate.Setting {
return predicate.Setting(sql.FieldNEQ(FieldDingtalkClientSecret, v))
}
// DingtalkClientSecretIn applies the In predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretIn(vs ...string) predicate.Setting {
return predicate.Setting(sql.FieldIn(FieldDingtalkClientSecret, vs...))
}
// DingtalkClientSecretNotIn applies the NotIn predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretNotIn(vs ...string) predicate.Setting {
return predicate.Setting(sql.FieldNotIn(FieldDingtalkClientSecret, vs...))
}
// DingtalkClientSecretGT applies the GT predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretGT(v string) predicate.Setting {
return predicate.Setting(sql.FieldGT(FieldDingtalkClientSecret, v))
}
// DingtalkClientSecretGTE applies the GTE predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretGTE(v string) predicate.Setting {
return predicate.Setting(sql.FieldGTE(FieldDingtalkClientSecret, v))
}
// DingtalkClientSecretLT applies the LT predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretLT(v string) predicate.Setting {
return predicate.Setting(sql.FieldLT(FieldDingtalkClientSecret, v))
}
// DingtalkClientSecretLTE applies the LTE predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretLTE(v string) predicate.Setting {
return predicate.Setting(sql.FieldLTE(FieldDingtalkClientSecret, v))
}
// DingtalkClientSecretContains applies the Contains predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretContains(v string) predicate.Setting {
return predicate.Setting(sql.FieldContains(FieldDingtalkClientSecret, v))
}
// DingtalkClientSecretHasPrefix applies the HasPrefix predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretHasPrefix(v string) predicate.Setting {
return predicate.Setting(sql.FieldHasPrefix(FieldDingtalkClientSecret, v))
}
// DingtalkClientSecretHasSuffix applies the HasSuffix predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretHasSuffix(v string) predicate.Setting {
return predicate.Setting(sql.FieldHasSuffix(FieldDingtalkClientSecret, v))
}
// DingtalkClientSecretIsNil applies the IsNil predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretIsNil() predicate.Setting {
return predicate.Setting(sql.FieldIsNull(FieldDingtalkClientSecret))
}
// DingtalkClientSecretNotNil applies the NotNil predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretNotNil() predicate.Setting {
return predicate.Setting(sql.FieldNotNull(FieldDingtalkClientSecret))
}
// DingtalkClientSecretEqualFold applies the EqualFold predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretEqualFold(v string) predicate.Setting {
return predicate.Setting(sql.FieldEqualFold(FieldDingtalkClientSecret, v))
}
// DingtalkClientSecretContainsFold applies the ContainsFold predicate on the "dingtalk_client_secret" field.
func DingtalkClientSecretContainsFold(v string) predicate.Setting {
return predicate.Setting(sql.FieldContainsFold(FieldDingtalkClientSecret, v))
// CustomOauthNotNil applies the NotNil predicate on the "custom_oauth" field.
func CustomOauthNotNil() predicate.Setting {
return predicate.Setting(sql.FieldNotNull(FieldCustomOauth))
}
// CreatedAtEQ applies the EQ predicate on the "created_at" field.

View File

@@ -13,6 +13,7 @@ import (
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/chaitin/MonkeyCode/backend/db/setting"
"github.com/chaitin/MonkeyCode/backend/ent/types"
"github.com/google/uuid"
)
@@ -66,45 +67,15 @@ func (sc *SettingCreate) SetNillableDisablePasswordLogin(b *bool) *SettingCreate
return sc
}
// SetEnableDingtalkOauth sets the "enable_dingtalk_oauth" field.
func (sc *SettingCreate) SetEnableDingtalkOauth(b bool) *SettingCreate {
sc.mutation.SetEnableDingtalkOauth(b)
// SetDingtalkOauth sets the "dingtalk_oauth" field.
func (sc *SettingCreate) SetDingtalkOauth(to *types.DingtalkOAuth) *SettingCreate {
sc.mutation.SetDingtalkOauth(to)
return sc
}
// SetNillableEnableDingtalkOauth sets the "enable_dingtalk_oauth" field if the given value is not nil.
func (sc *SettingCreate) SetNillableEnableDingtalkOauth(b *bool) *SettingCreate {
if b != nil {
sc.SetEnableDingtalkOauth(*b)
}
return sc
}
// SetDingtalkClientID sets the "dingtalk_client_id" field.
func (sc *SettingCreate) SetDingtalkClientID(s string) *SettingCreate {
sc.mutation.SetDingtalkClientID(s)
return sc
}
// SetNillableDingtalkClientID sets the "dingtalk_client_id" field if the given value is not nil.
func (sc *SettingCreate) SetNillableDingtalkClientID(s *string) *SettingCreate {
if s != nil {
sc.SetDingtalkClientID(*s)
}
return sc
}
// SetDingtalkClientSecret sets the "dingtalk_client_secret" field.
func (sc *SettingCreate) SetDingtalkClientSecret(s string) *SettingCreate {
sc.mutation.SetDingtalkClientSecret(s)
return sc
}
// SetNillableDingtalkClientSecret sets the "dingtalk_client_secret" field if the given value is not nil.
func (sc *SettingCreate) SetNillableDingtalkClientSecret(s *string) *SettingCreate {
if s != nil {
sc.SetDingtalkClientSecret(*s)
}
// SetCustomOauth sets the "custom_oauth" field.
func (sc *SettingCreate) SetCustomOauth(to *types.CustomOAuth) *SettingCreate {
sc.mutation.SetCustomOauth(to)
return sc
}
@@ -189,10 +160,6 @@ func (sc *SettingCreate) defaults() {
v := setting.DefaultDisablePasswordLogin
sc.mutation.SetDisablePasswordLogin(v)
}
if _, ok := sc.mutation.EnableDingtalkOauth(); !ok {
v := setting.DefaultEnableDingtalkOauth
sc.mutation.SetEnableDingtalkOauth(v)
}
if _, ok := sc.mutation.CreatedAt(); !ok {
v := setting.DefaultCreatedAt()
sc.mutation.SetCreatedAt(v)
@@ -214,9 +181,6 @@ func (sc *SettingCreate) check() error {
if _, ok := sc.mutation.DisablePasswordLogin(); !ok {
return &ValidationError{Name: "disable_password_login", err: errors.New(`db: missing required field "Setting.disable_password_login"`)}
}
if _, ok := sc.mutation.EnableDingtalkOauth(); !ok {
return &ValidationError{Name: "enable_dingtalk_oauth", err: errors.New(`db: missing required field "Setting.enable_dingtalk_oauth"`)}
}
if _, ok := sc.mutation.CreatedAt(); !ok {
return &ValidationError{Name: "created_at", err: errors.New(`db: missing required field "Setting.created_at"`)}
}
@@ -271,17 +235,13 @@ func (sc *SettingCreate) createSpec() (*Setting, *sqlgraph.CreateSpec) {
_spec.SetField(setting.FieldDisablePasswordLogin, field.TypeBool, value)
_node.DisablePasswordLogin = value
}
if value, ok := sc.mutation.EnableDingtalkOauth(); ok {
_spec.SetField(setting.FieldEnableDingtalkOauth, field.TypeBool, value)
_node.EnableDingtalkOauth = value
if value, ok := sc.mutation.DingtalkOauth(); ok {
_spec.SetField(setting.FieldDingtalkOauth, field.TypeJSON, value)
_node.DingtalkOauth = value
}
if value, ok := sc.mutation.DingtalkClientID(); ok {
_spec.SetField(setting.FieldDingtalkClientID, field.TypeString, value)
_node.DingtalkClientID = value
}
if value, ok := sc.mutation.DingtalkClientSecret(); ok {
_spec.SetField(setting.FieldDingtalkClientSecret, field.TypeString, value)
_node.DingtalkClientSecret = value
if value, ok := sc.mutation.CustomOauth(); ok {
_spec.SetField(setting.FieldCustomOauth, field.TypeJSON, value)
_node.CustomOauth = value
}
if value, ok := sc.mutation.CreatedAt(); ok {
_spec.SetField(setting.FieldCreatedAt, field.TypeTime, value)
@@ -379,51 +339,39 @@ func (u *SettingUpsert) UpdateDisablePasswordLogin() *SettingUpsert {
return u
}
// SetEnableDingtalkOauth sets the "enable_dingtalk_oauth" field.
func (u *SettingUpsert) SetEnableDingtalkOauth(v bool) *SettingUpsert {
u.Set(setting.FieldEnableDingtalkOauth, v)
// SetDingtalkOauth sets the "dingtalk_oauth" field.
func (u *SettingUpsert) SetDingtalkOauth(v *types.DingtalkOAuth) *SettingUpsert {
u.Set(setting.FieldDingtalkOauth, v)
return u
}
// UpdateEnableDingtalkOauth sets the "enable_dingtalk_oauth" field to the value that was provided on create.
func (u *SettingUpsert) UpdateEnableDingtalkOauth() *SettingUpsert {
u.SetExcluded(setting.FieldEnableDingtalkOauth)
// UpdateDingtalkOauth sets the "dingtalk_oauth" field to the value that was provided on create.
func (u *SettingUpsert) UpdateDingtalkOauth() *SettingUpsert {
u.SetExcluded(setting.FieldDingtalkOauth)
return u
}
// SetDingtalkClientID sets the "dingtalk_client_id" field.
func (u *SettingUpsert) SetDingtalkClientID(v string) *SettingUpsert {
u.Set(setting.FieldDingtalkClientID, v)
// ClearDingtalkOauth clears the value of the "dingtalk_oauth" field.
func (u *SettingUpsert) ClearDingtalkOauth() *SettingUpsert {
u.SetNull(setting.FieldDingtalkOauth)
return u
}
// UpdateDingtalkClientID sets the "dingtalk_client_id" field to the value that was provided on create.
func (u *SettingUpsert) UpdateDingtalkClientID() *SettingUpsert {
u.SetExcluded(setting.FieldDingtalkClientID)
// SetCustomOauth sets the "custom_oauth" field.
func (u *SettingUpsert) SetCustomOauth(v *types.CustomOAuth) *SettingUpsert {
u.Set(setting.FieldCustomOauth, v)
return u
}
// ClearDingtalkClientID clears the value of the "dingtalk_client_id" field.
func (u *SettingUpsert) ClearDingtalkClientID() *SettingUpsert {
u.SetNull(setting.FieldDingtalkClientID)
// UpdateCustomOauth sets the "custom_oauth" field to the value that was provided on create.
func (u *SettingUpsert) UpdateCustomOauth() *SettingUpsert {
u.SetExcluded(setting.FieldCustomOauth)
return u
}
// SetDingtalkClientSecret sets the "dingtalk_client_secret" field.
func (u *SettingUpsert) SetDingtalkClientSecret(v string) *SettingUpsert {
u.Set(setting.FieldDingtalkClientSecret, v)
return u
}
// UpdateDingtalkClientSecret sets the "dingtalk_client_secret" field to the value that was provided on create.
func (u *SettingUpsert) UpdateDingtalkClientSecret() *SettingUpsert {
u.SetExcluded(setting.FieldDingtalkClientSecret)
return u
}
// ClearDingtalkClientSecret clears the value of the "dingtalk_client_secret" field.
func (u *SettingUpsert) ClearDingtalkClientSecret() *SettingUpsert {
u.SetNull(setting.FieldDingtalkClientSecret)
// ClearCustomOauth clears the value of the "custom_oauth" field.
func (u *SettingUpsert) ClearCustomOauth() *SettingUpsert {
u.SetNull(setting.FieldCustomOauth)
return u
}
@@ -541,59 +489,45 @@ func (u *SettingUpsertOne) UpdateDisablePasswordLogin() *SettingUpsertOne {
})
}
// SetEnableDingtalkOauth sets the "enable_dingtalk_oauth" field.
func (u *SettingUpsertOne) SetEnableDingtalkOauth(v bool) *SettingUpsertOne {
// SetDingtalkOauth sets the "dingtalk_oauth" field.
func (u *SettingUpsertOne) SetDingtalkOauth(v *types.DingtalkOAuth) *SettingUpsertOne {
return u.Update(func(s *SettingUpsert) {
s.SetEnableDingtalkOauth(v)
s.SetDingtalkOauth(v)
})
}
// UpdateEnableDingtalkOauth sets the "enable_dingtalk_oauth" field to the value that was provided on create.
func (u *SettingUpsertOne) UpdateEnableDingtalkOauth() *SettingUpsertOne {
// UpdateDingtalkOauth sets the "dingtalk_oauth" field to the value that was provided on create.
func (u *SettingUpsertOne) UpdateDingtalkOauth() *SettingUpsertOne {
return u.Update(func(s *SettingUpsert) {
s.UpdateEnableDingtalkOauth()
s.UpdateDingtalkOauth()
})
}
// SetDingtalkClientID sets the "dingtalk_client_id" field.
func (u *SettingUpsertOne) SetDingtalkClientID(v string) *SettingUpsertOne {
// ClearDingtalkOauth clears the value of the "dingtalk_oauth" field.
func (u *SettingUpsertOne) ClearDingtalkOauth() *SettingUpsertOne {
return u.Update(func(s *SettingUpsert) {
s.SetDingtalkClientID(v)
s.ClearDingtalkOauth()
})
}
// UpdateDingtalkClientID sets the "dingtalk_client_id" field to the value that was provided on create.
func (u *SettingUpsertOne) UpdateDingtalkClientID() *SettingUpsertOne {
// SetCustomOauth sets the "custom_oauth" field.
func (u *SettingUpsertOne) SetCustomOauth(v *types.CustomOAuth) *SettingUpsertOne {
return u.Update(func(s *SettingUpsert) {
s.UpdateDingtalkClientID()
s.SetCustomOauth(v)
})
}
// ClearDingtalkClientID clears the value of the "dingtalk_client_id" field.
func (u *SettingUpsertOne) ClearDingtalkClientID() *SettingUpsertOne {
// UpdateCustomOauth sets the "custom_oauth" field to the value that was provided on create.
func (u *SettingUpsertOne) UpdateCustomOauth() *SettingUpsertOne {
return u.Update(func(s *SettingUpsert) {
s.ClearDingtalkClientID()
s.UpdateCustomOauth()
})
}
// SetDingtalkClientSecret sets the "dingtalk_client_secret" field.
func (u *SettingUpsertOne) SetDingtalkClientSecret(v string) *SettingUpsertOne {
// ClearCustomOauth clears the value of the "custom_oauth" field.
func (u *SettingUpsertOne) ClearCustomOauth() *SettingUpsertOne {
return u.Update(func(s *SettingUpsert) {
s.SetDingtalkClientSecret(v)
})
}
// UpdateDingtalkClientSecret sets the "dingtalk_client_secret" field to the value that was provided on create.
func (u *SettingUpsertOne) UpdateDingtalkClientSecret() *SettingUpsertOne {
return u.Update(func(s *SettingUpsert) {
s.UpdateDingtalkClientSecret()
})
}
// ClearDingtalkClientSecret clears the value of the "dingtalk_client_secret" field.
func (u *SettingUpsertOne) ClearDingtalkClientSecret() *SettingUpsertOne {
return u.Update(func(s *SettingUpsert) {
s.ClearDingtalkClientSecret()
s.ClearCustomOauth()
})
}
@@ -882,59 +816,45 @@ func (u *SettingUpsertBulk) UpdateDisablePasswordLogin() *SettingUpsertBulk {
})
}
// SetEnableDingtalkOauth sets the "enable_dingtalk_oauth" field.
func (u *SettingUpsertBulk) SetEnableDingtalkOauth(v bool) *SettingUpsertBulk {
// SetDingtalkOauth sets the "dingtalk_oauth" field.
func (u *SettingUpsertBulk) SetDingtalkOauth(v *types.DingtalkOAuth) *SettingUpsertBulk {
return u.Update(func(s *SettingUpsert) {
s.SetEnableDingtalkOauth(v)
s.SetDingtalkOauth(v)
})
}
// UpdateEnableDingtalkOauth sets the "enable_dingtalk_oauth" field to the value that was provided on create.
func (u *SettingUpsertBulk) UpdateEnableDingtalkOauth() *SettingUpsertBulk {
// UpdateDingtalkOauth sets the "dingtalk_oauth" field to the value that was provided on create.
func (u *SettingUpsertBulk) UpdateDingtalkOauth() *SettingUpsertBulk {
return u.Update(func(s *SettingUpsert) {
s.UpdateEnableDingtalkOauth()
s.UpdateDingtalkOauth()
})
}
// SetDingtalkClientID sets the "dingtalk_client_id" field.
func (u *SettingUpsertBulk) SetDingtalkClientID(v string) *SettingUpsertBulk {
// ClearDingtalkOauth clears the value of the "dingtalk_oauth" field.
func (u *SettingUpsertBulk) ClearDingtalkOauth() *SettingUpsertBulk {
return u.Update(func(s *SettingUpsert) {
s.SetDingtalkClientID(v)
s.ClearDingtalkOauth()
})
}
// UpdateDingtalkClientID sets the "dingtalk_client_id" field to the value that was provided on create.
func (u *SettingUpsertBulk) UpdateDingtalkClientID() *SettingUpsertBulk {
// SetCustomOauth sets the "custom_oauth" field.
func (u *SettingUpsertBulk) SetCustomOauth(v *types.CustomOAuth) *SettingUpsertBulk {
return u.Update(func(s *SettingUpsert) {
s.UpdateDingtalkClientID()
s.SetCustomOauth(v)
})
}
// ClearDingtalkClientID clears the value of the "dingtalk_client_id" field.
func (u *SettingUpsertBulk) ClearDingtalkClientID() *SettingUpsertBulk {
// UpdateCustomOauth sets the "custom_oauth" field to the value that was provided on create.
func (u *SettingUpsertBulk) UpdateCustomOauth() *SettingUpsertBulk {
return u.Update(func(s *SettingUpsert) {
s.ClearDingtalkClientID()
s.UpdateCustomOauth()
})
}
// SetDingtalkClientSecret sets the "dingtalk_client_secret" field.
func (u *SettingUpsertBulk) SetDingtalkClientSecret(v string) *SettingUpsertBulk {
// ClearCustomOauth clears the value of the "custom_oauth" field.
func (u *SettingUpsertBulk) ClearCustomOauth() *SettingUpsertBulk {
return u.Update(func(s *SettingUpsert) {
s.SetDingtalkClientSecret(v)
})
}
// UpdateDingtalkClientSecret sets the "dingtalk_client_secret" field to the value that was provided on create.
func (u *SettingUpsertBulk) UpdateDingtalkClientSecret() *SettingUpsertBulk {
return u.Update(func(s *SettingUpsert) {
s.UpdateDingtalkClientSecret()
})
}
// ClearDingtalkClientSecret clears the value of the "dingtalk_client_secret" field.
func (u *SettingUpsertBulk) ClearDingtalkClientSecret() *SettingUpsertBulk {
return u.Update(func(s *SettingUpsert) {
s.ClearDingtalkClientSecret()
s.ClearCustomOauth()
})
}

View File

@@ -13,6 +13,7 @@ import (
"entgo.io/ent/schema/field"
"github.com/chaitin/MonkeyCode/backend/db/predicate"
"github.com/chaitin/MonkeyCode/backend/db/setting"
"github.com/chaitin/MonkeyCode/backend/ent/types"
)
// SettingUpdate is the builder for updating Setting entities.
@@ -71,57 +72,27 @@ func (su *SettingUpdate) SetNillableDisablePasswordLogin(b *bool) *SettingUpdate
return su
}
// SetEnableDingtalkOauth sets the "enable_dingtalk_oauth" field.
func (su *SettingUpdate) SetEnableDingtalkOauth(b bool) *SettingUpdate {
su.mutation.SetEnableDingtalkOauth(b)
// SetDingtalkOauth sets the "dingtalk_oauth" field.
func (su *SettingUpdate) SetDingtalkOauth(to *types.DingtalkOAuth) *SettingUpdate {
su.mutation.SetDingtalkOauth(to)
return su
}
// SetNillableEnableDingtalkOauth sets the "enable_dingtalk_oauth" field if the given value is not nil.
func (su *SettingUpdate) SetNillableEnableDingtalkOauth(b *bool) *SettingUpdate {
if b != nil {
su.SetEnableDingtalkOauth(*b)
}
// ClearDingtalkOauth clears the value of the "dingtalk_oauth" field.
func (su *SettingUpdate) ClearDingtalkOauth() *SettingUpdate {
su.mutation.ClearDingtalkOauth()
return su
}
// SetDingtalkClientID sets the "dingtalk_client_id" field.
func (su *SettingUpdate) SetDingtalkClientID(s string) *SettingUpdate {
su.mutation.SetDingtalkClientID(s)
// SetCustomOauth sets the "custom_oauth" field.
func (su *SettingUpdate) SetCustomOauth(to *types.CustomOAuth) *SettingUpdate {
su.mutation.SetCustomOauth(to)
return su
}
// SetNillableDingtalkClientID sets the "dingtalk_client_id" field if the given value is not nil.
func (su *SettingUpdate) SetNillableDingtalkClientID(s *string) *SettingUpdate {
if s != nil {
su.SetDingtalkClientID(*s)
}
return su
}
// ClearDingtalkClientID clears the value of the "dingtalk_client_id" field.
func (su *SettingUpdate) ClearDingtalkClientID() *SettingUpdate {
su.mutation.ClearDingtalkClientID()
return su
}
// SetDingtalkClientSecret sets the "dingtalk_client_secret" field.
func (su *SettingUpdate) SetDingtalkClientSecret(s string) *SettingUpdate {
su.mutation.SetDingtalkClientSecret(s)
return su
}
// SetNillableDingtalkClientSecret sets the "dingtalk_client_secret" field if the given value is not nil.
func (su *SettingUpdate) SetNillableDingtalkClientSecret(s *string) *SettingUpdate {
if s != nil {
su.SetDingtalkClientSecret(*s)
}
return su
}
// ClearDingtalkClientSecret clears the value of the "dingtalk_client_secret" field.
func (su *SettingUpdate) ClearDingtalkClientSecret() *SettingUpdate {
su.mutation.ClearDingtalkClientSecret()
// ClearCustomOauth clears the value of the "custom_oauth" field.
func (su *SettingUpdate) ClearCustomOauth() *SettingUpdate {
su.mutation.ClearCustomOauth()
return su
}
@@ -210,20 +181,17 @@ func (su *SettingUpdate) sqlSave(ctx context.Context) (n int, err error) {
if value, ok := su.mutation.DisablePasswordLogin(); ok {
_spec.SetField(setting.FieldDisablePasswordLogin, field.TypeBool, value)
}
if value, ok := su.mutation.EnableDingtalkOauth(); ok {
_spec.SetField(setting.FieldEnableDingtalkOauth, field.TypeBool, value)
if value, ok := su.mutation.DingtalkOauth(); ok {
_spec.SetField(setting.FieldDingtalkOauth, field.TypeJSON, value)
}
if value, ok := su.mutation.DingtalkClientID(); ok {
_spec.SetField(setting.FieldDingtalkClientID, field.TypeString, value)
if su.mutation.DingtalkOauthCleared() {
_spec.ClearField(setting.FieldDingtalkOauth, field.TypeJSON)
}
if su.mutation.DingtalkClientIDCleared() {
_spec.ClearField(setting.FieldDingtalkClientID, field.TypeString)
if value, ok := su.mutation.CustomOauth(); ok {
_spec.SetField(setting.FieldCustomOauth, field.TypeJSON, value)
}
if value, ok := su.mutation.DingtalkClientSecret(); ok {
_spec.SetField(setting.FieldDingtalkClientSecret, field.TypeString, value)
}
if su.mutation.DingtalkClientSecretCleared() {
_spec.ClearField(setting.FieldDingtalkClientSecret, field.TypeString)
if su.mutation.CustomOauthCleared() {
_spec.ClearField(setting.FieldCustomOauth, field.TypeJSON)
}
if value, ok := su.mutation.CreatedAt(); ok {
_spec.SetField(setting.FieldCreatedAt, field.TypeTime, value)
@@ -295,57 +263,27 @@ func (suo *SettingUpdateOne) SetNillableDisablePasswordLogin(b *bool) *SettingUp
return suo
}
// SetEnableDingtalkOauth sets the "enable_dingtalk_oauth" field.
func (suo *SettingUpdateOne) SetEnableDingtalkOauth(b bool) *SettingUpdateOne {
suo.mutation.SetEnableDingtalkOauth(b)
// SetDingtalkOauth sets the "dingtalk_oauth" field.
func (suo *SettingUpdateOne) SetDingtalkOauth(to *types.DingtalkOAuth) *SettingUpdateOne {
suo.mutation.SetDingtalkOauth(to)
return suo
}
// SetNillableEnableDingtalkOauth sets the "enable_dingtalk_oauth" field if the given value is not nil.
func (suo *SettingUpdateOne) SetNillableEnableDingtalkOauth(b *bool) *SettingUpdateOne {
if b != nil {
suo.SetEnableDingtalkOauth(*b)
}
// ClearDingtalkOauth clears the value of the "dingtalk_oauth" field.
func (suo *SettingUpdateOne) ClearDingtalkOauth() *SettingUpdateOne {
suo.mutation.ClearDingtalkOauth()
return suo
}
// SetDingtalkClientID sets the "dingtalk_client_id" field.
func (suo *SettingUpdateOne) SetDingtalkClientID(s string) *SettingUpdateOne {
suo.mutation.SetDingtalkClientID(s)
// SetCustomOauth sets the "custom_oauth" field.
func (suo *SettingUpdateOne) SetCustomOauth(to *types.CustomOAuth) *SettingUpdateOne {
suo.mutation.SetCustomOauth(to)
return suo
}
// SetNillableDingtalkClientID sets the "dingtalk_client_id" field if the given value is not nil.
func (suo *SettingUpdateOne) SetNillableDingtalkClientID(s *string) *SettingUpdateOne {
if s != nil {
suo.SetDingtalkClientID(*s)
}
return suo
}
// ClearDingtalkClientID clears the value of the "dingtalk_client_id" field.
func (suo *SettingUpdateOne) ClearDingtalkClientID() *SettingUpdateOne {
suo.mutation.ClearDingtalkClientID()
return suo
}
// SetDingtalkClientSecret sets the "dingtalk_client_secret" field.
func (suo *SettingUpdateOne) SetDingtalkClientSecret(s string) *SettingUpdateOne {
suo.mutation.SetDingtalkClientSecret(s)
return suo
}
// SetNillableDingtalkClientSecret sets the "dingtalk_client_secret" field if the given value is not nil.
func (suo *SettingUpdateOne) SetNillableDingtalkClientSecret(s *string) *SettingUpdateOne {
if s != nil {
suo.SetDingtalkClientSecret(*s)
}
return suo
}
// ClearDingtalkClientSecret clears the value of the "dingtalk_client_secret" field.
func (suo *SettingUpdateOne) ClearDingtalkClientSecret() *SettingUpdateOne {
suo.mutation.ClearDingtalkClientSecret()
// ClearCustomOauth clears the value of the "custom_oauth" field.
func (suo *SettingUpdateOne) ClearCustomOauth() *SettingUpdateOne {
suo.mutation.ClearCustomOauth()
return suo
}
@@ -464,20 +402,17 @@ func (suo *SettingUpdateOne) sqlSave(ctx context.Context) (_node *Setting, err e
if value, ok := suo.mutation.DisablePasswordLogin(); ok {
_spec.SetField(setting.FieldDisablePasswordLogin, field.TypeBool, value)
}
if value, ok := suo.mutation.EnableDingtalkOauth(); ok {
_spec.SetField(setting.FieldEnableDingtalkOauth, field.TypeBool, value)
if value, ok := suo.mutation.DingtalkOauth(); ok {
_spec.SetField(setting.FieldDingtalkOauth, field.TypeJSON, value)
}
if value, ok := suo.mutation.DingtalkClientID(); ok {
_spec.SetField(setting.FieldDingtalkClientID, field.TypeString, value)
if suo.mutation.DingtalkOauthCleared() {
_spec.ClearField(setting.FieldDingtalkOauth, field.TypeJSON)
}
if suo.mutation.DingtalkClientIDCleared() {
_spec.ClearField(setting.FieldDingtalkClientID, field.TypeString)
if value, ok := suo.mutation.CustomOauth(); ok {
_spec.SetField(setting.FieldCustomOauth, field.TypeJSON, value)
}
if value, ok := suo.mutation.DingtalkClientSecret(); ok {
_spec.SetField(setting.FieldDingtalkClientSecret, field.TypeString, value)
}
if suo.mutation.DingtalkClientSecretCleared() {
_spec.ClearField(setting.FieldDingtalkClientSecret, field.TypeString)
if suo.mutation.CustomOauthCleared() {
_spec.ClearField(setting.FieldCustomOauth, field.TypeJSON)
}
if value, ok := suo.mutation.CreatedAt(); ok {
_spec.SetField(setting.FieldCreatedAt, field.TypeTime, value)

View File

@@ -17,7 +17,7 @@
"application/json"
],
"tags": [
"User"
"Admin"
],
"summary": "创建管理员",
"operationId": "create-admin",
@@ -64,7 +64,7 @@
"application/json"
],
"tags": [
"User"
"Admin"
],
"summary": "删除管理员",
"operationId": "delete-admin",
@@ -109,7 +109,7 @@
"application/json"
],
"tags": [
"User"
"Admin"
],
"summary": "获取管理员用户列表",
"operationId": "list-admin-user",
@@ -165,7 +165,7 @@
"application/json"
],
"tags": [
"User"
"Admin"
],
"summary": "管理员登录",
"operationId": "admin-login",
@@ -212,7 +212,7 @@
"application/json"
],
"tags": [
"User"
"Admin"
],
"summary": "获取管理员登录历史",
"operationId": "admin-login-history",
@@ -268,7 +268,7 @@
"application/json"
],
"tags": [
"User"
"Admin"
],
"summary": "获取系统设置",
"operationId": "get-setting",
@@ -302,7 +302,7 @@
"application/json"
],
"tags": [
"User"
"Admin"
],
"summary": "更新系统设置",
"operationId": "update-setting",
@@ -1604,15 +1604,23 @@
"summary": "用户 OAuth 登录或注册",
"operationId": "user-oauth-signup-or-in",
"parameters": [
{
"type": "string",
"description": "邀请码",
"name": "inviate_code",
"in": "query"
},
{
"enum": [
"email",
"dingtalk"
"dingtalk",
"custom"
],
"type": "string",
"x-enum-varnames": [
"UserPlatformEmail",
"UserPlatformDingTalk"
"UserPlatformDingTalk",
"UserPlatformCustom"
],
"description": "第三方平台 dingtalk",
"name": "platform",
@@ -1947,11 +1955,13 @@
"type": "string",
"enum": [
"email",
"dingtalk"
"dingtalk",
"custom"
],
"x-enum-varnames": [
"UserPlatformEmail",
"UserPlatformDingTalk"
"UserPlatformDingTalk",
"UserPlatformCustom"
]
},
"consts.UserStatus": {
@@ -2289,6 +2299,75 @@
}
}
},
"domain.CustomOAuth": {
"type": "object",
"properties": {
"access_token_url": {
"description": "自定义OAuth访问令牌URL",
"type": "string"
},
"authorize_url": {
"description": "自定义OAuth授权URL",
"type": "string"
},
"avatar_field": {
"description": "用户信息回包中的头像URL字段名",
"type": "string"
},
"client_id": {
"description": "自定义客户端ID",
"type": "string"
},
"client_secret": {
"description": "自定义客户端密钥",
"type": "string"
},
"email_field": {
"description": "用户信息回包中的邮箱字段名",
"type": "string"
},
"enable": {
"description": "自定义OAuth开关",
"type": "boolean"
},
"id_field": {
"description": "用户信息回包中的ID字段名",
"type": "string"
},
"name_field": {
"description": "用户信息回包中的用户名字段名",
"type": "string"
},
"scopes": {
"description": "自定义OAuth Scope列表",
"type": "array",
"items": {
"type": "string"
}
},
"userinfo_url": {
"description": "自定义OAuth用户信息URL",
"type": "string"
}
}
},
"domain.DingtalkOAuth": {
"type": "object",
"properties": {
"client_id": {
"description": "钉钉客户端ID",
"type": "string"
},
"client_secret": {
"description": "钉钉客户端密钥",
"type": "string"
},
"enable": {
"description": "钉钉OAuth开关",
"type": "boolean"
}
}
},
"domain.IPInfo": {
"type": "object",
"properties": {
@@ -2695,14 +2774,26 @@
"description": "创建时间",
"type": "integer"
},
"custom_oauth": {
"description": "自定义OAuth接入",
"allOf": [
{
"$ref": "#/definitions/domain.CustomOAuth"
}
]
},
"dingtalk_oauth": {
"description": "钉钉OAuth接入",
"allOf": [
{
"$ref": "#/definitions/domain.DingtalkOAuth"
}
]
},
"disable_password_login": {
"description": "是否禁用密码登录",
"type": "boolean"
},
"enable_dingtalk_oauth": {
"description": "是否开启钉钉OAuth",
"type": "boolean"
},
"enable_sso": {
"description": "是否开启SSO",
"type": "boolean"
@@ -2893,22 +2984,26 @@
"domain.UpdateSettingReq": {
"type": "object",
"properties": {
"dingtalk_client_id": {
"description": "钉钉客户端ID",
"type": "string"
"custom_oauth": {
"description": "自定义OAuth配置",
"allOf": [
{
"$ref": "#/definitions/domain.CustomOAuth"
}
]
},
"dingtalk_client_secret": {
"description": "钉钉客户端密钥",
"type": "string"
"dingtalk_oauth": {
"description": "钉钉OAuth配置",
"allOf": [
{
"$ref": "#/definitions/domain.DingtalkOAuth"
}
]
},
"disable_password_login": {
"description": "是否禁用密码登录",
"type": "boolean"
},
"enable_dingtalk_oauth": {
"description": "是否开启钉钉OAuth",
"type": "boolean"
},
"enable_sso": {
"description": "是否开启SSO",
"type": "boolean"
@@ -2946,6 +3041,10 @@
"domain.User": {
"type": "object",
"properties": {
"avatar_url": {
"description": "头像URL",
"type": "string"
},
"created_at": {
"description": "创建时间",
"type": "integer"

View File

@@ -13,6 +13,13 @@ type OAuthConfig struct {
ClientID string
ClientSecret string
RedirectURI string
Scope string
AuthorizeURL string
TokenURL string
UserInfoURL string
IDField string
NameField string
AvatarField string
}
type OAuthUserInfo struct {
@@ -27,6 +34,14 @@ type OAuthSignUpOrInReq struct {
Platform consts.UserPlatform `json:"platform" query:"platform" validate:"required"` // 第三方平台 dingtalk
SessionID string `json:"session_id" query:"session_id"` // 会话ID
RedirectURL string `json:"redirect_url" query:"redirect_url"` // 登录成功后跳转的 URL
InviteCode string `json:"inviate_code" query:"inviate_code"` // 邀请码
}
func (o OAuthSignUpOrInReq) OAuthKind() consts.OAuthKind {
if o.InviteCode == "" {
return consts.OAuthKindLogin
}
return consts.OAuthKindInvite
}
type OAuthCallbackReq struct {
@@ -43,4 +58,20 @@ type OAuthState struct {
SessionID string `json:"session_id"` // 会话ID
Platform consts.UserPlatform `json:"platform" query:"platform" validate:"required"` // 第三方平台 dingtalk
RedirectURL string `json:"redirect_url" query:"redirect_url"` // 登录成功后跳转的 URL
InviteCode string `json:"inviate_code"` // 邀请码
}
type OAuthAccessToken struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresIn int64 `json:"expires_in"`
Scope string `json:"scope"`
}
type GetAccessTokenReq struct {
GrantType string `json:"grant_type"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
Code string `json:"code"`
RedirectURL string `json:"redirect_uri"`
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/chaitin/MonkeyCode/backend/consts"
"github.com/chaitin/MonkeyCode/backend/db"
"github.com/chaitin/MonkeyCode/backend/ent/types"
"github.com/chaitin/MonkeyCode/backend/pkg/cvt"
)
@@ -48,8 +49,9 @@ type UserRepo interface {
UserLoginHistory(ctx context.Context, page *web.Pagination) ([]*db.UserLoginHistory, *db.PageInfo, error)
AdminLoginHistory(ctx context.Context, page *web.Pagination) ([]*db.AdminLoginHistory, *db.PageInfo, error)
GetSetting(ctx context.Context) (*db.Setting, error)
UpdateSetting(ctx context.Context, fn func(*db.SettingUpdateOne)) (*db.Setting, error)
SignUpOrIn(ctx context.Context, platform consts.UserPlatform, req *OAuthUserInfo) (*db.User, error)
UpdateSetting(ctx context.Context, fn func(*db.Setting, *db.SettingUpdateOne)) (*db.Setting, error)
OAuthRegister(ctx context.Context, platform consts.UserPlatform, inviteCode string, req *OAuthUserInfo) (*db.User, error)
OAuthLogin(ctx context.Context, platform consts.UserPlatform, req *OAuthUserInfo) (*db.User, error)
}
type UpdateUserReq struct {
@@ -202,6 +204,7 @@ type User struct {
Email string `json:"email"` // 邮箱
TwoStepAuth bool `json:"two_step_auth"` // 是否开启两步验证
Status consts.UserStatus `json:"status"` // 用户状态 active: 正常 locked: 锁定 inactive: 禁用
AvatarURL string `json:"avatar_url"` // 头像URL
CreatedAt int64 `json:"created_at"` // 创建时间
LastActiveAt int64 `json:"last_active_at"` // 最后活跃时间
}
@@ -215,6 +218,7 @@ func (u *User) From(e *db.User) *User {
u.Username = e.Username
u.Email = e.Email
u.Status = e.Status
u.AvatarURL = e.AvatarURL
u.CreatedAt = e.CreatedAt.Unix()
return u
@@ -249,21 +253,91 @@ type VSCodeSession struct {
}
type UpdateSettingReq struct {
EnableSSO *bool `json:"enable_sso"` // 是否开启SSO
ForceTwoFactorAuth *bool `json:"force_two_factor_auth"` // 是否强制两步验证
DisablePasswordLogin *bool `json:"disable_password_login"` // 是否禁用密码登录
EnableDingtalkOAuth *bool `json:"enable_dingtalk_oauth"` // 是否开启钉钉OAuth
DingtalkClientID *string `json:"dingtalk_client_id"` // 钉钉客户端ID
DingtalkClientSecret *string `json:"dingtalk_client_secret"` // 钉钉客户端密钥
EnableSSO *bool `json:"enable_sso"` // 是否开启SSO
ForceTwoFactorAuth *bool `json:"force_two_factor_auth"` // 是否强制两步验证
DisablePasswordLogin *bool `json:"disable_password_login"` // 是否禁用密码登录
DingtalkOAuth *DingtalkOAuthReq `json:"dingtalk_oauth"` // 钉钉OAuth配置
CustomOAuth *CustomOAuthReq `json:"custom_oauth"` // 自定义OAuth配置
}
type DingtalkOAuthReq struct {
Enable *bool `json:"enable"` // 钉钉OAuth开关
ClientID *string `json:"client_id"` // 钉钉客户端ID
ClientSecret *string `json:"client_secret"` // 钉钉客户端密钥
}
type DingtalkOAuth struct {
Enable bool `json:"enable"` // 钉钉OAuth开关
ClientID string `json:"client_id"` // 钉钉客户端ID
ClientSecret string `json:"client_secret"` // 钉钉客户端密钥
}
func (d *DingtalkOAuth) From(e *types.DingtalkOAuth) *DingtalkOAuth {
if e == nil {
d.Enable = false
return d
}
d.Enable = e.Enable
d.ClientID = e.ClientID
return d
}
type CustomOAuthReq struct {
Enable *bool `json:"enable"` // 自定义OAuth开关
ClientID *string `json:"client_id"` // 自定义客户端ID
ClientSecret *string `json:"client_secret"` // 自定义客户端密钥
AuthorizeURL *string `json:"authorize_url"` // 自定义OAuth授权URL
AccessTokenURL *string `json:"access_token_url"` // 自定义OAuth访问令牌URL
UserInfoURL *string `json:"userinfo_url"` // 自定义OAuth用户信息URL
Scopes []string `json:"scopes"` // 自定义OAuth Scope列表
IDField *string `json:"id_field"` // 用户信息回包中的ID字段名
NameField *string `json:"name_field"` // 用户信息回包中的用户名字段名
AvatarField *string `json:"avatar_field"` // 用户信息回包中的头像URL字段名
EmailField *string `json:"email_field"` // 用户信息回包中的邮箱字段名
}
type CustomOAuth struct {
Enable bool `json:"enable"` // 自定义OAuth开关
ClientID string `json:"client_id"` // 自定义客户端ID
ClientSecret string `json:"client_secret"` // 自定义客户端密钥
AuthorizeURL string `json:"authorize_url"` // 自定义OAuth授权URL
AccessTokenURL string `json:"access_token_url"` // 自定义OAuth访问令牌URL
UserInfoURL string `json:"userinfo_url"` // 自定义OAuth用户信息URL
Scopes []string `json:"scopes"` // 自定义OAuth Scope列表
IDField string `json:"id_field"` // 用户信息回包中的ID字段名
NameField string `json:"name_field"` // 用户信息回包中的用户名字段名
AvatarField string `json:"avatar_field"` // 用户信息回包中的头像URL字段名
EmailField string `json:"email_field"` // 用户信息回包中的邮箱字段名
}
func (c *CustomOAuth) From(e *types.CustomOAuth) *CustomOAuth {
if e == nil {
c.Enable = false
return c
}
c.Enable = e.Enable
c.ClientID = e.ClientID
c.AuthorizeURL = e.AuthorizeURL
c.AccessTokenURL = e.AccessTokenURL
c.UserInfoURL = e.UserInfoURL
c.Scopes = e.Scopes
c.IDField = e.IDField
c.NameField = e.NameField
c.AvatarField = e.AvatarField
c.EmailField = e.EmailField
return c
}
type Setting struct {
EnableSSO bool `json:"enable_sso"` // 是否开启SSO
ForceTwoFactorAuth bool `json:"force_two_factor_auth"` // 是否强制两步验证
DisablePasswordLogin bool `json:"disable_password_login"` // 是否禁用密码登录
EnableDingtalkOAuth bool `json:"enable_dingtalk_oauth"` // 是否开启钉钉OAuth
CreatedAt int64 `json:"created_at"` // 创建时间
UpdatedAt int64 `json:"updated_at"` // 更新时间
EnableSSO bool `json:"enable_sso"` // 是否开启SSO
ForceTwoFactorAuth bool `json:"force_two_factor_auth"` // 是否强制两步验证
DisablePasswordLogin bool `json:"disable_password_login"` // 是否禁用密码登录
DingtalkOAuth DingtalkOAuth `json:"dingtalk_oauth"` // 钉钉OAuth接入
CustomOAuth CustomOAuth `json:"custom_oauth"` // 自定义OAuth接入
CreatedAt int64 `json:"created_at"` // 创建时间
UpdatedAt int64 `json:"updated_at"` // 更新时间
}
func (s *Setting) From(e *db.Setting) *Setting {
@@ -274,7 +348,8 @@ func (s *Setting) From(e *db.Setting) *Setting {
s.EnableSSO = e.EnableSSO
s.ForceTwoFactorAuth = e.ForceTwoFactorAuth
s.DisablePasswordLogin = e.DisablePasswordLogin
s.EnableDingtalkOAuth = e.EnableDingtalkOauth
s.DingtalkOAuth = *cvt.From(e.DingtalkOauth, &DingtalkOAuth{})
s.CustomOAuth = *cvt.From(e.CustomOauth, &CustomOAuth{})
s.CreatedAt = e.CreatedAt.Unix()
s.UpdatedAt = e.UpdatedAt.Unix()

View File

@@ -9,6 +9,8 @@ import (
"entgo.io/ent/schema/field"
"github.com/google/uuid"
"github.com/chaitin/MonkeyCode/backend/ent/types"
)
// Setting holds the schema definition for the Setting entity.
@@ -31,9 +33,8 @@ func (Setting) Fields() []ent.Field {
field.Bool("enable_sso").Default(false),
field.Bool("force_two_factor_auth").Default(false),
field.Bool("disable_password_login").Default(false),
field.Bool("enable_dingtalk_oauth").Default(false),
field.String("dingtalk_client_id").Optional(),
field.String("dingtalk_client_secret").Optional(),
field.JSON("dingtalk_oauth", &types.DingtalkOAuth{}).Optional(),
field.JSON("custom_oauth", &types.CustomOAuth{}).Optional(),
field.Time("created_at").Default(time.Now),
field.Time("updated_at").Default(time.Now).UpdateDefault(time.Now),
}

View File

@@ -0,0 +1,21 @@
package types
type DingtalkOAuth struct {
Enable bool `json:"enable"` // 钉钉OAuth开关
ClientID string `json:"client_id"` // 钉钉客户端ID
ClientSecret string `json:"client_secret"` // 钉钉客户端密钥
}
type CustomOAuth struct {
Enable bool `json:"enable"` // 自定义OAuth开关
ClientID string `json:"client_id"` // 自定义客户端ID
ClientSecret string `json:"client_secret"` // 自定义客户端密钥
AuthorizeURL string `json:"authorize_url"` // 自定义OAuth授权URL
AccessTokenURL string `json:"access_token_url"` // 自定义OAuth访问令牌URL
UserInfoURL string `json:"userinfo_url"` // 自定义OAuth用户信息URL
Scopes []string `json:"scopes"` // 自定义OAuth Scope列表
IDField string `json:"id_field"` // 用户信息回包中的ID字段名
NameField string `json:"name_field"` // 用户信息回包中的用户名字段名`
AvatarField string `json:"avatar_field"` // 用户信息回包中的头像URL字段名`
EmailField string `json:"email_field"` // 用户信息回包中的邮箱字段名
}

View File

@@ -10,10 +10,14 @@ import (
var LocalFS embed.FS
var (
ErrPermission = web.NewBadRequestErr("err-permission")
ErrUserNotFound = web.NewBadRequestErr("err-user-not-found")
ErrPassword = web.NewBadRequestErr("err-password")
ErrInviteCodeInvalid = web.NewBadRequestErr("err-invite-code-invalid")
ErrEmailInvalid = web.NewBadRequestErr("err-email-invalid")
ErrOAuthStateInvalid = web.NewBadRequestErr("err-oauth-state-invalid")
ErrPermission = web.NewBadRequestErr("err-permission")
ErrUserNotFound = web.NewBadRequestErr("err-user-not-found")
ErrPassword = web.NewBadRequestErr("err-password")
ErrInviteCodeInvalid = web.NewBadRequestErr("err-invite-code-invalid")
ErrEmailInvalid = web.NewBadRequestErr("err-email-invalid")
ErrOAuthStateInvalid = web.NewBadRequestErr("err-oauth-state-invalid")
ErrUnsupportedPlatform = web.NewBadRequestErr("err-unsupported-platform")
ErrNotInvited = web.NewBadRequestErr("err-not-invited")
ErrDingtalkNotEnabled = web.NewBadRequestErr("err-dingtalk-not-enabled")
ErrCustomNotEnabled = web.NewBadRequestErr("err-custom-not-enabled")
)

View File

@@ -14,4 +14,16 @@ other = "邀请码无效"
other = "邮箱格式错误"
[err-oauth-state-invalid]
other = "OAuth 状态无效"
other = "OAuth 状态无效"
[err-unsupported-platform]
other = "不支持的平台"
[err-not-invited]
other = "未被邀请"
[err-dingtalk-not-enabled]
other = "钉钉未启用"
[err-custom-not-enabled]
other = "OAuth未启用"

View File

@@ -58,6 +58,7 @@ func NewUserHandler(
admin.GET("/login-history", web.BaseHandler(u.AdminLoginHistory, web.WithPage()))
admin.DELETE("/delete", web.BaseHandler(u.DeleteAdmin))
// user
g := w.Group("/api/v1/user")
g.GET("/oauth/signup-or-in", web.BindHandler(u.OAuthSignUpOrIn))
g.GET("/oauth/callback", web.BindHandler(u.OAuthCallback))
@@ -165,7 +166,7 @@ func (h *UserHandler) Delete(c *web.Context) error {
// DeleteAdmin 删除管理员
//
// @Tags User
// @Tags Admin
// @Summary 删除管理员
// @Description 删除管理员
// @ID delete-admin
@@ -184,7 +185,7 @@ func (h *UserHandler) DeleteAdmin(c *web.Context) error {
// AdminLogin 管理员登录
//
// @Tags User
// @Tags Admin
// @Summary 管理员登录
// @Description 管理员登录
// @ID admin-login
@@ -285,7 +286,7 @@ func (h *UserHandler) Register(c *web.Context, req domain.RegisterReq) error {
// CreateAdmin 创建管理员
//
// @Tags User
// @Tags Admin
// @Summary 创建管理员
// @Description 创建管理员
// @ID create-admin
@@ -308,7 +309,7 @@ func (h *UserHandler) CreateAdmin(c *web.Context, req domain.CreateAdminReq) err
// AdminList 获取管理员用户列表
//
// @Tags User
// @Tags Admin
// @Summary 获取管理员用户列表
// @Description 获取管理员用户列表
// @ID list-admin-user
@@ -327,7 +328,7 @@ func (h *UserHandler) AdminList(c *web.Context) error {
// AdminLoginHistory 获取管理员登录历史
//
// @Tags User
// @Tags Admin
// @Summary 获取管理员登录历史
// @Description 获取管理员登录历史
// @ID admin-login-history
@@ -346,7 +347,7 @@ func (h *UserHandler) AdminLoginHistory(c *web.Context) error {
// GetSetting 获取系统设置
//
// @Tags User
// @Tags Admin
// @Summary 获取系统设置
// @Description 获取系统设置
// @ID get-setting
@@ -364,7 +365,7 @@ func (h *UserHandler) GetSetting(c *web.Context) error {
// UpdateSetting 更新系统设置
//
// @Tags User
// @Tags Admin
// @Summary 更新系统设置
// @Description 更新系统设置
// @ID update-setting

View File

@@ -3,6 +3,7 @@ package repo
import (
"context"
"errors"
"fmt"
"time"
"github.com/google/uuid"
@@ -17,6 +18,7 @@ import (
"github.com/chaitin/MonkeyCode/backend/db/user"
"github.com/chaitin/MonkeyCode/backend/db/useridentity"
"github.com/chaitin/MonkeyCode/backend/domain"
"github.com/chaitin/MonkeyCode/backend/errcode"
"github.com/chaitin/MonkeyCode/backend/pkg/entx"
)
@@ -68,32 +70,40 @@ func (r *UserRepo) GetByName(ctx context.Context, username string) (*db.User, er
func (r *UserRepo) ValidateInviteCode(ctx context.Context, code string) (*db.InviteCode, error) {
var res *db.InviteCode
err := entx.WithTx(ctx, r.db, func(tx *db.Tx) error {
ic, err := tx.InviteCode.Query().Where(invitecode.Code(code)).Only(ctx)
ic, err := r.innerValidateInviteCode(ctx, tx, code)
if err != nil {
return err
}
if ic.ExpiredAt.Before(time.Now()) {
return errors.New("invite code has expired")
}
if ic.Status == consts.InviteCodeStatusUsed {
return errors.New("invite code has been used")
}
ic, err = tx.InviteCode.UpdateOneID(ic.ID).
SetStatus(consts.InviteCodeStatusUsed).
Save(ctx)
if err != nil {
return err
}
res = ic
return nil
})
return res, err
}
func (r *UserRepo) innerValidateInviteCode(ctx context.Context, tx *db.Tx, code string) (*db.InviteCode, error) {
ic, err := tx.InviteCode.Query().Where(invitecode.Code(code)).Only(ctx)
if err != nil {
return nil, err
}
if ic.ExpiredAt.Before(time.Now()) {
return nil, errors.New("invite code has expired")
}
if ic.Status == consts.InviteCodeStatusUsed {
return nil, errors.New("invite code has been used")
}
ic, err = tx.InviteCode.UpdateOneID(ic.ID).
SetStatus(consts.InviteCodeStatusUsed).
Save(ctx)
if err != nil {
return nil, err
}
return ic, nil
}
func (r *UserRepo) CreateUser(ctx context.Context, user *db.User) (*db.User, error) {
return r.db.User.Create().
SetUsername(user.Username).
@@ -184,18 +194,23 @@ func (r *UserRepo) GetSetting(ctx context.Context) (*db.Setting, error) {
return s, nil
}
func (r *UserRepo) UpdateSetting(ctx context.Context, fn func(*db.SettingUpdateOne)) (*db.Setting, error) {
var s *db.Setting
func (r *UserRepo) UpdateSetting(ctx context.Context, fn func(*db.Setting, *db.SettingUpdateOne)) (*db.Setting, error) {
var res *db.Setting
err := entx.WithTx(ctx, r.db, func(tx *db.Tx) error {
s, err := tx.Setting.Query().First(ctx)
if err != nil {
return err
}
up := tx.Setting.UpdateOneID(s.ID)
fn(up)
return up.Exec(ctx)
fn(s, up)
s, err = up.Save(ctx)
if err != nil {
return err
}
res = s
return nil
})
return s, err
return res, err
}
func (r *UserRepo) Update(ctx context.Context, id string, fn func(*db.UserUpdateOne) error) (*db.User, error) {
@@ -241,16 +256,19 @@ func (r *UserRepo) DeleteAdmin(ctx context.Context, id string) error {
return r.db.Admin.DeleteOne(admin).Exec(ctx)
}
func (r *UserRepo) SignUpOrIn(ctx context.Context, platform consts.UserPlatform, req *domain.OAuthUserInfo) (*db.User, error) {
func (r *UserRepo) OAuthRegister(ctx context.Context, platform consts.UserPlatform, inviteCode string, req *domain.OAuthUserInfo) (*db.User, error) {
var u *db.User
err := entx.WithTx(ctx, r.db, func(tx *db.Tx) error {
ui, err := tx.UserIdentity.Query().
if _, err := r.innerValidateInviteCode(ctx, tx, inviteCode); err != nil {
return errcode.ErrInviteCodeInvalid.Wrap(err)
}
_, err := tx.UserIdentity.Query().
WithUser().
Where(useridentity.Platform(platform), useridentity.IdentityID(req.ID)).
First(ctx)
if err == nil {
u = ui.Edges.User
return nil
return fmt.Errorf("user already exists for platform %s and identity ID %s", platform, req.ID)
}
if !db.IsNotFound(err) {
return err
@@ -282,3 +300,15 @@ func (r *UserRepo) SignUpOrIn(ctx context.Context, platform consts.UserPlatform,
})
return u, err
}
func (r *UserRepo) OAuthLogin(ctx context.Context, platform consts.UserPlatform, req *domain.OAuthUserInfo) (*db.User, error) {
ui, err := r.db.UserIdentity.Query().
WithUser().
Where(useridentity.Platform(platform), useridentity.IdentityID(req.ID)).
Where(useridentity.HasUser()).
Only(ctx)
if err != nil {
return nil, errcode.ErrNotInvited.Wrap(err)
}
return ui.Edges.User, nil
}

View File

@@ -6,6 +6,7 @@ import (
"fmt"
"log/slog"
"net/url"
"strings"
"time"
"github.com/google/uuid"
@@ -14,6 +15,7 @@ import (
"github.com/GoYoko/web"
"github.com/chaitin/MonkeyCode/backend/consts"
"github.com/chaitin/MonkeyCode/backend/ent/types"
"github.com/chaitin/MonkeyCode/backend/pkg/cvt"
"github.com/chaitin/MonkeyCode/backend/pkg/oauth"
@@ -268,24 +270,65 @@ func (u *UserUsecase) GetSetting(ctx context.Context) (*domain.Setting, error) {
}
func (u *UserUsecase) UpdateSetting(ctx context.Context, req *domain.UpdateSettingReq) (*domain.Setting, error) {
s, err := u.repo.UpdateSetting(ctx, func(s *db.SettingUpdateOne) {
s, err := u.repo.UpdateSetting(ctx, func(old *db.Setting, up *db.SettingUpdateOne) {
if req.EnableSSO != nil {
s.SetEnableSSO(*req.EnableSSO)
up.SetEnableSSO(*req.EnableSSO)
}
if req.ForceTwoFactorAuth != nil {
s.SetForceTwoFactorAuth(*req.ForceTwoFactorAuth)
up.SetForceTwoFactorAuth(*req.ForceTwoFactorAuth)
}
if req.DisablePasswordLogin != nil {
s.SetDisablePasswordLogin(*req.DisablePasswordLogin)
up.SetDisablePasswordLogin(*req.DisablePasswordLogin)
}
if req.EnableDingtalkOAuth != nil {
s.SetEnableDingtalkOauth(*req.EnableDingtalkOAuth)
if req.DingtalkOAuth != nil {
dingtalk := cvt.NilWithDefault(old.DingtalkOauth, &types.DingtalkOAuth{})
if req.DingtalkOAuth.Enable != nil {
dingtalk.Enable = *req.DingtalkOAuth.Enable
}
if req.DingtalkOAuth.ClientID != nil {
dingtalk.ClientID = *req.DingtalkOAuth.ClientID
}
if req.DingtalkOAuth.ClientSecret != nil {
dingtalk.ClientSecret = *req.DingtalkOAuth.ClientSecret
}
up.SetDingtalkOauth(dingtalk)
}
if req.DingtalkClientID != nil {
s.SetDingtalkClientID(*req.DingtalkClientID)
}
if req.DingtalkClientSecret != nil {
s.SetDingtalkClientSecret(*req.DingtalkClientSecret)
if req.CustomOAuth != nil {
custom := cvt.NilWithDefault(old.CustomOauth, &types.CustomOAuth{})
if req.CustomOAuth.Enable != nil {
custom.Enable = *req.CustomOAuth.Enable
}
if req.CustomOAuth.ClientID != nil {
custom.ClientID = *req.CustomOAuth.ClientID
}
if req.CustomOAuth.ClientSecret != nil {
custom.ClientSecret = *req.CustomOAuth.ClientSecret
}
if req.CustomOAuth.AuthorizeURL != nil {
custom.AuthorizeURL = *req.CustomOAuth.AuthorizeURL
}
if req.CustomOAuth.AccessTokenURL != nil {
custom.AccessTokenURL = *req.CustomOAuth.AccessTokenURL
}
if req.CustomOAuth.UserInfoURL != nil {
custom.UserInfoURL = *req.CustomOAuth.UserInfoURL
}
if req.CustomOAuth.Scopes != nil {
custom.Scopes = req.CustomOAuth.Scopes
}
if req.CustomOAuth.IDField != nil {
custom.IDField = *req.CustomOAuth.IDField
}
if req.CustomOAuth.NameField != nil {
custom.NameField = *req.CustomOAuth.NameField
}
if req.CustomOAuth.AvatarField != nil {
custom.AvatarField = *req.CustomOAuth.AvatarField
}
if req.CustomOAuth.EmailField != nil {
custom.EmailField = *req.CustomOAuth.EmailField
}
up.SetCustomOauth(custom)
}
})
if err != nil {
@@ -335,8 +378,26 @@ func (u *UserUsecase) OAuthSignUpOrIn(ctx context.Context, req *domain.OAuthSign
switch req.Platform {
case consts.UserPlatformDingTalk:
cfg.ClientID = setting.DingtalkClientID
cfg.ClientSecret = setting.DingtalkClientSecret
if setting.DingtalkOauth == nil || !setting.DingtalkOauth.Enable {
return nil, errcode.ErrDingtalkNotEnabled
}
cfg.ClientID = setting.DingtalkOauth.ClientID
cfg.ClientSecret = setting.DingtalkOauth.ClientSecret
case consts.UserPlatformCustom:
if setting.CustomOauth == nil || !setting.CustomOauth.Enable {
return nil, errcode.ErrCustomNotEnabled
}
cfg.ClientID = setting.CustomOauth.ClientID
cfg.ClientSecret = setting.CustomOauth.ClientSecret
cfg.AuthorizeURL = setting.CustomOauth.AuthorizeURL
cfg.Scope = strings.Join(setting.CustomOauth.Scopes, " ")
cfg.TokenURL = setting.CustomOauth.AccessTokenURL
cfg.UserInfoURL = setting.CustomOauth.UserInfoURL
cfg.IDField = setting.CustomOauth.IDField
cfg.NameField = setting.CustomOauth.NameField
cfg.AvatarField = setting.CustomOauth.AvatarField
default:
return nil, errcode.ErrUnsupportedPlatform
}
oauth, err := oauth.NewOAuther(cfg)
@@ -347,9 +408,10 @@ func (u *UserUsecase) OAuthSignUpOrIn(ctx context.Context, req *domain.OAuthSign
session := &domain.OAuthState{
SessionID: req.SessionID,
Kind: consts.OAuthKindSignUpOrIn,
Kind: req.OAuthKind(),
Platform: req.Platform,
RedirectURL: req.RedirectURL,
InviteCode: req.InviteCode,
}
b, err := json.Marshal(session)
if err != nil {
@@ -375,38 +437,74 @@ func (u *UserUsecase) OAuthCallback(ctx context.Context, req *domain.OAuthCallba
}
switch session.Kind {
case consts.OAuthKindSignUpOrIn:
return u.OAuthSignUpOrInCallback(ctx, req, &session)
case consts.OAuthKindInvite:
return u.WithOAuthCallback(ctx, req, &session, func(ctx context.Context, s *domain.OAuthState, oui *domain.OAuthUserInfo) (*db.User, error) {
return u.repo.OAuthRegister(ctx, s.Platform, s.InviteCode, oui)
})
case consts.OAuthKindLogin:
return u.WithOAuthCallback(ctx, req, &session, func(ctx context.Context, s *domain.OAuthState, oui *domain.OAuthUserInfo) (*db.User, error) {
return u.repo.OAuthLogin(ctx, s.Platform, oui)
})
default:
return "", errcode.ErrOAuthStateInvalid
}
}
func (u *UserUsecase) OAuthSignUpOrInCallback(ctx context.Context, req *domain.OAuthCallbackReq, session *domain.OAuthState) (string, error) {
func (u *UserUsecase) FetchUserInfo(ctx context.Context, req *domain.OAuthCallbackReq, session *domain.OAuthState) (*domain.OAuthUserInfo, error) {
setting, err := u.repo.GetSetting(ctx)
if err != nil {
return "", err
return nil, err
}
cfg := domain.OAuthConfig{
Debug: u.cfg.Debug,
Platform: session.Platform,
}
switch session.Platform {
case consts.UserPlatformDingTalk:
cfg.ClientID = setting.DingtalkClientID
cfg.ClientSecret = setting.DingtalkClientSecret
if setting.DingtalkOauth == nil || !setting.DingtalkOauth.Enable {
return nil, errcode.ErrDingtalkNotEnabled
}
cfg.ClientID = setting.DingtalkOauth.ClientID
cfg.ClientSecret = setting.DingtalkOauth.ClientSecret
case consts.UserPlatformCustom:
if setting.CustomOauth == nil || !setting.CustomOauth.Enable {
return nil, errcode.ErrCustomNotEnabled
}
cfg.ClientID = setting.CustomOauth.ClientID
cfg.ClientSecret = setting.CustomOauth.ClientSecret
cfg.AuthorizeURL = setting.CustomOauth.AuthorizeURL
cfg.Scope = strings.Join(setting.CustomOauth.Scopes, " ")
cfg.TokenURL = setting.CustomOauth.AccessTokenURL
cfg.UserInfoURL = setting.CustomOauth.UserInfoURL
cfg.IDField = setting.CustomOauth.IDField
cfg.NameField = setting.CustomOauth.NameField
cfg.AvatarField = setting.CustomOauth.AvatarField
default:
return nil, errcode.ErrUnsupportedPlatform
}
oauth, err := oauth.NewOAuther(cfg)
if err != nil {
return "", err
return nil, err
}
userInfo, err := oauth.GetUserInfo(req.Code)
if err != nil {
return nil, err
}
return userInfo, nil
}
type OAuthUserRepoHandle func(context.Context, *domain.OAuthState, *domain.OAuthUserInfo) (*db.User, error)
func (u *UserUsecase) WithOAuthCallback(ctx context.Context, req *domain.OAuthCallbackReq, session *domain.OAuthState, handle OAuthUserRepoHandle) (string, error) {
info, err := u.FetchUserInfo(ctx, req, session)
if err != nil {
return "", err
}
user, err := u.repo.SignUpOrIn(ctx, session.Platform, userInfo)
user, err := handle(ctx, session, info)
if err != nil {
return "", err
}

View File

@@ -0,0 +1,6 @@
ALTER TABLE settings DROP COLUMN IF EXISTS enable_dingtalk_oauth;
ALTER TABLE settings DROP COLUMN IF EXISTS dingtalk_client_id;
ALTER TABLE settings DROP COLUMN IF EXISTS dingtalk_client_secret;
ALTER TABLE settings ADD COLUMN dingtalk_oauth JSONB DEFAULT '{}'::JSONB;
ALTER TABLE settings ADD COLUMN custom_oauth JSONB DEFAULT '{}'::JSONB;

View File

@@ -0,0 +1,96 @@
package oauth
import (
"fmt"
"net/url"
"strings"
"time"
"github.com/google/uuid"
"github.com/chaitin/MonkeyCode/backend/domain"
"github.com/chaitin/MonkeyCode/backend/pkg/request"
)
type CustomOAuth struct {
cfg domain.OAuthConfig
}
func NewCustomOAuth(config domain.OAuthConfig) domain.OAuther {
c := &CustomOAuth{
cfg: config,
}
return c
}
// GetAuthorizeURL implements domain.OAuther.
func (c *CustomOAuth) GetAuthorizeURL() (string, string) {
state := uuid.NewString()
url := fmt.Sprintf("%s?response_type=code&client_id=%s&state=%s&redirect_uri=%s", c.cfg.AuthorizeURL, c.cfg.ClientID, state, c.cfg.RedirectURI)
return state, url
}
// GetUserInfo implements domain.OAuther.
func (c *CustomOAuth) GetUserInfo(code string) (*domain.OAuthUserInfo, error) {
accessToken, err := c.getAccessToken(code)
if err != nil {
return nil, err
}
info, err := c.getUserInfo(accessToken)
if err != nil {
return nil, err
}
return &domain.OAuthUserInfo{
ID: fmt.Sprint(info[c.cfg.IDField]),
AvatarURL: fmt.Sprint(info[c.cfg.AvatarField]),
Name: fmt.Sprint(info[c.cfg.NameField]),
}, nil
}
func (c *CustomOAuth) getAccessToken(code string) (string, error) {
u, err := url.Parse(c.cfg.TokenURL)
if err != nil {
return "", fmt.Errorf("[CustomOAuth] 无效的Token URL: %w", err)
}
client := request.NewClient(u.Scheme, u.Host, 30*time.Second)
client.SetDebug(c.cfg.Debug)
req := domain.GetAccessTokenReq{
GrantType: "authorization_code",
Code: code,
RedirectURL: c.cfg.RedirectURI,
ClientID: c.cfg.ClientID,
ClientSecret: c.cfg.ClientSecret,
}
resp, err := request.Post[domain.OAuthAccessToken](client, u.Path, req, request.WithHeader(request.Header{
"Accept": "application/json",
}))
if err != nil {
return "", fmt.Errorf("[CustomOAuth] 获取access token失败: %w", err)
}
return resp.AccessToken, nil
}
type UserInfo map[string]any
func (c *CustomOAuth) getUserInfo(accessToken string) (UserInfo, error) {
u, err := url.Parse(c.cfg.UserInfoURL)
if err != nil {
return nil, fmt.Errorf("[CustomOAuth] 无效的UseInfo URL: %w", err)
}
client := request.NewClient(u.Scheme, u.Host, 30*time.Second)
client.SetDebug(c.cfg.Debug)
h := request.Header{
"Authorization": fmt.Sprintf("Bearer %s", accessToken),
}
if strings.Contains(c.cfg.UserInfoURL, "github") {
h["Accept"] = "application/vnd.github.v3+json"
}
resp, err := request.Get[UserInfo](client, u.Path, request.WithHeader(h))
if err != nil {
return nil, fmt.Errorf("[CustomOAuth] 获取用户信息失败: %w", err)
}
return *resp, nil
}

View File

@@ -11,6 +11,8 @@ func NewOAuther(config domain.OAuthConfig) (domain.OAuther, error) {
switch config.Platform {
case consts.UserPlatformDingTalk:
return NewDingTalk(config), nil
case consts.UserPlatformCustom:
return NewCustomOAuth(config), nil
default:
return nil, fmt.Errorf("unsupported platform: %s", config.Platform)
}