feat: 支持配置前置代理

This commit is contained in:
yokowu
2025-07-31 14:36:19 +08:00
parent a8f6b63bc9
commit d64eb48a59
21 changed files with 409 additions and 26 deletions

View File

@@ -24,7 +24,7 @@ import (
"github.com/chaitin/MonkeyCode/backend/internal/middleware"
v1_2 "github.com/chaitin/MonkeyCode/backend/internal/model/handler/http/v1"
repo2 "github.com/chaitin/MonkeyCode/backend/internal/model/repo"
usecase3 "github.com/chaitin/MonkeyCode/backend/internal/model/usecase"
usecase4 "github.com/chaitin/MonkeyCode/backend/internal/model/usecase"
"github.com/chaitin/MonkeyCode/backend/internal/openai/handler/v1"
repo3 "github.com/chaitin/MonkeyCode/backend/internal/openai/repo"
"github.com/chaitin/MonkeyCode/backend/internal/openai/usecase"
@@ -36,7 +36,7 @@ import (
"github.com/chaitin/MonkeyCode/backend/internal/socket/handler"
v1_3 "github.com/chaitin/MonkeyCode/backend/internal/user/handler/v1"
repo5 "github.com/chaitin/MonkeyCode/backend/internal/user/repo"
usecase4 "github.com/chaitin/MonkeyCode/backend/internal/user/usecase"
usecase3 "github.com/chaitin/MonkeyCode/backend/internal/user/usecase"
repo8 "github.com/chaitin/MonkeyCode/backend/internal/workspace/repo"
usecase7 "github.com/chaitin/MonkeyCode/backend/internal/workspace/usecase"
"github.com/chaitin/MonkeyCode/backend/pkg"
@@ -72,20 +72,20 @@ func newServer() (*Server, error) {
openAIUsecase := openai.NewOpenAIUsecase(configConfig, openAIRepo, modelRepo, slogLogger)
extensionRepo := repo4.NewExtensionRepo(client)
extensionUsecase := usecase2.NewExtensionUsecase(extensionRepo, configConfig, slogLogger)
proxyMiddleware := middleware.NewProxyMiddleware(proxyUsecase)
activeMiddleware := middleware.NewActiveMiddleware(redisClient, slogLogger)
v1Handler := v1.NewV1Handler(slogLogger, web, llmProxy, proxyUsecase, openAIUsecase, extensionUsecase, proxyMiddleware, activeMiddleware, configConfig)
modelUsecase := usecase3.NewModelUsecase(slogLogger, modelRepo, configConfig)
sessionSession := session.NewSession(configConfig)
authMiddleware := middleware.NewAuthMiddleware(sessionSession, slogLogger)
readOnlyMiddleware := middleware.NewReadOnlyMiddleware(configConfig)
modelHandler := v1_2.NewModelHandler(web, modelUsecase, authMiddleware, activeMiddleware, readOnlyMiddleware, slogLogger)
ipdbIPDB, err := ipdb.NewIPDB(slogLogger)
if err != nil {
return nil, err
}
userRepo := repo5.NewUserRepo(client, ipdbIPDB, redisClient, configConfig)
userUsecase := usecase4.NewUserUsecase(configConfig, redisClient, userRepo, slogLogger, sessionSession)
sessionSession := session.NewSession(configConfig)
userUsecase := usecase3.NewUserUsecase(configConfig, redisClient, userRepo, slogLogger, sessionSession)
proxyMiddleware := middleware.NewProxyMiddleware(proxyUsecase)
activeMiddleware := middleware.NewActiveMiddleware(redisClient, slogLogger)
v1Handler := v1.NewV1Handler(slogLogger, web, llmProxy, proxyUsecase, openAIUsecase, extensionUsecase, userUsecase, proxyMiddleware, activeMiddleware, configConfig)
modelUsecase := usecase4.NewModelUsecase(slogLogger, modelRepo, configConfig)
authMiddleware := middleware.NewAuthMiddleware(sessionSession, slogLogger)
readOnlyMiddleware := middleware.NewReadOnlyMiddleware(configConfig)
modelHandler := v1_2.NewModelHandler(web, modelUsecase, authMiddleware, activeMiddleware, readOnlyMiddleware, slogLogger)
dashboardRepo := repo6.NewDashboardRepo(client)
dashboardUsecase := usecase5.NewDashboardUsecase(dashboardRepo)
billingRepo := repo7.NewBillingRepo(client)

View File

@@ -8,6 +8,7 @@ import (
"github.com/spf13/viper"
"github.com/chaitin/MonkeyCode/backend/domain"
"github.com/chaitin/MonkeyCode/backend/pkg/logger"
)
@@ -77,7 +78,7 @@ type Config struct {
} `mapstructure:"data_report"`
}
func (c *Config) GetBaseURL(req *http.Request) string {
func (c *Config) GetBaseURL(req *http.Request, settings *domain.Setting) string {
scheme := "http"
if req.TLS != nil {
scheme = "https"
@@ -85,6 +86,18 @@ func (c *Config) GetBaseURL(req *http.Request) string {
if proto := req.Header.Get("X-Forwarded-Proto"); proto != "" {
scheme = proto
}
if settings != nil && settings.BaseURL != "" {
baseurl := settings.BaseURL
if !strings.HasPrefix(baseurl, "http") {
baseurl = fmt.Sprintf("%s://%s", scheme, baseurl)
}
return strings.TrimSuffix(baseurl, "/")
}
if port := req.Header.Get("X-Forwarded-Port"); port != "" && port != "80" && port != "443" {
c.Server.Port = port
}
baseurl := fmt.Sprintf("%s://%s", scheme, req.Host)
if c.Server.Port != "" {
baseurl = fmt.Sprintf("%s:%s", baseurl, c.Server.Port)

View File

@@ -315,6 +315,7 @@ var (
{Name: "enable_auto_login", Type: field.TypeBool, Default: false},
{Name: "dingtalk_oauth", Type: field.TypeJSON, Nullable: true},
{Name: "custom_oauth", Type: field.TypeJSON, Nullable: true},
{Name: "base_url", Type: field.TypeString, Nullable: true},
{Name: "created_at", Type: field.TypeTime},
{Name: "updated_at", Type: field.TypeTime},
}

View File

@@ -10909,6 +10909,7 @@ type SettingMutation struct {
enable_auto_login *bool
dingtalk_oauth **types.DingtalkOAuth
custom_oauth **types.CustomOAuth
base_url *string
created_at *time.Time
updated_at *time.Time
clearedFields map[string]struct{}
@@ -11263,6 +11264,55 @@ func (m *SettingMutation) ResetCustomOauth() {
delete(m.clearedFields, setting.FieldCustomOauth)
}
// SetBaseURL sets the "base_url" field.
func (m *SettingMutation) SetBaseURL(s string) {
m.base_url = &s
}
// BaseURL returns the value of the "base_url" field in the mutation.
func (m *SettingMutation) BaseURL() (r string, exists bool) {
v := m.base_url
if v == nil {
return
}
return *v, true
}
// OldBaseURL returns the old "base_url" 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) OldBaseURL(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldBaseURL is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldBaseURL requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldBaseURL: %w", err)
}
return oldValue.BaseURL, nil
}
// ClearBaseURL clears the value of the "base_url" field.
func (m *SettingMutation) ClearBaseURL() {
m.base_url = nil
m.clearedFields[setting.FieldBaseURL] = struct{}{}
}
// BaseURLCleared returns if the "base_url" field was cleared in this mutation.
func (m *SettingMutation) BaseURLCleared() bool {
_, ok := m.clearedFields[setting.FieldBaseURL]
return ok
}
// ResetBaseURL resets all changes to the "base_url" field.
func (m *SettingMutation) ResetBaseURL() {
m.base_url = nil
delete(m.clearedFields, setting.FieldBaseURL)
}
// SetCreatedAt sets the "created_at" field.
func (m *SettingMutation) SetCreatedAt(t time.Time) {
m.created_at = &t
@@ -11369,7 +11419,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, 9)
if m.enable_sso != nil {
fields = append(fields, setting.FieldEnableSSO)
}
@@ -11388,6 +11438,9 @@ func (m *SettingMutation) Fields() []string {
if m.custom_oauth != nil {
fields = append(fields, setting.FieldCustomOauth)
}
if m.base_url != nil {
fields = append(fields, setting.FieldBaseURL)
}
if m.created_at != nil {
fields = append(fields, setting.FieldCreatedAt)
}
@@ -11414,6 +11467,8 @@ func (m *SettingMutation) Field(name string) (ent.Value, bool) {
return m.DingtalkOauth()
case setting.FieldCustomOauth:
return m.CustomOauth()
case setting.FieldBaseURL:
return m.BaseURL()
case setting.FieldCreatedAt:
return m.CreatedAt()
case setting.FieldUpdatedAt:
@@ -11439,6 +11494,8 @@ func (m *SettingMutation) OldField(ctx context.Context, name string) (ent.Value,
return m.OldDingtalkOauth(ctx)
case setting.FieldCustomOauth:
return m.OldCustomOauth(ctx)
case setting.FieldBaseURL:
return m.OldBaseURL(ctx)
case setting.FieldCreatedAt:
return m.OldCreatedAt(ctx)
case setting.FieldUpdatedAt:
@@ -11494,6 +11551,13 @@ func (m *SettingMutation) SetField(name string, value ent.Value) error {
}
m.SetCustomOauth(v)
return nil
case setting.FieldBaseURL:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetBaseURL(v)
return nil
case setting.FieldCreatedAt:
v, ok := value.(time.Time)
if !ok {
@@ -11544,6 +11608,9 @@ func (m *SettingMutation) ClearedFields() []string {
if m.FieldCleared(setting.FieldCustomOauth) {
fields = append(fields, setting.FieldCustomOauth)
}
if m.FieldCleared(setting.FieldBaseURL) {
fields = append(fields, setting.FieldBaseURL)
}
return fields
}
@@ -11564,6 +11631,9 @@ func (m *SettingMutation) ClearField(name string) error {
case setting.FieldCustomOauth:
m.ClearCustomOauth()
return nil
case setting.FieldBaseURL:
m.ClearBaseURL()
return nil
}
return fmt.Errorf("unknown Setting nullable field %s", name)
}
@@ -11590,6 +11660,9 @@ func (m *SettingMutation) ResetField(name string) error {
case setting.FieldCustomOauth:
m.ResetCustomOauth()
return nil
case setting.FieldBaseURL:
m.ResetBaseURL()
return nil
case setting.FieldCreatedAt:
m.ResetCreatedAt()
return nil

View File

@@ -243,11 +243,11 @@ func init() {
// setting.DefaultEnableAutoLogin holds the default value on creation for the enable_auto_login field.
setting.DefaultEnableAutoLogin = settingDescEnableAutoLogin.Default.(bool)
// settingDescCreatedAt is the schema descriptor for created_at field.
settingDescCreatedAt := settingFields[7].Descriptor()
settingDescCreatedAt := settingFields[8].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[9].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

@@ -32,6 +32,8 @@ type Setting struct {
DingtalkOauth *types.DingtalkOAuth `json:"dingtalk_oauth,omitempty"`
// CustomOauth holds the value of the "custom_oauth" field.
CustomOauth *types.CustomOAuth `json:"custom_oauth,omitempty"`
// BaseURL holds the value of the "base_url" field.
BaseURL string `json:"base_url,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.
@@ -48,6 +50,8 @@ func (*Setting) scanValues(columns []string) ([]any, error) {
values[i] = new([]byte)
case setting.FieldEnableSSO, setting.FieldForceTwoFactorAuth, setting.FieldDisablePasswordLogin, setting.FieldEnableAutoLogin:
values[i] = new(sql.NullBool)
case setting.FieldBaseURL:
values[i] = new(sql.NullString)
case setting.FieldCreatedAt, setting.FieldUpdatedAt:
values[i] = new(sql.NullTime)
case setting.FieldID:
@@ -113,6 +117,12 @@ func (s *Setting) assignValues(columns []string, values []any) error {
return fmt.Errorf("unmarshal field custom_oauth: %w", err)
}
}
case setting.FieldBaseURL:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field base_url", values[i])
} else if value.Valid {
s.BaseURL = value.String
}
case setting.FieldCreatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field created_at", values[i])
@@ -179,6 +189,9 @@ func (s *Setting) String() string {
builder.WriteString("custom_oauth=")
builder.WriteString(fmt.Sprintf("%v", s.CustomOauth))
builder.WriteString(", ")
builder.WriteString("base_url=")
builder.WriteString(s.BaseURL)
builder.WriteString(", ")
builder.WriteString("created_at=")
builder.WriteString(s.CreatedAt.Format(time.ANSIC))
builder.WriteString(", ")

View File

@@ -25,6 +25,8 @@ const (
FieldDingtalkOauth = "dingtalk_oauth"
// FieldCustomOauth holds the string denoting the custom_oauth field in the database.
FieldCustomOauth = "custom_oauth"
// FieldBaseURL holds the string denoting the base_url field in the database.
FieldBaseURL = "base_url"
// 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.
@@ -42,6 +44,7 @@ var Columns = []string{
FieldEnableAutoLogin,
FieldDingtalkOauth,
FieldCustomOauth,
FieldBaseURL,
FieldCreatedAt,
FieldUpdatedAt,
}
@@ -101,6 +104,11 @@ func ByEnableAutoLogin(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldEnableAutoLogin, opts...).ToFunc()
}
// ByBaseURL orders the results by the base_url field.
func ByBaseURL(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldBaseURL, 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

@@ -75,6 +75,11 @@ func EnableAutoLogin(v bool) predicate.Setting {
return predicate.Setting(sql.FieldEQ(FieldEnableAutoLogin, v))
}
// BaseURL applies equality check predicate on the "base_url" field. It's identical to BaseURLEQ.
func BaseURL(v string) predicate.Setting {
return predicate.Setting(sql.FieldEQ(FieldBaseURL, 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))
@@ -145,6 +150,81 @@ func CustomOauthNotNil() predicate.Setting {
return predicate.Setting(sql.FieldNotNull(FieldCustomOauth))
}
// BaseURLEQ applies the EQ predicate on the "base_url" field.
func BaseURLEQ(v string) predicate.Setting {
return predicate.Setting(sql.FieldEQ(FieldBaseURL, v))
}
// BaseURLNEQ applies the NEQ predicate on the "base_url" field.
func BaseURLNEQ(v string) predicate.Setting {
return predicate.Setting(sql.FieldNEQ(FieldBaseURL, v))
}
// BaseURLIn applies the In predicate on the "base_url" field.
func BaseURLIn(vs ...string) predicate.Setting {
return predicate.Setting(sql.FieldIn(FieldBaseURL, vs...))
}
// BaseURLNotIn applies the NotIn predicate on the "base_url" field.
func BaseURLNotIn(vs ...string) predicate.Setting {
return predicate.Setting(sql.FieldNotIn(FieldBaseURL, vs...))
}
// BaseURLGT applies the GT predicate on the "base_url" field.
func BaseURLGT(v string) predicate.Setting {
return predicate.Setting(sql.FieldGT(FieldBaseURL, v))
}
// BaseURLGTE applies the GTE predicate on the "base_url" field.
func BaseURLGTE(v string) predicate.Setting {
return predicate.Setting(sql.FieldGTE(FieldBaseURL, v))
}
// BaseURLLT applies the LT predicate on the "base_url" field.
func BaseURLLT(v string) predicate.Setting {
return predicate.Setting(sql.FieldLT(FieldBaseURL, v))
}
// BaseURLLTE applies the LTE predicate on the "base_url" field.
func BaseURLLTE(v string) predicate.Setting {
return predicate.Setting(sql.FieldLTE(FieldBaseURL, v))
}
// BaseURLContains applies the Contains predicate on the "base_url" field.
func BaseURLContains(v string) predicate.Setting {
return predicate.Setting(sql.FieldContains(FieldBaseURL, v))
}
// BaseURLHasPrefix applies the HasPrefix predicate on the "base_url" field.
func BaseURLHasPrefix(v string) predicate.Setting {
return predicate.Setting(sql.FieldHasPrefix(FieldBaseURL, v))
}
// BaseURLHasSuffix applies the HasSuffix predicate on the "base_url" field.
func BaseURLHasSuffix(v string) predicate.Setting {
return predicate.Setting(sql.FieldHasSuffix(FieldBaseURL, v))
}
// BaseURLIsNil applies the IsNil predicate on the "base_url" field.
func BaseURLIsNil() predicate.Setting {
return predicate.Setting(sql.FieldIsNull(FieldBaseURL))
}
// BaseURLNotNil applies the NotNil predicate on the "base_url" field.
func BaseURLNotNil() predicate.Setting {
return predicate.Setting(sql.FieldNotNull(FieldBaseURL))
}
// BaseURLEqualFold applies the EqualFold predicate on the "base_url" field.
func BaseURLEqualFold(v string) predicate.Setting {
return predicate.Setting(sql.FieldEqualFold(FieldBaseURL, v))
}
// BaseURLContainsFold applies the ContainsFold predicate on the "base_url" field.
func BaseURLContainsFold(v string) predicate.Setting {
return predicate.Setting(sql.FieldContainsFold(FieldBaseURL, v))
}
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
func CreatedAtEQ(v time.Time) predicate.Setting {
return predicate.Setting(sql.FieldEQ(FieldCreatedAt, v))

View File

@@ -93,6 +93,20 @@ func (sc *SettingCreate) SetCustomOauth(to *types.CustomOAuth) *SettingCreate {
return sc
}
// SetBaseURL sets the "base_url" field.
func (sc *SettingCreate) SetBaseURL(s string) *SettingCreate {
sc.mutation.SetBaseURL(s)
return sc
}
// SetNillableBaseURL sets the "base_url" field if the given value is not nil.
func (sc *SettingCreate) SetNillableBaseURL(s *string) *SettingCreate {
if s != nil {
sc.SetBaseURL(*s)
}
return sc
}
// SetCreatedAt sets the "created_at" field.
func (sc *SettingCreate) SetCreatedAt(t time.Time) *SettingCreate {
sc.mutation.SetCreatedAt(t)
@@ -268,6 +282,10 @@ func (sc *SettingCreate) createSpec() (*Setting, *sqlgraph.CreateSpec) {
_spec.SetField(setting.FieldCustomOauth, field.TypeJSON, value)
_node.CustomOauth = value
}
if value, ok := sc.mutation.BaseURL(); ok {
_spec.SetField(setting.FieldBaseURL, field.TypeString, value)
_node.BaseURL = value
}
if value, ok := sc.mutation.CreatedAt(); ok {
_spec.SetField(setting.FieldCreatedAt, field.TypeTime, value)
_node.CreatedAt = value
@@ -412,6 +430,24 @@ func (u *SettingUpsert) ClearCustomOauth() *SettingUpsert {
return u
}
// SetBaseURL sets the "base_url" field.
func (u *SettingUpsert) SetBaseURL(v string) *SettingUpsert {
u.Set(setting.FieldBaseURL, v)
return u
}
// UpdateBaseURL sets the "base_url" field to the value that was provided on create.
func (u *SettingUpsert) UpdateBaseURL() *SettingUpsert {
u.SetExcluded(setting.FieldBaseURL)
return u
}
// ClearBaseURL clears the value of the "base_url" field.
func (u *SettingUpsert) ClearBaseURL() *SettingUpsert {
u.SetNull(setting.FieldBaseURL)
return u
}
// SetCreatedAt sets the "created_at" field.
func (u *SettingUpsert) SetCreatedAt(v time.Time) *SettingUpsert {
u.Set(setting.FieldCreatedAt, v)
@@ -582,6 +618,27 @@ func (u *SettingUpsertOne) ClearCustomOauth() *SettingUpsertOne {
})
}
// SetBaseURL sets the "base_url" field.
func (u *SettingUpsertOne) SetBaseURL(v string) *SettingUpsertOne {
return u.Update(func(s *SettingUpsert) {
s.SetBaseURL(v)
})
}
// UpdateBaseURL sets the "base_url" field to the value that was provided on create.
func (u *SettingUpsertOne) UpdateBaseURL() *SettingUpsertOne {
return u.Update(func(s *SettingUpsert) {
s.UpdateBaseURL()
})
}
// ClearBaseURL clears the value of the "base_url" field.
func (u *SettingUpsertOne) ClearBaseURL() *SettingUpsertOne {
return u.Update(func(s *SettingUpsert) {
s.ClearBaseURL()
})
}
// SetCreatedAt sets the "created_at" field.
func (u *SettingUpsertOne) SetCreatedAt(v time.Time) *SettingUpsertOne {
return u.Update(func(s *SettingUpsert) {
@@ -923,6 +980,27 @@ func (u *SettingUpsertBulk) ClearCustomOauth() *SettingUpsertBulk {
})
}
// SetBaseURL sets the "base_url" field.
func (u *SettingUpsertBulk) SetBaseURL(v string) *SettingUpsertBulk {
return u.Update(func(s *SettingUpsert) {
s.SetBaseURL(v)
})
}
// UpdateBaseURL sets the "base_url" field to the value that was provided on create.
func (u *SettingUpsertBulk) UpdateBaseURL() *SettingUpsertBulk {
return u.Update(func(s *SettingUpsert) {
s.UpdateBaseURL()
})
}
// ClearBaseURL clears the value of the "base_url" field.
func (u *SettingUpsertBulk) ClearBaseURL() *SettingUpsertBulk {
return u.Update(func(s *SettingUpsert) {
s.ClearBaseURL()
})
}
// SetCreatedAt sets the "created_at" field.
func (u *SettingUpsertBulk) SetCreatedAt(v time.Time) *SettingUpsertBulk {
return u.Update(func(s *SettingUpsert) {

View File

@@ -110,6 +110,26 @@ func (su *SettingUpdate) ClearCustomOauth() *SettingUpdate {
return su
}
// SetBaseURL sets the "base_url" field.
func (su *SettingUpdate) SetBaseURL(s string) *SettingUpdate {
su.mutation.SetBaseURL(s)
return su
}
// SetNillableBaseURL sets the "base_url" field if the given value is not nil.
func (su *SettingUpdate) SetNillableBaseURL(s *string) *SettingUpdate {
if s != nil {
su.SetBaseURL(*s)
}
return su
}
// ClearBaseURL clears the value of the "base_url" field.
func (su *SettingUpdate) ClearBaseURL() *SettingUpdate {
su.mutation.ClearBaseURL()
return su
}
// SetCreatedAt sets the "created_at" field.
func (su *SettingUpdate) SetCreatedAt(t time.Time) *SettingUpdate {
su.mutation.SetCreatedAt(t)
@@ -210,6 +230,12 @@ func (su *SettingUpdate) sqlSave(ctx context.Context) (n int, err error) {
if su.mutation.CustomOauthCleared() {
_spec.ClearField(setting.FieldCustomOauth, field.TypeJSON)
}
if value, ok := su.mutation.BaseURL(); ok {
_spec.SetField(setting.FieldBaseURL, field.TypeString, value)
}
if su.mutation.BaseURLCleared() {
_spec.ClearField(setting.FieldBaseURL, field.TypeString)
}
if value, ok := su.mutation.CreatedAt(); ok {
_spec.SetField(setting.FieldCreatedAt, field.TypeTime, value)
}
@@ -318,6 +344,26 @@ func (suo *SettingUpdateOne) ClearCustomOauth() *SettingUpdateOne {
return suo
}
// SetBaseURL sets the "base_url" field.
func (suo *SettingUpdateOne) SetBaseURL(s string) *SettingUpdateOne {
suo.mutation.SetBaseURL(s)
return suo
}
// SetNillableBaseURL sets the "base_url" field if the given value is not nil.
func (suo *SettingUpdateOne) SetNillableBaseURL(s *string) *SettingUpdateOne {
if s != nil {
suo.SetBaseURL(*s)
}
return suo
}
// ClearBaseURL clears the value of the "base_url" field.
func (suo *SettingUpdateOne) ClearBaseURL() *SettingUpdateOne {
suo.mutation.ClearBaseURL()
return suo
}
// SetCreatedAt sets the "created_at" field.
func (suo *SettingUpdateOne) SetCreatedAt(t time.Time) *SettingUpdateOne {
suo.mutation.SetCreatedAt(t)
@@ -448,6 +494,12 @@ func (suo *SettingUpdateOne) sqlSave(ctx context.Context) (_node *Setting, err e
if suo.mutation.CustomOauthCleared() {
_spec.ClearField(setting.FieldCustomOauth, field.TypeJSON)
}
if value, ok := suo.mutation.BaseURL(); ok {
_spec.SetField(setting.FieldBaseURL, field.TypeString, value)
}
if suo.mutation.BaseURLCleared() {
_spec.ClearField(setting.FieldBaseURL, field.TypeString)
}
if value, ok := suo.mutation.CreatedAt(); ok {
_spec.SetField(setting.FieldCreatedAt, field.TypeTime, value)
}

View File

@@ -402,7 +402,7 @@
}
},
"put": {
"description": "更新系统设置",
"description": "更新为增量更新,只传需要更新的字段",
"consumes": [
"application/json"
],
@@ -4948,6 +4948,10 @@
"domain.Setting": {
"type": "object",
"properties": {
"base_url": {
"description": "base url 配置,为了支持前置代理",
"type": "string"
},
"created_at": {
"description": "创建时间",
"type": "integer"
@@ -5259,6 +5263,10 @@
"domain.UpdateSettingReq": {
"type": "object",
"properties": {
"base_url": {
"description": "base url 配置,为了支持前置代理",
"type": "string"
},
"custom_oauth": {
"description": "自定义OAuth配置",
"allOf": [

View File

@@ -293,6 +293,7 @@ type UpdateSettingReq struct {
EnableAutoLogin *bool `json:"enable_auto_login"` // 是否开启自动登录
DingtalkOAuth *DingtalkOAuthReq `json:"dingtalk_oauth"` // 钉钉OAuth配置
CustomOAuth *CustomOAuthReq `json:"custom_oauth"` // 自定义OAuth配置
BaseURL *string `json:"base_url"` // base url 配置,为了支持前置代理
}
type DingtalkOAuthReq struct {
@@ -372,6 +373,7 @@ type Setting struct {
EnableAutoLogin bool `json:"enable_auto_login"` // 是否开启自动登录
DingtalkOAuth DingtalkOAuth `json:"dingtalk_oauth"` // 钉钉OAuth接入
CustomOAuth CustomOAuth `json:"custom_oauth"` // 自定义OAuth接入
BaseURL string `json:"base_url,omitempty"` // base url 配置,为了支持前置代理
CreatedAt int64 `json:"created_at"` // 创建时间
UpdatedAt int64 `json:"updated_at"` // 更新时间
}
@@ -387,6 +389,7 @@ func (s *Setting) From(e *db.Setting) *Setting {
s.EnableAutoLogin = e.EnableAutoLogin
s.DingtalkOAuth = *cvt.From(e.DingtalkOauth, &DingtalkOAuth{})
s.CustomOAuth = *cvt.From(e.CustomOauth, &CustomOAuth{})
s.BaseURL = e.BaseURL
s.CreatedAt = e.CreatedAt.Unix()
s.UpdatedAt = e.UpdatedAt.Unix()

View File

@@ -36,6 +36,7 @@ func (Setting) Fields() []ent.Field {
field.Bool("enable_auto_login").Default(false),
field.JSON("dingtalk_oauth", &types.DingtalkOAuth{}).Optional(),
field.JSON("custom_oauth", &types.CustomOAuth{}).Optional(),
field.String("base_url").Optional(),
field.Time("created_at").Default(time.Now),
field.Time("updated_at").Default(time.Now).UpdateDefault(time.Now),
}

View File

@@ -6,6 +6,11 @@ type DingtalkOAuth struct {
ClientSecret string `json:"client_secret"` // 钉钉客户端密钥
}
type BaseURL struct {
Host string `json:"host"`
Port string `json:"port"`
}
type CustomOAuth struct {
Enable bool `json:"enable"` // 自定义OAuth开关
ClientID string `json:"client_id"` // 自定义客户端ID

View File

@@ -21,6 +21,7 @@ type V1Handler struct {
proxyUse domain.ProxyUsecase
usecase domain.OpenAIUsecase
euse domain.ExtensionUsecase
uuse domain.UserUsecase
config *config.Config
}
@@ -31,6 +32,7 @@ func NewV1Handler(
proxyUse domain.ProxyUsecase,
usecase domain.OpenAIUsecase,
euse domain.ExtensionUsecase,
uuse domain.UserUsecase,
middleware *middleware.ProxyMiddleware,
active *middleware.ActiveMiddleware,
config *config.Config,
@@ -41,6 +43,7 @@ func NewV1Handler(
proxyUse: proxyUse,
usecase: usecase,
euse: euse,
uuse: uuse,
config: config,
}
@@ -73,9 +76,13 @@ func (h *V1Handler) Version(c *web.Context) error {
return err
}
s, err := h.uuse.GetSetting(c.Request().Context())
if err != nil {
return err
}
return c.JSON(http.StatusOK, domain.VersionInfo{
Version: v.Version,
URL: fmt.Sprintf("%s/api/v1/static/vsix/%s", h.config.GetBaseURL(c.Request()), v.Version),
URL: fmt.Sprintf("%s/api/v1/static/vsix/%s", h.config.GetBaseURL(c.Request(), s), v.Version),
})
}
@@ -182,8 +189,12 @@ func (h *V1Handler) Embeddings(c *web.Context) error {
func (h *V1Handler) GetConfig(c *web.Context, req domain.ConfigReq) error {
key := middleware.GetApiKey(c)
s, err := h.uuse.GetSetting(c.Request().Context())
if err != nil {
return err
}
req.Key = key.Key
req.BaseURL = h.config.GetBaseURL(c.Request())
req.BaseURL = h.config.GetBaseURL(c.Request(), s)
resp, err := h.usecase.GetConfig(c.Request().Context(), &req)
if err != nil {
return err

View File

@@ -127,7 +127,11 @@ func NewUserHandler(
}
func (h *UserHandler) VSCodeAuthInit(c *web.Context, req domain.VSCodeAuthInitReq) error {
req.BaseURL = h.cfg.GetBaseURL(c.Request())
s, err := h.usecase.GetSetting(c.Request().Context())
if err != nil {
return err
}
req.BaseURL = h.cfg.GetBaseURL(c.Request(), s)
resp, err := h.usecase.VSCodeAuthInit(c.Request().Context(), &req)
if err != nil {
return err
@@ -174,9 +178,14 @@ func (h *UserHandler) VSIXDownload(c *web.Context) error {
return err
}
s, err := h.usecase.GetSetting(c.Request().Context())
if err != nil {
return err
}
host := c.Request().Host
h.logger.With("url", c.Request().URL).With("header", c.Request().Header).With("host", host).DebugContext(c.Request().Context(), "vsix download")
cacheKey := h.generateCacheKey(v.Version, h.cfg.GetBaseURL(c.Request()))
cacheKey := h.generateCacheKey(v.Version, h.cfg.GetBaseURL(c.Request(), s))
h.cacheMu.RLock()
if entry, exists := h.vsixCache[cacheKey]; exists {
@@ -195,7 +204,7 @@ func (h *UserHandler) VSIXDownload(c *web.Context) error {
h.cacheMu.RUnlock()
var buf bytes.Buffer
if err := vsix.ChangeVsixEndpoint(v.Path, "extension/package.json", h.cfg.GetBaseURL(c.Request()), &buf); err != nil {
if err := vsix.ChangeVsixEndpoint(v.Path, "extension/package.json", h.cfg.GetBaseURL(c.Request(), s), &buf); err != nil {
return err
}
@@ -534,7 +543,7 @@ func (h *UserHandler) GetSetting(c *web.Context) error {
//
// @Tags Admin
// @Summary 更新系统设置
// @Description 更新系统设置
// @Description 更新为增量更新,只传需要更新的字段
// @ID update-setting
// @Accept json
// @Produce json
@@ -562,7 +571,11 @@ func (h *UserHandler) UpdateSetting(c *web.Context, req domain.UpdateSettingReq)
// @Router /api/v1/user/oauth/signup-or-in [get]
func (h *UserHandler) OAuthSignUpOrIn(ctx *web.Context, req domain.OAuthSignUpOrInReq) error {
h.logger.With("req", req).DebugContext(ctx.Request().Context(), "OAuthSignUpOrIn")
req.BaseURL = h.cfg.GetBaseURL(ctx.Request())
s, err := h.usecase.GetSetting(ctx.Request().Context())
if err != nil {
return err
}
req.BaseURL = h.cfg.GetBaseURL(ctx.Request(), s)
resp, err := h.usecase.OAuthSignUpOrIn(ctx.Request().Context(), &req)
if err != nil {
return err

View File

@@ -2,6 +2,7 @@ package repo
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
@@ -225,9 +226,15 @@ func (r *UserRepo) GetUserByApiKey(ctx context.Context, apiKey string) (*db.User
}
func (r *UserRepo) GetSetting(ctx context.Context) (*db.Setting, error) {
if b, err := r.redis.Get(ctx, "setting").Result(); err == nil {
s := &db.Setting{}
if err := json.Unmarshal([]byte(b), s); err == nil {
return s, nil
}
}
s, err := r.db.Setting.Query().First(ctx)
if db.IsNotFound(err) {
return r.db.Setting.Create().
s, err = r.db.Setting.Create().
SetEnableSSO(false).
SetForceTwoFactorAuth(false).
SetDisablePasswordLogin(false).
@@ -236,6 +243,13 @@ func (r *UserRepo) GetSetting(ctx context.Context) (*db.Setting, error) {
if err != nil {
return nil, err
}
b, err := json.Marshal(s)
if err != nil {
return nil, err
}
if err := r.redis.Set(ctx, "setting", b, time.Hour*24).Err(); err != nil {
return nil, err
}
return s, nil
}
@@ -253,7 +267,7 @@ func (r *UserRepo) UpdateSetting(ctx context.Context, fn func(*db.Setting, *db.S
return err
}
res = s
return nil
return r.redis.Del(ctx, "setting").Err()
})
return res, err
}

View File

@@ -391,6 +391,9 @@ func (u *UserUsecase) UpdateSetting(ctx context.Context, req *domain.UpdateSetti
}
up.SetCustomOauth(custom)
}
if req.BaseURL != nil {
up.SetBaseURL(*req.BaseURL)
}
})
if err != nil {
return nil, err
@@ -518,7 +521,11 @@ func (u *UserUsecase) OAuthSignUpOrIn(ctx context.Context, req *domain.OAuthSign
func (u *UserUsecase) OAuthCallback(c *web.Context, req *domain.OAuthCallbackReq) error {
ctx := c.Request().Context()
req.IP = c.RealIP()
req.BaseURL = u.cfg.GetBaseURL(c.Request())
s, err := u.GetSetting(ctx)
if err != nil {
return err
}
req.BaseURL = u.cfg.GetBaseURL(c.Request(), s)
b, err := u.redis.Get(ctx, fmt.Sprintf("oauth:state:%s", req.State)).Result()
if err != nil {
return err

View File

@@ -0,0 +1 @@
ALTER TABLE settings DROP COLUMN IF EXISTS base_url;

View File

@@ -0,0 +1 @@
ALTER TABLE settings ADD COLUMN IF NOT EXISTS base_url TEXT;

View File

@@ -32,6 +32,7 @@ http {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Port $http_x_forwarded_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;