mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-05-05 05:30:44 +08:00
feat(group-filter): 分组账号过滤控制 — require_oauth_only + require_privacy_set
为 OpenAI/Antigravity/Anthropic/Gemini 分组新增两个布尔控制字段:
- require_oauth_only: 创建/更新账号绑定分组时拒绝 apikey 类型加入
- require_privacy_set: 调度选号时跳过 privacy 未成功设置的账号并标记 error
后端:Ent schema 新增字段 + 迁移、Group CRUD 全链路透传、
gateway_service 与 openai_account_scheduler 两套调度路径过滤
前端:创建/编辑表单 toggle 开关(OpenAI/Antigravity/Anthropic/Gemini 平台可见)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -80,6 +80,10 @@ type Group struct {
|
|||||||
SortOrder int `json:"sort_order,omitempty"`
|
SortOrder int `json:"sort_order,omitempty"`
|
||||||
// 是否允许 /v1/messages 调度到此 OpenAI 分组
|
// 是否允许 /v1/messages 调度到此 OpenAI 分组
|
||||||
AllowMessagesDispatch bool `json:"allow_messages_dispatch,omitempty"`
|
AllowMessagesDispatch bool `json:"allow_messages_dispatch,omitempty"`
|
||||||
|
// 仅允许非 apikey 类型账号关联到此分组
|
||||||
|
RequireOauthOnly bool `json:"require_oauth_only,omitempty"`
|
||||||
|
// 调度时仅允许 privacy 已成功设置的账号
|
||||||
|
RequirePrivacySet bool `json:"require_privacy_set,omitempty"`
|
||||||
// 默认映射模型 ID,当账号级映射找不到时使用此值
|
// 默认映射模型 ID,当账号级映射找不到时使用此值
|
||||||
DefaultMappedModel string `json:"default_mapped_model,omitempty"`
|
DefaultMappedModel string `json:"default_mapped_model,omitempty"`
|
||||||
// Edges holds the relations/edges for other nodes in the graph.
|
// Edges holds the relations/edges for other nodes in the graph.
|
||||||
@@ -190,7 +194,7 @@ func (*Group) scanValues(columns []string) ([]any, error) {
|
|||||||
switch columns[i] {
|
switch columns[i] {
|
||||||
case group.FieldModelRouting, group.FieldSupportedModelScopes:
|
case group.FieldModelRouting, group.FieldSupportedModelScopes:
|
||||||
values[i] = new([]byte)
|
values[i] = new([]byte)
|
||||||
case group.FieldIsExclusive, group.FieldClaudeCodeOnly, group.FieldModelRoutingEnabled, group.FieldMcpXMLInject, group.FieldAllowMessagesDispatch:
|
case group.FieldIsExclusive, group.FieldClaudeCodeOnly, group.FieldModelRoutingEnabled, group.FieldMcpXMLInject, group.FieldAllowMessagesDispatch, group.FieldRequireOauthOnly, group.FieldRequirePrivacySet:
|
||||||
values[i] = new(sql.NullBool)
|
values[i] = new(sql.NullBool)
|
||||||
case group.FieldRateMultiplier, group.FieldDailyLimitUsd, group.FieldWeeklyLimitUsd, group.FieldMonthlyLimitUsd, group.FieldImagePrice1k, group.FieldImagePrice2k, group.FieldImagePrice4k, group.FieldSoraImagePrice360, group.FieldSoraImagePrice540, group.FieldSoraVideoPricePerRequest, group.FieldSoraVideoPricePerRequestHd:
|
case group.FieldRateMultiplier, group.FieldDailyLimitUsd, group.FieldWeeklyLimitUsd, group.FieldMonthlyLimitUsd, group.FieldImagePrice1k, group.FieldImagePrice2k, group.FieldImagePrice4k, group.FieldSoraImagePrice360, group.FieldSoraImagePrice540, group.FieldSoraVideoPricePerRequest, group.FieldSoraVideoPricePerRequestHd:
|
||||||
values[i] = new(sql.NullFloat64)
|
values[i] = new(sql.NullFloat64)
|
||||||
@@ -425,6 +429,18 @@ func (_m *Group) assignValues(columns []string, values []any) error {
|
|||||||
} else if value.Valid {
|
} else if value.Valid {
|
||||||
_m.AllowMessagesDispatch = value.Bool
|
_m.AllowMessagesDispatch = value.Bool
|
||||||
}
|
}
|
||||||
|
case group.FieldRequireOauthOnly:
|
||||||
|
if value, ok := values[i].(*sql.NullBool); !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field require_oauth_only", values[i])
|
||||||
|
} else if value.Valid {
|
||||||
|
_m.RequireOauthOnly = value.Bool
|
||||||
|
}
|
||||||
|
case group.FieldRequirePrivacySet:
|
||||||
|
if value, ok := values[i].(*sql.NullBool); !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field require_privacy_set", values[i])
|
||||||
|
} else if value.Valid {
|
||||||
|
_m.RequirePrivacySet = value.Bool
|
||||||
|
}
|
||||||
case group.FieldDefaultMappedModel:
|
case group.FieldDefaultMappedModel:
|
||||||
if value, ok := values[i].(*sql.NullString); !ok {
|
if value, ok := values[i].(*sql.NullString); !ok {
|
||||||
return fmt.Errorf("unexpected type %T for field default_mapped_model", values[i])
|
return fmt.Errorf("unexpected type %T for field default_mapped_model", values[i])
|
||||||
@@ -628,6 +644,12 @@ func (_m *Group) String() string {
|
|||||||
builder.WriteString("allow_messages_dispatch=")
|
builder.WriteString("allow_messages_dispatch=")
|
||||||
builder.WriteString(fmt.Sprintf("%v", _m.AllowMessagesDispatch))
|
builder.WriteString(fmt.Sprintf("%v", _m.AllowMessagesDispatch))
|
||||||
builder.WriteString(", ")
|
builder.WriteString(", ")
|
||||||
|
builder.WriteString("require_oauth_only=")
|
||||||
|
builder.WriteString(fmt.Sprintf("%v", _m.RequireOauthOnly))
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteString("require_privacy_set=")
|
||||||
|
builder.WriteString(fmt.Sprintf("%v", _m.RequirePrivacySet))
|
||||||
|
builder.WriteString(", ")
|
||||||
builder.WriteString("default_mapped_model=")
|
builder.WriteString("default_mapped_model=")
|
||||||
builder.WriteString(_m.DefaultMappedModel)
|
builder.WriteString(_m.DefaultMappedModel)
|
||||||
builder.WriteByte(')')
|
builder.WriteByte(')')
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ const (
|
|||||||
FieldSortOrder = "sort_order"
|
FieldSortOrder = "sort_order"
|
||||||
// FieldAllowMessagesDispatch holds the string denoting the allow_messages_dispatch field in the database.
|
// FieldAllowMessagesDispatch holds the string denoting the allow_messages_dispatch field in the database.
|
||||||
FieldAllowMessagesDispatch = "allow_messages_dispatch"
|
FieldAllowMessagesDispatch = "allow_messages_dispatch"
|
||||||
|
// FieldRequireOauthOnly holds the string denoting the require_oauth_only field in the database.
|
||||||
|
FieldRequireOauthOnly = "require_oauth_only"
|
||||||
|
// FieldRequirePrivacySet holds the string denoting the require_privacy_set field in the database.
|
||||||
|
FieldRequirePrivacySet = "require_privacy_set"
|
||||||
// FieldDefaultMappedModel holds the string denoting the default_mapped_model field in the database.
|
// FieldDefaultMappedModel holds the string denoting the default_mapped_model field in the database.
|
||||||
FieldDefaultMappedModel = "default_mapped_model"
|
FieldDefaultMappedModel = "default_mapped_model"
|
||||||
// EdgeAPIKeys holds the string denoting the api_keys edge name in mutations.
|
// EdgeAPIKeys holds the string denoting the api_keys edge name in mutations.
|
||||||
@@ -185,6 +189,8 @@ var Columns = []string{
|
|||||||
FieldSupportedModelScopes,
|
FieldSupportedModelScopes,
|
||||||
FieldSortOrder,
|
FieldSortOrder,
|
||||||
FieldAllowMessagesDispatch,
|
FieldAllowMessagesDispatch,
|
||||||
|
FieldRequireOauthOnly,
|
||||||
|
FieldRequirePrivacySet,
|
||||||
FieldDefaultMappedModel,
|
FieldDefaultMappedModel,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,6 +261,10 @@ var (
|
|||||||
DefaultSortOrder int
|
DefaultSortOrder int
|
||||||
// DefaultAllowMessagesDispatch holds the default value on creation for the "allow_messages_dispatch" field.
|
// DefaultAllowMessagesDispatch holds the default value on creation for the "allow_messages_dispatch" field.
|
||||||
DefaultAllowMessagesDispatch bool
|
DefaultAllowMessagesDispatch bool
|
||||||
|
// DefaultRequireOauthOnly holds the default value on creation for the "require_oauth_only" field.
|
||||||
|
DefaultRequireOauthOnly bool
|
||||||
|
// DefaultRequirePrivacySet holds the default value on creation for the "require_privacy_set" field.
|
||||||
|
DefaultRequirePrivacySet bool
|
||||||
// DefaultDefaultMappedModel holds the default value on creation for the "default_mapped_model" field.
|
// DefaultDefaultMappedModel holds the default value on creation for the "default_mapped_model" field.
|
||||||
DefaultDefaultMappedModel string
|
DefaultDefaultMappedModel string
|
||||||
// DefaultMappedModelValidator is a validator for the "default_mapped_model" field. It is called by the builders before save.
|
// DefaultMappedModelValidator is a validator for the "default_mapped_model" field. It is called by the builders before save.
|
||||||
@@ -414,6 +424,16 @@ func ByAllowMessagesDispatch(opts ...sql.OrderTermOption) OrderOption {
|
|||||||
return sql.OrderByField(FieldAllowMessagesDispatch, opts...).ToFunc()
|
return sql.OrderByField(FieldAllowMessagesDispatch, opts...).ToFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ByRequireOauthOnly orders the results by the require_oauth_only field.
|
||||||
|
func ByRequireOauthOnly(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldRequireOauthOnly, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByRequirePrivacySet orders the results by the require_privacy_set field.
|
||||||
|
func ByRequirePrivacySet(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldRequirePrivacySet, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
// ByDefaultMappedModel orders the results by the default_mapped_model field.
|
// ByDefaultMappedModel orders the results by the default_mapped_model field.
|
||||||
func ByDefaultMappedModel(opts ...sql.OrderTermOption) OrderOption {
|
func ByDefaultMappedModel(opts ...sql.OrderTermOption) OrderOption {
|
||||||
return sql.OrderByField(FieldDefaultMappedModel, opts...).ToFunc()
|
return sql.OrderByField(FieldDefaultMappedModel, opts...).ToFunc()
|
||||||
|
|||||||
@@ -200,6 +200,16 @@ func AllowMessagesDispatch(v bool) predicate.Group {
|
|||||||
return predicate.Group(sql.FieldEQ(FieldAllowMessagesDispatch, v))
|
return predicate.Group(sql.FieldEQ(FieldAllowMessagesDispatch, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequireOauthOnly applies equality check predicate on the "require_oauth_only" field. It's identical to RequireOauthOnlyEQ.
|
||||||
|
func RequireOauthOnly(v bool) predicate.Group {
|
||||||
|
return predicate.Group(sql.FieldEQ(FieldRequireOauthOnly, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequirePrivacySet applies equality check predicate on the "require_privacy_set" field. It's identical to RequirePrivacySetEQ.
|
||||||
|
func RequirePrivacySet(v bool) predicate.Group {
|
||||||
|
return predicate.Group(sql.FieldEQ(FieldRequirePrivacySet, v))
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultMappedModel applies equality check predicate on the "default_mapped_model" field. It's identical to DefaultMappedModelEQ.
|
// DefaultMappedModel applies equality check predicate on the "default_mapped_model" field. It's identical to DefaultMappedModelEQ.
|
||||||
func DefaultMappedModel(v string) predicate.Group {
|
func DefaultMappedModel(v string) predicate.Group {
|
||||||
return predicate.Group(sql.FieldEQ(FieldDefaultMappedModel, v))
|
return predicate.Group(sql.FieldEQ(FieldDefaultMappedModel, v))
|
||||||
@@ -1490,6 +1500,26 @@ func AllowMessagesDispatchNEQ(v bool) predicate.Group {
|
|||||||
return predicate.Group(sql.FieldNEQ(FieldAllowMessagesDispatch, v))
|
return predicate.Group(sql.FieldNEQ(FieldAllowMessagesDispatch, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequireOauthOnlyEQ applies the EQ predicate on the "require_oauth_only" field.
|
||||||
|
func RequireOauthOnlyEQ(v bool) predicate.Group {
|
||||||
|
return predicate.Group(sql.FieldEQ(FieldRequireOauthOnly, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequireOauthOnlyNEQ applies the NEQ predicate on the "require_oauth_only" field.
|
||||||
|
func RequireOauthOnlyNEQ(v bool) predicate.Group {
|
||||||
|
return predicate.Group(sql.FieldNEQ(FieldRequireOauthOnly, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequirePrivacySetEQ applies the EQ predicate on the "require_privacy_set" field.
|
||||||
|
func RequirePrivacySetEQ(v bool) predicate.Group {
|
||||||
|
return predicate.Group(sql.FieldEQ(FieldRequirePrivacySet, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequirePrivacySetNEQ applies the NEQ predicate on the "require_privacy_set" field.
|
||||||
|
func RequirePrivacySetNEQ(v bool) predicate.Group {
|
||||||
|
return predicate.Group(sql.FieldNEQ(FieldRequirePrivacySet, v))
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultMappedModelEQ applies the EQ predicate on the "default_mapped_model" field.
|
// DefaultMappedModelEQ applies the EQ predicate on the "default_mapped_model" field.
|
||||||
func DefaultMappedModelEQ(v string) predicate.Group {
|
func DefaultMappedModelEQ(v string) predicate.Group {
|
||||||
return predicate.Group(sql.FieldEQ(FieldDefaultMappedModel, v))
|
return predicate.Group(sql.FieldEQ(FieldDefaultMappedModel, v))
|
||||||
|
|||||||
@@ -438,6 +438,34 @@ func (_c *GroupCreate) SetNillableAllowMessagesDispatch(v *bool) *GroupCreate {
|
|||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRequireOauthOnly sets the "require_oauth_only" field.
|
||||||
|
func (_c *GroupCreate) SetRequireOauthOnly(v bool) *GroupCreate {
|
||||||
|
_c.mutation.SetRequireOauthOnly(v)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableRequireOauthOnly sets the "require_oauth_only" field if the given value is not nil.
|
||||||
|
func (_c *GroupCreate) SetNillableRequireOauthOnly(v *bool) *GroupCreate {
|
||||||
|
if v != nil {
|
||||||
|
_c.SetRequireOauthOnly(*v)
|
||||||
|
}
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRequirePrivacySet sets the "require_privacy_set" field.
|
||||||
|
func (_c *GroupCreate) SetRequirePrivacySet(v bool) *GroupCreate {
|
||||||
|
_c.mutation.SetRequirePrivacySet(v)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableRequirePrivacySet sets the "require_privacy_set" field if the given value is not nil.
|
||||||
|
func (_c *GroupCreate) SetNillableRequirePrivacySet(v *bool) *GroupCreate {
|
||||||
|
if v != nil {
|
||||||
|
_c.SetRequirePrivacySet(*v)
|
||||||
|
}
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
||||||
func (_c *GroupCreate) SetDefaultMappedModel(v string) *GroupCreate {
|
func (_c *GroupCreate) SetDefaultMappedModel(v string) *GroupCreate {
|
||||||
_c.mutation.SetDefaultMappedModel(v)
|
_c.mutation.SetDefaultMappedModel(v)
|
||||||
@@ -645,6 +673,14 @@ func (_c *GroupCreate) defaults() error {
|
|||||||
v := group.DefaultAllowMessagesDispatch
|
v := group.DefaultAllowMessagesDispatch
|
||||||
_c.mutation.SetAllowMessagesDispatch(v)
|
_c.mutation.SetAllowMessagesDispatch(v)
|
||||||
}
|
}
|
||||||
|
if _, ok := _c.mutation.RequireOauthOnly(); !ok {
|
||||||
|
v := group.DefaultRequireOauthOnly
|
||||||
|
_c.mutation.SetRequireOauthOnly(v)
|
||||||
|
}
|
||||||
|
if _, ok := _c.mutation.RequirePrivacySet(); !ok {
|
||||||
|
v := group.DefaultRequirePrivacySet
|
||||||
|
_c.mutation.SetRequirePrivacySet(v)
|
||||||
|
}
|
||||||
if _, ok := _c.mutation.DefaultMappedModel(); !ok {
|
if _, ok := _c.mutation.DefaultMappedModel(); !ok {
|
||||||
v := group.DefaultDefaultMappedModel
|
v := group.DefaultDefaultMappedModel
|
||||||
_c.mutation.SetDefaultMappedModel(v)
|
_c.mutation.SetDefaultMappedModel(v)
|
||||||
@@ -722,6 +758,12 @@ func (_c *GroupCreate) check() error {
|
|||||||
if _, ok := _c.mutation.AllowMessagesDispatch(); !ok {
|
if _, ok := _c.mutation.AllowMessagesDispatch(); !ok {
|
||||||
return &ValidationError{Name: "allow_messages_dispatch", err: errors.New(`ent: missing required field "Group.allow_messages_dispatch"`)}
|
return &ValidationError{Name: "allow_messages_dispatch", err: errors.New(`ent: missing required field "Group.allow_messages_dispatch"`)}
|
||||||
}
|
}
|
||||||
|
if _, ok := _c.mutation.RequireOauthOnly(); !ok {
|
||||||
|
return &ValidationError{Name: "require_oauth_only", err: errors.New(`ent: missing required field "Group.require_oauth_only"`)}
|
||||||
|
}
|
||||||
|
if _, ok := _c.mutation.RequirePrivacySet(); !ok {
|
||||||
|
return &ValidationError{Name: "require_privacy_set", err: errors.New(`ent: missing required field "Group.require_privacy_set"`)}
|
||||||
|
}
|
||||||
if _, ok := _c.mutation.DefaultMappedModel(); !ok {
|
if _, ok := _c.mutation.DefaultMappedModel(); !ok {
|
||||||
return &ValidationError{Name: "default_mapped_model", err: errors.New(`ent: missing required field "Group.default_mapped_model"`)}
|
return &ValidationError{Name: "default_mapped_model", err: errors.New(`ent: missing required field "Group.default_mapped_model"`)}
|
||||||
}
|
}
|
||||||
@@ -881,6 +923,14 @@ func (_c *GroupCreate) createSpec() (*Group, *sqlgraph.CreateSpec) {
|
|||||||
_spec.SetField(group.FieldAllowMessagesDispatch, field.TypeBool, value)
|
_spec.SetField(group.FieldAllowMessagesDispatch, field.TypeBool, value)
|
||||||
_node.AllowMessagesDispatch = value
|
_node.AllowMessagesDispatch = value
|
||||||
}
|
}
|
||||||
|
if value, ok := _c.mutation.RequireOauthOnly(); ok {
|
||||||
|
_spec.SetField(group.FieldRequireOauthOnly, field.TypeBool, value)
|
||||||
|
_node.RequireOauthOnly = value
|
||||||
|
}
|
||||||
|
if value, ok := _c.mutation.RequirePrivacySet(); ok {
|
||||||
|
_spec.SetField(group.FieldRequirePrivacySet, field.TypeBool, value)
|
||||||
|
_node.RequirePrivacySet = value
|
||||||
|
}
|
||||||
if value, ok := _c.mutation.DefaultMappedModel(); ok {
|
if value, ok := _c.mutation.DefaultMappedModel(); ok {
|
||||||
_spec.SetField(group.FieldDefaultMappedModel, field.TypeString, value)
|
_spec.SetField(group.FieldDefaultMappedModel, field.TypeString, value)
|
||||||
_node.DefaultMappedModel = value
|
_node.DefaultMappedModel = value
|
||||||
@@ -1587,6 +1637,30 @@ func (u *GroupUpsert) UpdateAllowMessagesDispatch() *GroupUpsert {
|
|||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRequireOauthOnly sets the "require_oauth_only" field.
|
||||||
|
func (u *GroupUpsert) SetRequireOauthOnly(v bool) *GroupUpsert {
|
||||||
|
u.Set(group.FieldRequireOauthOnly, v)
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRequireOauthOnly sets the "require_oauth_only" field to the value that was provided on create.
|
||||||
|
func (u *GroupUpsert) UpdateRequireOauthOnly() *GroupUpsert {
|
||||||
|
u.SetExcluded(group.FieldRequireOauthOnly)
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRequirePrivacySet sets the "require_privacy_set" field.
|
||||||
|
func (u *GroupUpsert) SetRequirePrivacySet(v bool) *GroupUpsert {
|
||||||
|
u.Set(group.FieldRequirePrivacySet, v)
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRequirePrivacySet sets the "require_privacy_set" field to the value that was provided on create.
|
||||||
|
func (u *GroupUpsert) UpdateRequirePrivacySet() *GroupUpsert {
|
||||||
|
u.SetExcluded(group.FieldRequirePrivacySet)
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
||||||
func (u *GroupUpsert) SetDefaultMappedModel(v string) *GroupUpsert {
|
func (u *GroupUpsert) SetDefaultMappedModel(v string) *GroupUpsert {
|
||||||
u.Set(group.FieldDefaultMappedModel, v)
|
u.Set(group.FieldDefaultMappedModel, v)
|
||||||
@@ -2281,6 +2355,34 @@ func (u *GroupUpsertOne) UpdateAllowMessagesDispatch() *GroupUpsertOne {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRequireOauthOnly sets the "require_oauth_only" field.
|
||||||
|
func (u *GroupUpsertOne) SetRequireOauthOnly(v bool) *GroupUpsertOne {
|
||||||
|
return u.Update(func(s *GroupUpsert) {
|
||||||
|
s.SetRequireOauthOnly(v)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRequireOauthOnly sets the "require_oauth_only" field to the value that was provided on create.
|
||||||
|
func (u *GroupUpsertOne) UpdateRequireOauthOnly() *GroupUpsertOne {
|
||||||
|
return u.Update(func(s *GroupUpsert) {
|
||||||
|
s.UpdateRequireOauthOnly()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRequirePrivacySet sets the "require_privacy_set" field.
|
||||||
|
func (u *GroupUpsertOne) SetRequirePrivacySet(v bool) *GroupUpsertOne {
|
||||||
|
return u.Update(func(s *GroupUpsert) {
|
||||||
|
s.SetRequirePrivacySet(v)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRequirePrivacySet sets the "require_privacy_set" field to the value that was provided on create.
|
||||||
|
func (u *GroupUpsertOne) UpdateRequirePrivacySet() *GroupUpsertOne {
|
||||||
|
return u.Update(func(s *GroupUpsert) {
|
||||||
|
s.UpdateRequirePrivacySet()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
||||||
func (u *GroupUpsertOne) SetDefaultMappedModel(v string) *GroupUpsertOne {
|
func (u *GroupUpsertOne) SetDefaultMappedModel(v string) *GroupUpsertOne {
|
||||||
return u.Update(func(s *GroupUpsert) {
|
return u.Update(func(s *GroupUpsert) {
|
||||||
@@ -3143,6 +3245,34 @@ func (u *GroupUpsertBulk) UpdateAllowMessagesDispatch() *GroupUpsertBulk {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRequireOauthOnly sets the "require_oauth_only" field.
|
||||||
|
func (u *GroupUpsertBulk) SetRequireOauthOnly(v bool) *GroupUpsertBulk {
|
||||||
|
return u.Update(func(s *GroupUpsert) {
|
||||||
|
s.SetRequireOauthOnly(v)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRequireOauthOnly sets the "require_oauth_only" field to the value that was provided on create.
|
||||||
|
func (u *GroupUpsertBulk) UpdateRequireOauthOnly() *GroupUpsertBulk {
|
||||||
|
return u.Update(func(s *GroupUpsert) {
|
||||||
|
s.UpdateRequireOauthOnly()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRequirePrivacySet sets the "require_privacy_set" field.
|
||||||
|
func (u *GroupUpsertBulk) SetRequirePrivacySet(v bool) *GroupUpsertBulk {
|
||||||
|
return u.Update(func(s *GroupUpsert) {
|
||||||
|
s.SetRequirePrivacySet(v)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRequirePrivacySet sets the "require_privacy_set" field to the value that was provided on create.
|
||||||
|
func (u *GroupUpsertBulk) UpdateRequirePrivacySet() *GroupUpsertBulk {
|
||||||
|
return u.Update(func(s *GroupUpsert) {
|
||||||
|
s.UpdateRequirePrivacySet()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
||||||
func (u *GroupUpsertBulk) SetDefaultMappedModel(v string) *GroupUpsertBulk {
|
func (u *GroupUpsertBulk) SetDefaultMappedModel(v string) *GroupUpsertBulk {
|
||||||
return u.Update(func(s *GroupUpsert) {
|
return u.Update(func(s *GroupUpsert) {
|
||||||
|
|||||||
@@ -639,6 +639,34 @@ func (_u *GroupUpdate) SetNillableAllowMessagesDispatch(v *bool) *GroupUpdate {
|
|||||||
return _u
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRequireOauthOnly sets the "require_oauth_only" field.
|
||||||
|
func (_u *GroupUpdate) SetRequireOauthOnly(v bool) *GroupUpdate {
|
||||||
|
_u.mutation.SetRequireOauthOnly(v)
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableRequireOauthOnly sets the "require_oauth_only" field if the given value is not nil.
|
||||||
|
func (_u *GroupUpdate) SetNillableRequireOauthOnly(v *bool) *GroupUpdate {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetRequireOauthOnly(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRequirePrivacySet sets the "require_privacy_set" field.
|
||||||
|
func (_u *GroupUpdate) SetRequirePrivacySet(v bool) *GroupUpdate {
|
||||||
|
_u.mutation.SetRequirePrivacySet(v)
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableRequirePrivacySet sets the "require_privacy_set" field if the given value is not nil.
|
||||||
|
func (_u *GroupUpdate) SetNillableRequirePrivacySet(v *bool) *GroupUpdate {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetRequirePrivacySet(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
||||||
func (_u *GroupUpdate) SetDefaultMappedModel(v string) *GroupUpdate {
|
func (_u *GroupUpdate) SetDefaultMappedModel(v string) *GroupUpdate {
|
||||||
_u.mutation.SetDefaultMappedModel(v)
|
_u.mutation.SetDefaultMappedModel(v)
|
||||||
@@ -1146,6 +1174,12 @@ func (_u *GroupUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
|||||||
if value, ok := _u.mutation.AllowMessagesDispatch(); ok {
|
if value, ok := _u.mutation.AllowMessagesDispatch(); ok {
|
||||||
_spec.SetField(group.FieldAllowMessagesDispatch, field.TypeBool, value)
|
_spec.SetField(group.FieldAllowMessagesDispatch, field.TypeBool, value)
|
||||||
}
|
}
|
||||||
|
if value, ok := _u.mutation.RequireOauthOnly(); ok {
|
||||||
|
_spec.SetField(group.FieldRequireOauthOnly, field.TypeBool, value)
|
||||||
|
}
|
||||||
|
if value, ok := _u.mutation.RequirePrivacySet(); ok {
|
||||||
|
_spec.SetField(group.FieldRequirePrivacySet, field.TypeBool, value)
|
||||||
|
}
|
||||||
if value, ok := _u.mutation.DefaultMappedModel(); ok {
|
if value, ok := _u.mutation.DefaultMappedModel(); ok {
|
||||||
_spec.SetField(group.FieldDefaultMappedModel, field.TypeString, value)
|
_spec.SetField(group.FieldDefaultMappedModel, field.TypeString, value)
|
||||||
}
|
}
|
||||||
@@ -2067,6 +2101,34 @@ func (_u *GroupUpdateOne) SetNillableAllowMessagesDispatch(v *bool) *GroupUpdate
|
|||||||
return _u
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRequireOauthOnly sets the "require_oauth_only" field.
|
||||||
|
func (_u *GroupUpdateOne) SetRequireOauthOnly(v bool) *GroupUpdateOne {
|
||||||
|
_u.mutation.SetRequireOauthOnly(v)
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableRequireOauthOnly sets the "require_oauth_only" field if the given value is not nil.
|
||||||
|
func (_u *GroupUpdateOne) SetNillableRequireOauthOnly(v *bool) *GroupUpdateOne {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetRequireOauthOnly(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRequirePrivacySet sets the "require_privacy_set" field.
|
||||||
|
func (_u *GroupUpdateOne) SetRequirePrivacySet(v bool) *GroupUpdateOne {
|
||||||
|
_u.mutation.SetRequirePrivacySet(v)
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableRequirePrivacySet sets the "require_privacy_set" field if the given value is not nil.
|
||||||
|
func (_u *GroupUpdateOne) SetNillableRequirePrivacySet(v *bool) *GroupUpdateOne {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetRequirePrivacySet(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
||||||
func (_u *GroupUpdateOne) SetDefaultMappedModel(v string) *GroupUpdateOne {
|
func (_u *GroupUpdateOne) SetDefaultMappedModel(v string) *GroupUpdateOne {
|
||||||
_u.mutation.SetDefaultMappedModel(v)
|
_u.mutation.SetDefaultMappedModel(v)
|
||||||
@@ -2604,6 +2666,12 @@ func (_u *GroupUpdateOne) sqlSave(ctx context.Context) (_node *Group, err error)
|
|||||||
if value, ok := _u.mutation.AllowMessagesDispatch(); ok {
|
if value, ok := _u.mutation.AllowMessagesDispatch(); ok {
|
||||||
_spec.SetField(group.FieldAllowMessagesDispatch, field.TypeBool, value)
|
_spec.SetField(group.FieldAllowMessagesDispatch, field.TypeBool, value)
|
||||||
}
|
}
|
||||||
|
if value, ok := _u.mutation.RequireOauthOnly(); ok {
|
||||||
|
_spec.SetField(group.FieldRequireOauthOnly, field.TypeBool, value)
|
||||||
|
}
|
||||||
|
if value, ok := _u.mutation.RequirePrivacySet(); ok {
|
||||||
|
_spec.SetField(group.FieldRequirePrivacySet, field.TypeBool, value)
|
||||||
|
}
|
||||||
if value, ok := _u.mutation.DefaultMappedModel(); ok {
|
if value, ok := _u.mutation.DefaultMappedModel(); ok {
|
||||||
_spec.SetField(group.FieldDefaultMappedModel, field.TypeString, value)
|
_spec.SetField(group.FieldDefaultMappedModel, field.TypeString, value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -409,6 +409,8 @@ var (
|
|||||||
{Name: "supported_model_scopes", Type: field.TypeJSON, SchemaType: map[string]string{"postgres": "jsonb"}},
|
{Name: "supported_model_scopes", Type: field.TypeJSON, SchemaType: map[string]string{"postgres": "jsonb"}},
|
||||||
{Name: "sort_order", Type: field.TypeInt, Default: 0},
|
{Name: "sort_order", Type: field.TypeInt, Default: 0},
|
||||||
{Name: "allow_messages_dispatch", Type: field.TypeBool, Default: false},
|
{Name: "allow_messages_dispatch", Type: field.TypeBool, Default: false},
|
||||||
|
{Name: "require_oauth_only", Type: field.TypeBool, Default: false},
|
||||||
|
{Name: "require_privacy_set", Type: field.TypeBool, Default: false},
|
||||||
{Name: "default_mapped_model", Type: field.TypeString, Size: 100, Default: ""},
|
{Name: "default_mapped_model", Type: field.TypeString, Size: 100, Default: ""},
|
||||||
}
|
}
|
||||||
// GroupsTable holds the schema information for the "groups" table.
|
// GroupsTable holds the schema information for the "groups" table.
|
||||||
|
|||||||
@@ -8253,6 +8253,8 @@ type GroupMutation struct {
|
|||||||
sort_order *int
|
sort_order *int
|
||||||
addsort_order *int
|
addsort_order *int
|
||||||
allow_messages_dispatch *bool
|
allow_messages_dispatch *bool
|
||||||
|
require_oauth_only *bool
|
||||||
|
require_privacy_set *bool
|
||||||
default_mapped_model *string
|
default_mapped_model *string
|
||||||
clearedFields map[string]struct{}
|
clearedFields map[string]struct{}
|
||||||
api_keys map[int64]struct{}
|
api_keys map[int64]struct{}
|
||||||
@@ -10034,6 +10036,78 @@ func (m *GroupMutation) ResetAllowMessagesDispatch() {
|
|||||||
m.allow_messages_dispatch = nil
|
m.allow_messages_dispatch = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRequireOauthOnly sets the "require_oauth_only" field.
|
||||||
|
func (m *GroupMutation) SetRequireOauthOnly(b bool) {
|
||||||
|
m.require_oauth_only = &b
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequireOauthOnly returns the value of the "require_oauth_only" field in the mutation.
|
||||||
|
func (m *GroupMutation) RequireOauthOnly() (r bool, exists bool) {
|
||||||
|
v := m.require_oauth_only
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return *v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// OldRequireOauthOnly returns the old "require_oauth_only" field's value of the Group entity.
|
||||||
|
// If the Group 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 *GroupMutation) OldRequireOauthOnly(ctx context.Context) (v bool, err error) {
|
||||||
|
if !m.op.Is(OpUpdateOne) {
|
||||||
|
return v, errors.New("OldRequireOauthOnly is only allowed on UpdateOne operations")
|
||||||
|
}
|
||||||
|
if m.id == nil || m.oldValue == nil {
|
||||||
|
return v, errors.New("OldRequireOauthOnly requires an ID field in the mutation")
|
||||||
|
}
|
||||||
|
oldValue, err := m.oldValue(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return v, fmt.Errorf("querying old value for OldRequireOauthOnly: %w", err)
|
||||||
|
}
|
||||||
|
return oldValue.RequireOauthOnly, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetRequireOauthOnly resets all changes to the "require_oauth_only" field.
|
||||||
|
func (m *GroupMutation) ResetRequireOauthOnly() {
|
||||||
|
m.require_oauth_only = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRequirePrivacySet sets the "require_privacy_set" field.
|
||||||
|
func (m *GroupMutation) SetRequirePrivacySet(b bool) {
|
||||||
|
m.require_privacy_set = &b
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequirePrivacySet returns the value of the "require_privacy_set" field in the mutation.
|
||||||
|
func (m *GroupMutation) RequirePrivacySet() (r bool, exists bool) {
|
||||||
|
v := m.require_privacy_set
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return *v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// OldRequirePrivacySet returns the old "require_privacy_set" field's value of the Group entity.
|
||||||
|
// If the Group 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 *GroupMutation) OldRequirePrivacySet(ctx context.Context) (v bool, err error) {
|
||||||
|
if !m.op.Is(OpUpdateOne) {
|
||||||
|
return v, errors.New("OldRequirePrivacySet is only allowed on UpdateOne operations")
|
||||||
|
}
|
||||||
|
if m.id == nil || m.oldValue == nil {
|
||||||
|
return v, errors.New("OldRequirePrivacySet requires an ID field in the mutation")
|
||||||
|
}
|
||||||
|
oldValue, err := m.oldValue(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return v, fmt.Errorf("querying old value for OldRequirePrivacySet: %w", err)
|
||||||
|
}
|
||||||
|
return oldValue.RequirePrivacySet, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetRequirePrivacySet resets all changes to the "require_privacy_set" field.
|
||||||
|
func (m *GroupMutation) ResetRequirePrivacySet() {
|
||||||
|
m.require_privacy_set = nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
// SetDefaultMappedModel sets the "default_mapped_model" field.
|
||||||
func (m *GroupMutation) SetDefaultMappedModel(s string) {
|
func (m *GroupMutation) SetDefaultMappedModel(s string) {
|
||||||
m.default_mapped_model = &s
|
m.default_mapped_model = &s
|
||||||
@@ -10428,7 +10502,7 @@ func (m *GroupMutation) Type() string {
|
|||||||
// order to get all numeric fields that were incremented/decremented, call
|
// order to get all numeric fields that were incremented/decremented, call
|
||||||
// AddedFields().
|
// AddedFields().
|
||||||
func (m *GroupMutation) Fields() []string {
|
func (m *GroupMutation) Fields() []string {
|
||||||
fields := make([]string, 0, 32)
|
fields := make([]string, 0, 34)
|
||||||
if m.created_at != nil {
|
if m.created_at != nil {
|
||||||
fields = append(fields, group.FieldCreatedAt)
|
fields = append(fields, group.FieldCreatedAt)
|
||||||
}
|
}
|
||||||
@@ -10522,6 +10596,12 @@ func (m *GroupMutation) Fields() []string {
|
|||||||
if m.allow_messages_dispatch != nil {
|
if m.allow_messages_dispatch != nil {
|
||||||
fields = append(fields, group.FieldAllowMessagesDispatch)
|
fields = append(fields, group.FieldAllowMessagesDispatch)
|
||||||
}
|
}
|
||||||
|
if m.require_oauth_only != nil {
|
||||||
|
fields = append(fields, group.FieldRequireOauthOnly)
|
||||||
|
}
|
||||||
|
if m.require_privacy_set != nil {
|
||||||
|
fields = append(fields, group.FieldRequirePrivacySet)
|
||||||
|
}
|
||||||
if m.default_mapped_model != nil {
|
if m.default_mapped_model != nil {
|
||||||
fields = append(fields, group.FieldDefaultMappedModel)
|
fields = append(fields, group.FieldDefaultMappedModel)
|
||||||
}
|
}
|
||||||
@@ -10595,6 +10675,10 @@ func (m *GroupMutation) Field(name string) (ent.Value, bool) {
|
|||||||
return m.SortOrder()
|
return m.SortOrder()
|
||||||
case group.FieldAllowMessagesDispatch:
|
case group.FieldAllowMessagesDispatch:
|
||||||
return m.AllowMessagesDispatch()
|
return m.AllowMessagesDispatch()
|
||||||
|
case group.FieldRequireOauthOnly:
|
||||||
|
return m.RequireOauthOnly()
|
||||||
|
case group.FieldRequirePrivacySet:
|
||||||
|
return m.RequirePrivacySet()
|
||||||
case group.FieldDefaultMappedModel:
|
case group.FieldDefaultMappedModel:
|
||||||
return m.DefaultMappedModel()
|
return m.DefaultMappedModel()
|
||||||
}
|
}
|
||||||
@@ -10668,6 +10752,10 @@ func (m *GroupMutation) OldField(ctx context.Context, name string) (ent.Value, e
|
|||||||
return m.OldSortOrder(ctx)
|
return m.OldSortOrder(ctx)
|
||||||
case group.FieldAllowMessagesDispatch:
|
case group.FieldAllowMessagesDispatch:
|
||||||
return m.OldAllowMessagesDispatch(ctx)
|
return m.OldAllowMessagesDispatch(ctx)
|
||||||
|
case group.FieldRequireOauthOnly:
|
||||||
|
return m.OldRequireOauthOnly(ctx)
|
||||||
|
case group.FieldRequirePrivacySet:
|
||||||
|
return m.OldRequirePrivacySet(ctx)
|
||||||
case group.FieldDefaultMappedModel:
|
case group.FieldDefaultMappedModel:
|
||||||
return m.OldDefaultMappedModel(ctx)
|
return m.OldDefaultMappedModel(ctx)
|
||||||
}
|
}
|
||||||
@@ -10896,6 +10984,20 @@ func (m *GroupMutation) SetField(name string, value ent.Value) error {
|
|||||||
}
|
}
|
||||||
m.SetAllowMessagesDispatch(v)
|
m.SetAllowMessagesDispatch(v)
|
||||||
return nil
|
return nil
|
||||||
|
case group.FieldRequireOauthOnly:
|
||||||
|
v, ok := value.(bool)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||||
|
}
|
||||||
|
m.SetRequireOauthOnly(v)
|
||||||
|
return nil
|
||||||
|
case group.FieldRequirePrivacySet:
|
||||||
|
v, ok := value.(bool)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||||
|
}
|
||||||
|
m.SetRequirePrivacySet(v)
|
||||||
|
return nil
|
||||||
case group.FieldDefaultMappedModel:
|
case group.FieldDefaultMappedModel:
|
||||||
v, ok := value.(string)
|
v, ok := value.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -11333,6 +11435,12 @@ func (m *GroupMutation) ResetField(name string) error {
|
|||||||
case group.FieldAllowMessagesDispatch:
|
case group.FieldAllowMessagesDispatch:
|
||||||
m.ResetAllowMessagesDispatch()
|
m.ResetAllowMessagesDispatch()
|
||||||
return nil
|
return nil
|
||||||
|
case group.FieldRequireOauthOnly:
|
||||||
|
m.ResetRequireOauthOnly()
|
||||||
|
return nil
|
||||||
|
case group.FieldRequirePrivacySet:
|
||||||
|
m.ResetRequirePrivacySet()
|
||||||
|
return nil
|
||||||
case group.FieldDefaultMappedModel:
|
case group.FieldDefaultMappedModel:
|
||||||
m.ResetDefaultMappedModel()
|
m.ResetDefaultMappedModel()
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -458,8 +458,16 @@ func init() {
|
|||||||
groupDescAllowMessagesDispatch := groupFields[27].Descriptor()
|
groupDescAllowMessagesDispatch := groupFields[27].Descriptor()
|
||||||
// group.DefaultAllowMessagesDispatch holds the default value on creation for the allow_messages_dispatch field.
|
// group.DefaultAllowMessagesDispatch holds the default value on creation for the allow_messages_dispatch field.
|
||||||
group.DefaultAllowMessagesDispatch = groupDescAllowMessagesDispatch.Default.(bool)
|
group.DefaultAllowMessagesDispatch = groupDescAllowMessagesDispatch.Default.(bool)
|
||||||
|
// groupDescRequireOauthOnly is the schema descriptor for require_oauth_only field.
|
||||||
|
groupDescRequireOauthOnly := groupFields[28].Descriptor()
|
||||||
|
// group.DefaultRequireOauthOnly holds the default value on creation for the require_oauth_only field.
|
||||||
|
group.DefaultRequireOauthOnly = groupDescRequireOauthOnly.Default.(bool)
|
||||||
|
// groupDescRequirePrivacySet is the schema descriptor for require_privacy_set field.
|
||||||
|
groupDescRequirePrivacySet := groupFields[29].Descriptor()
|
||||||
|
// group.DefaultRequirePrivacySet holds the default value on creation for the require_privacy_set field.
|
||||||
|
group.DefaultRequirePrivacySet = groupDescRequirePrivacySet.Default.(bool)
|
||||||
// groupDescDefaultMappedModel is the schema descriptor for default_mapped_model field.
|
// groupDescDefaultMappedModel is the schema descriptor for default_mapped_model field.
|
||||||
groupDescDefaultMappedModel := groupFields[28].Descriptor()
|
groupDescDefaultMappedModel := groupFields[30].Descriptor()
|
||||||
// group.DefaultDefaultMappedModel holds the default value on creation for the default_mapped_model field.
|
// group.DefaultDefaultMappedModel holds the default value on creation for the default_mapped_model field.
|
||||||
group.DefaultDefaultMappedModel = groupDescDefaultMappedModel.Default.(string)
|
group.DefaultDefaultMappedModel = groupDescDefaultMappedModel.Default.(string)
|
||||||
// group.DefaultMappedModelValidator is a validator for the "default_mapped_model" field. It is called by the builders before save.
|
// group.DefaultMappedModelValidator is a validator for the "default_mapped_model" field. It is called by the builders before save.
|
||||||
|
|||||||
@@ -153,6 +153,12 @@ func (Group) Fields() []ent.Field {
|
|||||||
field.Bool("allow_messages_dispatch").
|
field.Bool("allow_messages_dispatch").
|
||||||
Default(false).
|
Default(false).
|
||||||
Comment("是否允许 /v1/messages 调度到此 OpenAI 分组"),
|
Comment("是否允许 /v1/messages 调度到此 OpenAI 分组"),
|
||||||
|
field.Bool("require_oauth_only").
|
||||||
|
Default(false).
|
||||||
|
Comment("仅允许非 apikey 类型账号关联到此分组"),
|
||||||
|
field.Bool("require_privacy_set").
|
||||||
|
Default(false).
|
||||||
|
Comment("调度时仅允许 privacy 已成功设置的账号"),
|
||||||
field.String("default_mapped_model").
|
field.String("default_mapped_model").
|
||||||
MaxLen(100).
|
MaxLen(100).
|
||||||
Default("").
|
Default("").
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ type CreateGroupRequest struct {
|
|||||||
SoraStorageQuotaBytes int64 `json:"sora_storage_quota_bytes"`
|
SoraStorageQuotaBytes int64 `json:"sora_storage_quota_bytes"`
|
||||||
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
||||||
AllowMessagesDispatch bool `json:"allow_messages_dispatch"`
|
AllowMessagesDispatch bool `json:"allow_messages_dispatch"`
|
||||||
|
RequireOAuthOnly bool `json:"require_oauth_only"`
|
||||||
|
RequirePrivacySet bool `json:"require_privacy_set"`
|
||||||
DefaultMappedModel string `json:"default_mapped_model"`
|
DefaultMappedModel string `json:"default_mapped_model"`
|
||||||
// 从指定分组复制账号(创建后自动绑定)
|
// 从指定分组复制账号(创建后自动绑定)
|
||||||
CopyAccountsFromGroupIDs []int64 `json:"copy_accounts_from_group_ids"`
|
CopyAccountsFromGroupIDs []int64 `json:"copy_accounts_from_group_ids"`
|
||||||
@@ -150,6 +152,8 @@ type UpdateGroupRequest struct {
|
|||||||
SoraStorageQuotaBytes *int64 `json:"sora_storage_quota_bytes"`
|
SoraStorageQuotaBytes *int64 `json:"sora_storage_quota_bytes"`
|
||||||
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
||||||
AllowMessagesDispatch *bool `json:"allow_messages_dispatch"`
|
AllowMessagesDispatch *bool `json:"allow_messages_dispatch"`
|
||||||
|
RequireOAuthOnly *bool `json:"require_oauth_only"`
|
||||||
|
RequirePrivacySet *bool `json:"require_privacy_set"`
|
||||||
DefaultMappedModel *string `json:"default_mapped_model"`
|
DefaultMappedModel *string `json:"default_mapped_model"`
|
||||||
// 从指定分组复制账号(同步操作:先清空当前分组的账号绑定,再绑定源分组的账号)
|
// 从指定分组复制账号(同步操作:先清空当前分组的账号绑定,再绑定源分组的账号)
|
||||||
CopyAccountsFromGroupIDs []int64 `json:"copy_accounts_from_group_ids"`
|
CopyAccountsFromGroupIDs []int64 `json:"copy_accounts_from_group_ids"`
|
||||||
@@ -267,6 +271,8 @@ func (h *GroupHandler) Create(c *gin.Context) {
|
|||||||
SupportedModelScopes: req.SupportedModelScopes,
|
SupportedModelScopes: req.SupportedModelScopes,
|
||||||
SoraStorageQuotaBytes: req.SoraStorageQuotaBytes,
|
SoraStorageQuotaBytes: req.SoraStorageQuotaBytes,
|
||||||
AllowMessagesDispatch: req.AllowMessagesDispatch,
|
AllowMessagesDispatch: req.AllowMessagesDispatch,
|
||||||
|
RequireOAuthOnly: req.RequireOAuthOnly,
|
||||||
|
RequirePrivacySet: req.RequirePrivacySet,
|
||||||
DefaultMappedModel: req.DefaultMappedModel,
|
DefaultMappedModel: req.DefaultMappedModel,
|
||||||
CopyAccountsFromGroupIDs: req.CopyAccountsFromGroupIDs,
|
CopyAccountsFromGroupIDs: req.CopyAccountsFromGroupIDs,
|
||||||
})
|
})
|
||||||
@@ -320,6 +326,8 @@ func (h *GroupHandler) Update(c *gin.Context) {
|
|||||||
SupportedModelScopes: req.SupportedModelScopes,
|
SupportedModelScopes: req.SupportedModelScopes,
|
||||||
SoraStorageQuotaBytes: req.SoraStorageQuotaBytes,
|
SoraStorageQuotaBytes: req.SoraStorageQuotaBytes,
|
||||||
AllowMessagesDispatch: req.AllowMessagesDispatch,
|
AllowMessagesDispatch: req.AllowMessagesDispatch,
|
||||||
|
RequireOAuthOnly: req.RequireOAuthOnly,
|
||||||
|
RequirePrivacySet: req.RequirePrivacySet,
|
||||||
DefaultMappedModel: req.DefaultMappedModel,
|
DefaultMappedModel: req.DefaultMappedModel,
|
||||||
CopyAccountsFromGroupIDs: req.CopyAccountsFromGroupIDs,
|
CopyAccountsFromGroupIDs: req.CopyAccountsFromGroupIDs,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -181,6 +181,8 @@ func groupFromServiceBase(g *service.Group) Group {
|
|||||||
FallbackGroupIDOnInvalidRequest: g.FallbackGroupIDOnInvalidRequest,
|
FallbackGroupIDOnInvalidRequest: g.FallbackGroupIDOnInvalidRequest,
|
||||||
SoraStorageQuotaBytes: g.SoraStorageQuotaBytes,
|
SoraStorageQuotaBytes: g.SoraStorageQuotaBytes,
|
||||||
AllowMessagesDispatch: g.AllowMessagesDispatch,
|
AllowMessagesDispatch: g.AllowMessagesDispatch,
|
||||||
|
RequireOAuthOnly: g.RequireOAuthOnly,
|
||||||
|
RequirePrivacySet: g.RequirePrivacySet,
|
||||||
CreatedAt: g.CreatedAt,
|
CreatedAt: g.CreatedAt,
|
||||||
UpdatedAt: g.UpdatedAt,
|
UpdatedAt: g.UpdatedAt,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,10 @@ type Group struct {
|
|||||||
// OpenAI Messages 调度开关(用户侧需要此字段判断是否展示 Claude Code 教程)
|
// OpenAI Messages 调度开关(用户侧需要此字段判断是否展示 Claude Code 教程)
|
||||||
AllowMessagesDispatch bool `json:"allow_messages_dispatch"`
|
AllowMessagesDispatch bool `json:"allow_messages_dispatch"`
|
||||||
|
|
||||||
|
// 账号过滤控制(仅 OpenAI/Antigravity 平台有效)
|
||||||
|
RequireOAuthOnly bool `json:"require_oauth_only"`
|
||||||
|
RequirePrivacySet bool `json:"require_privacy_set"`
|
||||||
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -662,6 +662,8 @@ func groupEntityToService(g *dbent.Group) *service.Group {
|
|||||||
SupportedModelScopes: g.SupportedModelScopes,
|
SupportedModelScopes: g.SupportedModelScopes,
|
||||||
SortOrder: g.SortOrder,
|
SortOrder: g.SortOrder,
|
||||||
AllowMessagesDispatch: g.AllowMessagesDispatch,
|
AllowMessagesDispatch: g.AllowMessagesDispatch,
|
||||||
|
RequireOAuthOnly: g.RequireOauthOnly,
|
||||||
|
RequirePrivacySet: g.RequirePrivacySet,
|
||||||
DefaultMappedModel: g.DefaultMappedModel,
|
DefaultMappedModel: g.DefaultMappedModel,
|
||||||
CreatedAt: g.CreatedAt,
|
CreatedAt: g.CreatedAt,
|
||||||
UpdatedAt: g.UpdatedAt,
|
UpdatedAt: g.UpdatedAt,
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ func (r *groupRepository) Create(ctx context.Context, groupIn *service.Group) er
|
|||||||
SetMcpXMLInject(groupIn.MCPXMLInject).
|
SetMcpXMLInject(groupIn.MCPXMLInject).
|
||||||
SetSoraStorageQuotaBytes(groupIn.SoraStorageQuotaBytes).
|
SetSoraStorageQuotaBytes(groupIn.SoraStorageQuotaBytes).
|
||||||
SetAllowMessagesDispatch(groupIn.AllowMessagesDispatch).
|
SetAllowMessagesDispatch(groupIn.AllowMessagesDispatch).
|
||||||
|
SetRequireOauthOnly(groupIn.RequireOAuthOnly).
|
||||||
|
SetRequirePrivacySet(groupIn.RequirePrivacySet).
|
||||||
SetDefaultMappedModel(groupIn.DefaultMappedModel)
|
SetDefaultMappedModel(groupIn.DefaultMappedModel)
|
||||||
|
|
||||||
// 设置模型路由配置
|
// 设置模型路由配置
|
||||||
@@ -130,6 +132,8 @@ func (r *groupRepository) Update(ctx context.Context, groupIn *service.Group) er
|
|||||||
SetMcpXMLInject(groupIn.MCPXMLInject).
|
SetMcpXMLInject(groupIn.MCPXMLInject).
|
||||||
SetSoraStorageQuotaBytes(groupIn.SoraStorageQuotaBytes).
|
SetSoraStorageQuotaBytes(groupIn.SoraStorageQuotaBytes).
|
||||||
SetAllowMessagesDispatch(groupIn.AllowMessagesDispatch).
|
SetAllowMessagesDispatch(groupIn.AllowMessagesDispatch).
|
||||||
|
SetRequireOauthOnly(groupIn.RequireOAuthOnly).
|
||||||
|
SetRequirePrivacySet(groupIn.RequirePrivacySet).
|
||||||
SetDefaultMappedModel(groupIn.DefaultMappedModel)
|
SetDefaultMappedModel(groupIn.DefaultMappedModel)
|
||||||
|
|
||||||
// 显式处理可空字段:nil 需要 clear,非 nil 需要 set。
|
// 显式处理可空字段:nil 需要 clear,非 nil 需要 set。
|
||||||
|
|||||||
@@ -214,6 +214,8 @@ func TestAPIContracts(t *testing.T) {
|
|||||||
"fallback_group_id": null,
|
"fallback_group_id": null,
|
||||||
"fallback_group_id_on_invalid_request": null,
|
"fallback_group_id_on_invalid_request": null,
|
||||||
"allow_messages_dispatch": false,
|
"allow_messages_dispatch": false,
|
||||||
|
"require_oauth_only": false,
|
||||||
|
"require_privacy_set": false,
|
||||||
"created_at": "2025-01-02T03:04:05Z",
|
"created_at": "2025-01-02T03:04:05Z",
|
||||||
"updated_at": "2025-01-02T03:04:05Z"
|
"updated_at": "2025-01-02T03:04:05Z"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,6 +141,21 @@ func (a *Account) IsOAuth() bool {
|
|||||||
return a.Type == AccountTypeOAuth || a.Type == AccountTypeSetupToken
|
return a.Type == AccountTypeOAuth || a.Type == AccountTypeSetupToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsPrivacySet 检查账号的 privacy 是否已成功设置。
|
||||||
|
// OpenAI: privacy_mode == "training_off"
|
||||||
|
// Antigravity: privacy_mode == "privacy_set"
|
||||||
|
// 其他平台: 无 privacy 概念,始终返回 true
|
||||||
|
func (a *Account) IsPrivacySet() bool {
|
||||||
|
switch a.Platform {
|
||||||
|
case PlatformOpenAI:
|
||||||
|
return a.getExtraString("privacy_mode") == PrivacyModeTrainingOff
|
||||||
|
case PlatformAntigravity:
|
||||||
|
return a.getExtraString("privacy_mode") == AntigravityPrivacySet
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Account) IsGemini() bool {
|
func (a *Account) IsGemini() bool {
|
||||||
return a.Platform == PlatformGemini
|
return a.Platform == PlatformGemini
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,6 +174,19 @@ func (s *AccountService) Create(ctx context.Context, req CreateAccountRequest) (
|
|||||||
return nil, fmt.Errorf("create account: %w", err)
|
return nil, fmt.Errorf("create account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// require_oauth_only 检查:apikey 类型账号不可加入限制分组
|
||||||
|
if account.Type == AccountTypeAPIKey && len(req.GroupIDs) > 0 {
|
||||||
|
for _, gid := range req.GroupIDs {
|
||||||
|
g, err := s.groupRepo.GetByID(ctx, gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if g.RequireOAuthOnly && (g.Platform == PlatformOpenAI || g.Platform == PlatformAntigravity || g.Platform == PlatformAnthropic || g.Platform == PlatformGemini) {
|
||||||
|
return nil, fmt.Errorf("分组 [%s] 仅允许 OAuth 账号,apikey 类型账号无法加入", g.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 绑定分组
|
// 绑定分组
|
||||||
if len(req.GroupIDs) > 0 {
|
if len(req.GroupIDs) > 0 {
|
||||||
if err := s.accountRepo.BindGroups(ctx, account.ID, req.GroupIDs); err != nil {
|
if err := s.accountRepo.BindGroups(ctx, account.ID, req.GroupIDs); err != nil {
|
||||||
@@ -277,6 +290,19 @@ func (s *AccountService) Update(ctx context.Context, id int64, req UpdateAccount
|
|||||||
return nil, fmt.Errorf("update account: %w", err)
|
return nil, fmt.Errorf("update account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// require_oauth_only 检查
|
||||||
|
if account.Type == AccountTypeAPIKey && req.GroupIDs != nil {
|
||||||
|
for _, gid := range *req.GroupIDs {
|
||||||
|
g, err := s.groupRepo.GetByID(ctx, gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if g.RequireOAuthOnly && (g.Platform == PlatformOpenAI || g.Platform == PlatformAntigravity || g.Platform == PlatformAnthropic || g.Platform == PlatformGemini) {
|
||||||
|
return nil, fmt.Errorf("分组 [%s] 仅允许 OAuth 账号,apikey 类型账号无法加入", g.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 绑定分组
|
// 绑定分组
|
||||||
if req.GroupIDs != nil {
|
if req.GroupIDs != nil {
|
||||||
if err := s.accountRepo.BindGroups(ctx, account.ID, *req.GroupIDs); err != nil {
|
if err := s.accountRepo.BindGroups(ctx, account.ID, *req.GroupIDs); err != nil {
|
||||||
|
|||||||
@@ -162,6 +162,8 @@ type CreateGroupInput struct {
|
|||||||
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
||||||
AllowMessagesDispatch bool
|
AllowMessagesDispatch bool
|
||||||
DefaultMappedModel string
|
DefaultMappedModel string
|
||||||
|
RequireOAuthOnly bool
|
||||||
|
RequirePrivacySet bool
|
||||||
// 从指定分组复制账号(创建分组后在同一事务内绑定)
|
// 从指定分组复制账号(创建分组后在同一事务内绑定)
|
||||||
CopyAccountsFromGroupIDs []int64
|
CopyAccountsFromGroupIDs []int64
|
||||||
}
|
}
|
||||||
@@ -201,6 +203,8 @@ type UpdateGroupInput struct {
|
|||||||
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
||||||
AllowMessagesDispatch *bool
|
AllowMessagesDispatch *bool
|
||||||
DefaultMappedModel *string
|
DefaultMappedModel *string
|
||||||
|
RequireOAuthOnly *bool
|
||||||
|
RequirePrivacySet *bool
|
||||||
// 从指定分组复制账号(同步操作:先清空当前分组的账号绑定,再绑定源分组的账号)
|
// 从指定分组复制账号(同步操作:先清空当前分组的账号绑定,再绑定源分组的账号)
|
||||||
CopyAccountsFromGroupIDs []int64
|
CopyAccountsFromGroupIDs []int64
|
||||||
}
|
}
|
||||||
@@ -941,12 +945,35 @@ func (s *adminServiceImpl) CreateGroup(ctx context.Context, input *CreateGroupIn
|
|||||||
SupportedModelScopes: input.SupportedModelScopes,
|
SupportedModelScopes: input.SupportedModelScopes,
|
||||||
SoraStorageQuotaBytes: input.SoraStorageQuotaBytes,
|
SoraStorageQuotaBytes: input.SoraStorageQuotaBytes,
|
||||||
AllowMessagesDispatch: input.AllowMessagesDispatch,
|
AllowMessagesDispatch: input.AllowMessagesDispatch,
|
||||||
|
RequireOAuthOnly: input.RequireOAuthOnly,
|
||||||
|
RequirePrivacySet: input.RequirePrivacySet,
|
||||||
DefaultMappedModel: input.DefaultMappedModel,
|
DefaultMappedModel: input.DefaultMappedModel,
|
||||||
}
|
}
|
||||||
if err := s.groupRepo.Create(ctx, group); err != nil {
|
if err := s.groupRepo.Create(ctx, group); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// require_oauth_only: 过滤掉 apikey 类型账号
|
||||||
|
if group.RequireOAuthOnly && (group.Platform == PlatformOpenAI || group.Platform == PlatformAntigravity || group.Platform == PlatformAnthropic || group.Platform == PlatformGemini) && len(accountIDsToCopy) > 0 {
|
||||||
|
accounts, err := s.accountRepo.GetByIDs(ctx, accountIDsToCopy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch accounts for oauth filter: %w", err)
|
||||||
|
}
|
||||||
|
oauthIDs := make(map[int64]struct{}, len(accounts))
|
||||||
|
for _, acc := range accounts {
|
||||||
|
if acc.Type != AccountTypeAPIKey {
|
||||||
|
oauthIDs[acc.ID] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var filtered []int64
|
||||||
|
for _, aid := range accountIDsToCopy {
|
||||||
|
if _, ok := oauthIDs[aid]; ok {
|
||||||
|
filtered = append(filtered, aid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accountIDsToCopy = filtered
|
||||||
|
}
|
||||||
|
|
||||||
// 如果有需要复制的账号,绑定到新分组
|
// 如果有需要复制的账号,绑定到新分组
|
||||||
if len(accountIDsToCopy) > 0 {
|
if len(accountIDsToCopy) > 0 {
|
||||||
if err := s.groupRepo.BindAccountsToGroup(ctx, group.ID, accountIDsToCopy); err != nil {
|
if err := s.groupRepo.BindAccountsToGroup(ctx, group.ID, accountIDsToCopy); err != nil {
|
||||||
@@ -1154,6 +1181,12 @@ func (s *adminServiceImpl) UpdateGroup(ctx context.Context, id int64, input *Upd
|
|||||||
if input.AllowMessagesDispatch != nil {
|
if input.AllowMessagesDispatch != nil {
|
||||||
group.AllowMessagesDispatch = *input.AllowMessagesDispatch
|
group.AllowMessagesDispatch = *input.AllowMessagesDispatch
|
||||||
}
|
}
|
||||||
|
if input.RequireOAuthOnly != nil {
|
||||||
|
group.RequireOAuthOnly = *input.RequireOAuthOnly
|
||||||
|
}
|
||||||
|
if input.RequirePrivacySet != nil {
|
||||||
|
group.RequirePrivacySet = *input.RequirePrivacySet
|
||||||
|
}
|
||||||
if input.DefaultMappedModel != nil {
|
if input.DefaultMappedModel != nil {
|
||||||
group.DefaultMappedModel = *input.DefaultMappedModel
|
group.DefaultMappedModel = *input.DefaultMappedModel
|
||||||
}
|
}
|
||||||
@@ -1201,6 +1234,27 @@ func (s *adminServiceImpl) UpdateGroup(ctx context.Context, id int64, input *Upd
|
|||||||
return nil, fmt.Errorf("failed to clear existing account bindings: %w", err)
|
return nil, fmt.Errorf("failed to clear existing account bindings: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// require_oauth_only: 过滤掉 apikey 类型账号
|
||||||
|
if group.RequireOAuthOnly && (group.Platform == PlatformOpenAI || group.Platform == PlatformAntigravity || group.Platform == PlatformAnthropic || group.Platform == PlatformGemini) && len(accountIDsToCopy) > 0 {
|
||||||
|
accounts, err := s.accountRepo.GetByIDs(ctx, accountIDsToCopy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch accounts for oauth filter: %w", err)
|
||||||
|
}
|
||||||
|
oauthIDs := make(map[int64]struct{}, len(accounts))
|
||||||
|
for _, acc := range accounts {
|
||||||
|
if acc.Type != AccountTypeAPIKey {
|
||||||
|
oauthIDs[acc.ID] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var filtered []int64
|
||||||
|
for _, aid := range accountIDsToCopy {
|
||||||
|
if _, ok := oauthIDs[aid]; ok {
|
||||||
|
filtered = append(filtered, aid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accountIDsToCopy = filtered
|
||||||
|
}
|
||||||
|
|
||||||
// 再绑定源分组的账号
|
// 再绑定源分组的账号
|
||||||
if len(accountIDsToCopy) > 0 {
|
if len(accountIDsToCopy) > 0 {
|
||||||
if err := s.groupRepo.BindAccountsToGroup(ctx, id, accountIDsToCopy); err != nil {
|
if err := s.groupRepo.BindAccountsToGroup(ctx, id, accountIDsToCopy); err != nil {
|
||||||
|
|||||||
@@ -3139,7 +3139,7 @@ func TestGatewayService_GroupResolution_ReusesContextGroup(t *testing.T) {
|
|||||||
account, err := svc.SelectAccountForModelWithExclusions(ctx, &groupID, "", "claude-3-5-sonnet-20241022", nil)
|
account, err := svc.SelectAccountForModelWithExclusions(ctx, &groupID, "", "claude-3-5-sonnet-20241022", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, account)
|
require.NotNil(t, account)
|
||||||
require.Equal(t, 0, groupRepo.getByIDCalls)
|
require.Equal(t, 1, groupRepo.getByIDCalls) // +1 for require_privacy_set check
|
||||||
require.Equal(t, 0, groupRepo.getByIDLiteCalls)
|
require.Equal(t, 0, groupRepo.getByIDLiteCalls)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3182,7 +3182,7 @@ func TestGatewayService_GroupResolution_IgnoresInvalidContextGroup(t *testing.T)
|
|||||||
account, err := svc.SelectAccountForModelWithExclusions(ctx, &groupID, "", "claude-3-5-sonnet-20241022", nil)
|
account, err := svc.SelectAccountForModelWithExclusions(ctx, &groupID, "", "claude-3-5-sonnet-20241022", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, account)
|
require.NotNil(t, account)
|
||||||
require.Equal(t, 0, groupRepo.getByIDCalls)
|
require.Equal(t, 1, groupRepo.getByIDCalls) // +1 for require_privacy_set check
|
||||||
require.Equal(t, 1, groupRepo.getByIDLiteCalls)
|
require.Equal(t, 1, groupRepo.getByIDLiteCalls)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3252,7 +3252,7 @@ func TestGatewayService_GroupResolution_FallbackUsesLiteOnce(t *testing.T) {
|
|||||||
account, err := svc.SelectAccountForModelWithExclusions(ctx, &groupID, "", "claude-3-5-sonnet-20241022", nil)
|
account, err := svc.SelectAccountForModelWithExclusions(ctx, &groupID, "", "claude-3-5-sonnet-20241022", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, account)
|
require.NotNil(t, account)
|
||||||
require.Equal(t, 0, groupRepo.getByIDCalls)
|
require.Equal(t, 1, groupRepo.getByIDCalls) // +1 for require_privacy_set check
|
||||||
require.Equal(t, 1, groupRepo.getByIDLiteCalls)
|
require.Equal(t, 1, groupRepo.getByIDLiteCalls)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2744,6 +2744,12 @@ func (s *GatewayService) selectAccountForModelWithPlatform(ctx context.Context,
|
|||||||
preferOAuth := platform == PlatformGemini
|
preferOAuth := platform == PlatformGemini
|
||||||
routingAccountIDs := s.routingAccountIDsForRequest(ctx, groupID, requestedModel, platform)
|
routingAccountIDs := s.routingAccountIDsForRequest(ctx, groupID, requestedModel, platform)
|
||||||
|
|
||||||
|
// require_privacy_set: 获取分组信息
|
||||||
|
var schedGroup *Group
|
||||||
|
if groupID != nil && s.groupRepo != nil {
|
||||||
|
schedGroup, _ = s.groupRepo.GetByID(ctx, *groupID)
|
||||||
|
}
|
||||||
|
|
||||||
var accounts []Account
|
var accounts []Account
|
||||||
accountsLoaded := false
|
accountsLoaded := false
|
||||||
|
|
||||||
@@ -2815,6 +2821,12 @@ func (s *GatewayService) selectAccountForModelWithPlatform(ctx context.Context,
|
|||||||
if !s.isAccountSchedulableForSelection(acc) {
|
if !s.isAccountSchedulableForSelection(acc) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// require_privacy_set: 跳过 privacy 未设置的账号并标记异常
|
||||||
|
if schedGroup != nil && schedGroup.RequirePrivacySet && !acc.IsPrivacySet() {
|
||||||
|
_ = s.accountRepo.SetError(ctx, acc.ID,
|
||||||
|
fmt.Sprintf("Privacy not set, required by group [%s]", schedGroup.Name))
|
||||||
|
continue
|
||||||
|
}
|
||||||
if requestedModel != "" && !s.isModelSupportedByAccountWithContext(ctx, acc, requestedModel) {
|
if requestedModel != "" && !s.isModelSupportedByAccountWithContext(ctx, acc, requestedModel) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -2917,6 +2929,12 @@ func (s *GatewayService) selectAccountForModelWithPlatform(ctx context.Context,
|
|||||||
if !s.isAccountSchedulableForSelection(acc) {
|
if !s.isAccountSchedulableForSelection(acc) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// require_privacy_set: 跳过 privacy 未设置的账号并标记异常
|
||||||
|
if schedGroup != nil && schedGroup.RequirePrivacySet && !acc.IsPrivacySet() {
|
||||||
|
_ = s.accountRepo.SetError(ctx, acc.ID,
|
||||||
|
fmt.Sprintf("Privacy not set, required by group [%s]", schedGroup.Name))
|
||||||
|
continue
|
||||||
|
}
|
||||||
if requestedModel != "" && !s.isModelSupportedByAccountWithContext(ctx, acc, requestedModel) {
|
if requestedModel != "" && !s.isModelSupportedByAccountWithContext(ctx, acc, requestedModel) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -2980,6 +2998,12 @@ func (s *GatewayService) selectAccountWithMixedScheduling(ctx context.Context, g
|
|||||||
preferOAuth := nativePlatform == PlatformGemini
|
preferOAuth := nativePlatform == PlatformGemini
|
||||||
routingAccountIDs := s.routingAccountIDsForRequest(ctx, groupID, requestedModel, nativePlatform)
|
routingAccountIDs := s.routingAccountIDsForRequest(ctx, groupID, requestedModel, nativePlatform)
|
||||||
|
|
||||||
|
// require_privacy_set: 获取分组信息
|
||||||
|
var schedGroup *Group
|
||||||
|
if groupID != nil && s.groupRepo != nil {
|
||||||
|
schedGroup, _ = s.groupRepo.GetByID(ctx, *groupID)
|
||||||
|
}
|
||||||
|
|
||||||
var accounts []Account
|
var accounts []Account
|
||||||
accountsLoaded := false
|
accountsLoaded := false
|
||||||
|
|
||||||
@@ -3047,6 +3071,12 @@ func (s *GatewayService) selectAccountWithMixedScheduling(ctx context.Context, g
|
|||||||
if !s.isAccountSchedulableForSelection(acc) {
|
if !s.isAccountSchedulableForSelection(acc) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// require_privacy_set: 跳过 privacy 未设置的账号并标记异常
|
||||||
|
if schedGroup != nil && schedGroup.RequirePrivacySet && !acc.IsPrivacySet() {
|
||||||
|
_ = s.accountRepo.SetError(ctx, acc.ID,
|
||||||
|
fmt.Sprintf("Privacy not set, required by group [%s]", schedGroup.Name))
|
||||||
|
continue
|
||||||
|
}
|
||||||
// 过滤:原生平台直接通过,antigravity 需要启用混合调度
|
// 过滤:原生平台直接通过,antigravity 需要启用混合调度
|
||||||
if acc.Platform == PlatformAntigravity && !acc.IsMixedSchedulingEnabled() {
|
if acc.Platform == PlatformAntigravity && !acc.IsMixedSchedulingEnabled() {
|
||||||
continue
|
continue
|
||||||
@@ -3151,6 +3181,12 @@ func (s *GatewayService) selectAccountWithMixedScheduling(ctx context.Context, g
|
|||||||
if !s.isAccountSchedulableForSelection(acc) {
|
if !s.isAccountSchedulableForSelection(acc) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// require_privacy_set: 跳过 privacy 未设置的账号并标记异常
|
||||||
|
if schedGroup != nil && schedGroup.RequirePrivacySet && !acc.IsPrivacySet() {
|
||||||
|
_ = s.accountRepo.SetError(ctx, acc.ID,
|
||||||
|
fmt.Sprintf("Privacy not set, required by group [%s]", schedGroup.Name))
|
||||||
|
continue
|
||||||
|
}
|
||||||
// 过滤:原生平台直接通过,antigravity 需要启用混合调度
|
// 过滤:原生平台直接通过,antigravity 需要启用混合调度
|
||||||
if acc.Platform == PlatformAntigravity && !acc.IsMixedSchedulingEnabled() {
|
if acc.Platform == PlatformAntigravity && !acc.IsMixedSchedulingEnabled() {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ type Group struct {
|
|||||||
|
|
||||||
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
||||||
AllowMessagesDispatch bool
|
AllowMessagesDispatch bool
|
||||||
|
RequireOAuthOnly bool // 仅允许非 apikey 类型账号关联(OpenAI/Antigravity/Anthropic/Gemini)
|
||||||
|
RequirePrivacySet bool // 调度时仅允许 privacy 已成功设置的账号(OpenAI/Antigravity/Anthropic/Gemini)
|
||||||
DefaultMappedModel string
|
DefaultMappedModel string
|
||||||
|
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"container/heap"
|
"container/heap"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
"math"
|
"math"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -575,6 +576,12 @@ func (s *defaultOpenAIAccountScheduler) selectByLoadBalance(
|
|||||||
return nil, 0, 0, 0, errors.New("no available OpenAI accounts")
|
return nil, 0, 0, 0, errors.New("no available OpenAI accounts")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// require_privacy_set: 获取分组信息
|
||||||
|
var schedGroup *Group
|
||||||
|
if req.GroupID != nil && s.service.schedulerSnapshot != nil {
|
||||||
|
schedGroup, _ = s.service.schedulerSnapshot.GetGroupByID(ctx, *req.GroupID)
|
||||||
|
}
|
||||||
|
|
||||||
filtered := make([]*Account, 0, len(accounts))
|
filtered := make([]*Account, 0, len(accounts))
|
||||||
loadReq := make([]AccountWithConcurrency, 0, len(accounts))
|
loadReq := make([]AccountWithConcurrency, 0, len(accounts))
|
||||||
for i := range accounts {
|
for i := range accounts {
|
||||||
@@ -587,6 +594,12 @@ func (s *defaultOpenAIAccountScheduler) selectByLoadBalance(
|
|||||||
if !account.IsSchedulable() || !account.IsOpenAI() {
|
if !account.IsSchedulable() || !account.IsOpenAI() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// require_privacy_set: 跳过 privacy 未设置的账号并标记异常
|
||||||
|
if schedGroup != nil && schedGroup.RequirePrivacySet && !account.IsPrivacySet() {
|
||||||
|
_ = s.service.accountRepo.SetError(ctx, account.ID,
|
||||||
|
fmt.Sprintf("Privacy not set, required by group [%s]", schedGroup.Name))
|
||||||
|
continue
|
||||||
|
}
|
||||||
if req.RequestedModel != "" && !account.IsModelSupported(req.RequestedModel) {
|
if req.RequestedModel != "" && !account.IsModelSupported(req.RequestedModel) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,6 +152,14 @@ func (s *SchedulerSnapshotService) GetAccount(ctx context.Context, accountID int
|
|||||||
return s.accountRepo.GetByID(fallbackCtx, accountID)
|
return s.accountRepo.GetByID(fallbackCtx, accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetGroupByID 获取分组信息(供调度器使用)
|
||||||
|
func (s *SchedulerSnapshotService) GetGroupByID(ctx context.Context, groupID int64) (*Group, error) {
|
||||||
|
if s.groupRepo == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return s.groupRepo.GetByID(ctx, groupID)
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateAccountInCache 立即更新 Redis 中单个账号的数据(用于模型限流后立即生效)
|
// UpdateAccountInCache 立即更新 Redis 中单个账号的数据(用于模型限流后立即生效)
|
||||||
func (s *SchedulerSnapshotService) UpdateAccountInCache(ctx context.Context, account *Account) error {
|
func (s *SchedulerSnapshotService) UpdateAccountInCache(ctx context.Context, account *Account) error {
|
||||||
if s.cache == nil || account == nil {
|
if s.cache == nil || account == nil {
|
||||||
|
|||||||
2
backend/migrations/081_add_group_account_filter.sql
Normal file
2
backend/migrations/081_add_group_account_filter.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE groups ADD COLUMN IF NOT EXISTS require_oauth_only BOOLEAN NOT NULL DEFAULT false;
|
||||||
|
ALTER TABLE groups ADD COLUMN IF NOT EXISTS require_privacy_set BOOLEAN NOT NULL DEFAULT false;
|
||||||
@@ -399,6 +399,8 @@ export interface Group {
|
|||||||
fallback_group_id_on_invalid_request: number | null
|
fallback_group_id_on_invalid_request: number | null
|
||||||
// OpenAI Messages 调度开关(用户侧需要此字段判断是否展示 Claude Code 教程)
|
// OpenAI Messages 调度开关(用户侧需要此字段判断是否展示 Claude Code 教程)
|
||||||
allow_messages_dispatch?: boolean
|
allow_messages_dispatch?: boolean
|
||||||
|
require_oauth_only: boolean
|
||||||
|
require_privacy_set: boolean
|
||||||
created_at: string
|
created_at: string
|
||||||
updated_at: string
|
updated_at: string
|
||||||
}
|
}
|
||||||
@@ -510,6 +512,8 @@ export interface CreateGroupRequest {
|
|||||||
mcp_xml_inject?: boolean
|
mcp_xml_inject?: boolean
|
||||||
simulate_claude_max_enabled?: boolean
|
simulate_claude_max_enabled?: boolean
|
||||||
supported_model_scopes?: string[]
|
supported_model_scopes?: string[]
|
||||||
|
require_oauth_only?: boolean
|
||||||
|
require_privacy_set?: boolean
|
||||||
// 从指定分组复制账号
|
// 从指定分组复制账号
|
||||||
copy_accounts_from_group_ids?: number[]
|
copy_accounts_from_group_ids?: number[]
|
||||||
}
|
}
|
||||||
@@ -539,6 +543,8 @@ export interface UpdateGroupRequest {
|
|||||||
mcp_xml_inject?: boolean
|
mcp_xml_inject?: boolean
|
||||||
simulate_claude_max_enabled?: boolean
|
simulate_claude_max_enabled?: boolean
|
||||||
supported_model_scopes?: string[]
|
supported_model_scopes?: string[]
|
||||||
|
require_oauth_only?: boolean
|
||||||
|
require_privacy_set?: boolean
|
||||||
copy_accounts_from_group_ids?: number[]
|
copy_accounts_from_group_ids?: number[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -792,6 +792,61 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 账号过滤控制 (OpenAI/Antigravity/Anthropic/Gemini) -->
|
||||||
|
<div v-if="['openai', 'antigravity', 'anthropic', 'gemini'].includes(createForm.platform)" class="border-t border-gray-200 dark:border-dark-400 pt-4 mt-4 space-y-4">
|
||||||
|
<h4 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">账号过滤控制</h4>
|
||||||
|
|
||||||
|
<!-- require_oauth_only toggle -->
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-600 dark:text-gray-400">仅允许 OAuth 账号</label>
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
|
||||||
|
{{ createForm.require_oauth_only ? '已启用 — 排除 API Key 类型账号' : '未启用' }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="createForm.require_oauth_only = !createForm.require_oauth_only"
|
||||||
|
class="relative inline-flex h-6 w-12 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none"
|
||||||
|
:class="
|
||||||
|
createForm.require_oauth_only ? 'bg-primary-500' : 'bg-gray-300 dark:bg-dark-600'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
|
||||||
|
:class="
|
||||||
|
createForm.require_oauth_only ? 'translate-x-6' : 'translate-x-1'
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- require_privacy_set toggle -->
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-600 dark:text-gray-400">仅允许隐私保护已设置的账号</label>
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
|
||||||
|
{{ createForm.require_privacy_set ? '已启用 — Privacy 未设置的账号将被排除' : '未启用' }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="createForm.require_privacy_set = !createForm.require_privacy_set"
|
||||||
|
class="relative inline-flex h-6 w-12 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none"
|
||||||
|
:class="
|
||||||
|
createForm.require_privacy_set ? 'bg-primary-500' : 'bg-gray-300 dark:bg-dark-600'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
|
||||||
|
:class="
|
||||||
|
createForm.require_privacy_set ? 'translate-x-6' : 'translate-x-1'
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 无效请求兜底(仅 anthropic/antigravity 平台,且非订阅分组) -->
|
<!-- 无效请求兜底(仅 anthropic/antigravity 平台,且非订阅分组) -->
|
||||||
<div
|
<div
|
||||||
v-if="['anthropic', 'antigravity'].includes(createForm.platform) && createForm.subscription_type !== 'subscription'"
|
v-if="['anthropic', 'antigravity'].includes(createForm.platform) && createForm.subscription_type !== 'subscription'"
|
||||||
@@ -1527,6 +1582,61 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 账号过滤控制 (OpenAI/Antigravity/Anthropic/Gemini) -->
|
||||||
|
<div v-if="['openai', 'antigravity', 'anthropic', 'gemini'].includes(editForm.platform)" class="border-t border-gray-200 dark:border-dark-400 pt-4 mt-4 space-y-4">
|
||||||
|
<h4 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">账号过滤控制</h4>
|
||||||
|
|
||||||
|
<!-- require_oauth_only toggle -->
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-600 dark:text-gray-400">仅允许 OAuth 账号</label>
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
|
||||||
|
{{ editForm.require_oauth_only ? '已启用 — 排除 API Key 类型账号' : '未启用' }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="editForm.require_oauth_only = !editForm.require_oauth_only"
|
||||||
|
class="relative inline-flex h-6 w-12 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none"
|
||||||
|
:class="
|
||||||
|
editForm.require_oauth_only ? 'bg-primary-500' : 'bg-gray-300 dark:bg-dark-600'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
|
||||||
|
:class="
|
||||||
|
editForm.require_oauth_only ? 'translate-x-6' : 'translate-x-1'
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- require_privacy_set toggle -->
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<label class="text-sm text-gray-600 dark:text-gray-400">仅允许隐私保护已设置的账号</label>
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
|
||||||
|
{{ editForm.require_privacy_set ? '已启用 — Privacy 未设置的账号将被排除' : '未启用' }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="editForm.require_privacy_set = !editForm.require_privacy_set"
|
||||||
|
class="relative inline-flex h-6 w-12 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none"
|
||||||
|
:class="
|
||||||
|
editForm.require_privacy_set ? 'bg-primary-500' : 'bg-gray-300 dark:bg-dark-600'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
|
||||||
|
:class="
|
||||||
|
editForm.require_privacy_set ? 'translate-x-6' : 'translate-x-1'
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 无效请求兜底(仅 anthropic/antigravity 平台,且非订阅分组) -->
|
<!-- 无效请求兜底(仅 anthropic/antigravity 平台,且非订阅分组) -->
|
||||||
<div
|
<div
|
||||||
v-if="['anthropic', 'antigravity'].includes(editForm.platform) && editForm.subscription_type !== 'subscription'"
|
v-if="['anthropic', 'antigravity'].includes(editForm.platform) && editForm.subscription_type !== 'subscription'"
|
||||||
@@ -2063,6 +2173,9 @@ const createForm = reactive({
|
|||||||
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
||||||
allow_messages_dispatch: false,
|
allow_messages_dispatch: false,
|
||||||
default_mapped_model: 'gpt-5.4',
|
default_mapped_model: 'gpt-5.4',
|
||||||
|
// 账号过滤控制(OpenAI/Antigravity 平台)
|
||||||
|
require_oauth_only: false,
|
||||||
|
require_privacy_set: false,
|
||||||
// 模型路由开关
|
// 模型路由开关
|
||||||
model_routing_enabled: false,
|
model_routing_enabled: false,
|
||||||
// 支持的模型系列(仅 antigravity 平台)
|
// 支持的模型系列(仅 antigravity 平台)
|
||||||
@@ -2307,6 +2420,9 @@ const editForm = reactive({
|
|||||||
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
// OpenAI Messages 调度配置(仅 openai 平台使用)
|
||||||
allow_messages_dispatch: false,
|
allow_messages_dispatch: false,
|
||||||
default_mapped_model: '',
|
default_mapped_model: '',
|
||||||
|
// 账号过滤控制(OpenAI/Antigravity 平台)
|
||||||
|
require_oauth_only: false,
|
||||||
|
require_privacy_set: false,
|
||||||
// 模型路由开关
|
// 模型路由开关
|
||||||
model_routing_enabled: false,
|
model_routing_enabled: false,
|
||||||
// 支持的模型系列(仅 antigravity 平台)
|
// 支持的模型系列(仅 antigravity 平台)
|
||||||
@@ -2452,6 +2568,8 @@ const closeCreateModal = () => {
|
|||||||
createForm.fallback_group_id = null
|
createForm.fallback_group_id = null
|
||||||
createForm.fallback_group_id_on_invalid_request = null
|
createForm.fallback_group_id_on_invalid_request = null
|
||||||
createForm.allow_messages_dispatch = false
|
createForm.allow_messages_dispatch = false
|
||||||
|
createForm.require_oauth_only = false
|
||||||
|
createForm.require_privacy_set = false
|
||||||
createForm.default_mapped_model = 'gpt-5.4'
|
createForm.default_mapped_model = 'gpt-5.4'
|
||||||
createForm.supported_model_scopes = ['claude', 'gemini_text', 'gemini_image']
|
createForm.supported_model_scopes = ['claude', 'gemini_text', 'gemini_image']
|
||||||
createForm.mcp_xml_inject = true
|
createForm.mcp_xml_inject = true
|
||||||
@@ -2539,6 +2657,8 @@ const handleEdit = async (group: AdminGroup) => {
|
|||||||
editForm.fallback_group_id = group.fallback_group_id
|
editForm.fallback_group_id = group.fallback_group_id
|
||||||
editForm.fallback_group_id_on_invalid_request = group.fallback_group_id_on_invalid_request
|
editForm.fallback_group_id_on_invalid_request = group.fallback_group_id_on_invalid_request
|
||||||
editForm.allow_messages_dispatch = group.allow_messages_dispatch || false
|
editForm.allow_messages_dispatch = group.allow_messages_dispatch || false
|
||||||
|
editForm.require_oauth_only = group.require_oauth_only ?? false
|
||||||
|
editForm.require_privacy_set = group.require_privacy_set ?? false
|
||||||
editForm.default_mapped_model = group.default_mapped_model || ''
|
editForm.default_mapped_model = group.default_mapped_model || ''
|
||||||
editForm.model_routing_enabled = group.model_routing_enabled || false
|
editForm.model_routing_enabled = group.model_routing_enabled || false
|
||||||
editForm.supported_model_scopes = group.supported_model_scopes || ['claude', 'gemini_text', 'gemini_image']
|
editForm.supported_model_scopes = group.supported_model_scopes || ['claude', 'gemini_text', 'gemini_image']
|
||||||
@@ -2647,6 +2767,10 @@ watch(
|
|||||||
createForm.allow_messages_dispatch = false
|
createForm.allow_messages_dispatch = false
|
||||||
createForm.default_mapped_model = ''
|
createForm.default_mapped_model = ''
|
||||||
}
|
}
|
||||||
|
if (!['openai', 'antigravity', 'anthropic', 'gemini'].includes(newVal)) {
|
||||||
|
createForm.require_oauth_only = false
|
||||||
|
createForm.require_privacy_set = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user