Commit f694afbb authored by erio's avatar erio
Browse files

feat(notify): add percentage threshold type for balance low notification

- Add threshold_type field (fixed/percentage) to system and user settings
- Add total_recharged field to users table, auto-incremented on balance credit
- Percentage mode: effective threshold = total_recharged × percentage / 100
- User-level threshold_type inherits from system default when not set
- Update admin settings UI with radio selector (fixed amount / percentage)
- Migration: 102_add_balance_notify_threshold_type.sql
parent d0674e0f
...@@ -1079,8 +1079,10 @@ var ( ...@@ -1079,8 +1079,10 @@ var (
{Name: "totp_enabled", Type: field.TypeBool, Default: false}, {Name: "totp_enabled", Type: field.TypeBool, Default: false},
{Name: "totp_enabled_at", Type: field.TypeTime, Nullable: true}, {Name: "totp_enabled_at", Type: field.TypeTime, Nullable: true},
{Name: "balance_notify_enabled", Type: field.TypeBool, Default: true}, {Name: "balance_notify_enabled", Type: field.TypeBool, Default: true},
{Name: "balance_notify_threshold_type", Type: field.TypeString, Default: "fixed"},
{Name: "balance_notify_threshold", Type: field.TypeFloat64, Nullable: true, SchemaType: map[string]string{"postgres": "decimal(20,8)"}}, {Name: "balance_notify_threshold", Type: field.TypeFloat64, Nullable: true, SchemaType: map[string]string{"postgres": "decimal(20,8)"}},
{Name: "balance_notify_extra_emails", Type: field.TypeString, Default: "[]", SchemaType: map[string]string{"postgres": "text"}}, {Name: "balance_notify_extra_emails", Type: field.TypeString, Default: "[]", SchemaType: map[string]string{"postgres": "text"}},
{Name: "total_recharged", Type: field.TypeFloat64, Default: 0, SchemaType: map[string]string{"postgres": "decimal(20,8)"}},
} }
// UsersTable holds the schema information for the "users" table. // UsersTable holds the schema information for the "users" table.
UsersTable = &schema.Table{ UsersTable = &schema.Table{
......
...@@ -28211,9 +28211,12 @@ type UserMutation struct { ...@@ -28211,9 +28211,12 @@ type UserMutation struct {
totp_enabled *bool totp_enabled *bool
totp_enabled_at *time.Time totp_enabled_at *time.Time
balance_notify_enabled *bool balance_notify_enabled *bool
balance_notify_threshold_type *string
balance_notify_threshold *float64 balance_notify_threshold *float64
addbalance_notify_threshold *float64 addbalance_notify_threshold *float64
balance_notify_extra_emails *string balance_notify_extra_emails *string
total_recharged *float64
addtotal_recharged *float64
clearedFields map[string]struct{} clearedFields map[string]struct{}
api_keys map[int64]struct{} api_keys map[int64]struct{}
removedapi_keys map[int64]struct{} removedapi_keys map[int64]struct{}
...@@ -28967,6 +28970,42 @@ func (m *UserMutation) ResetBalanceNotifyEnabled() { ...@@ -28967,6 +28970,42 @@ func (m *UserMutation) ResetBalanceNotifyEnabled() {
m.balance_notify_enabled = nil m.balance_notify_enabled = nil
} }
   
// SetBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field.
func (m *UserMutation) SetBalanceNotifyThresholdType(s string) {
m.balance_notify_threshold_type = &s
}
// BalanceNotifyThresholdType returns the value of the "balance_notify_threshold_type" field in the mutation.
func (m *UserMutation) BalanceNotifyThresholdType() (r string, exists bool) {
v := m.balance_notify_threshold_type
if v == nil {
return
}
return *v, true
}
// OldBalanceNotifyThresholdType returns the old "balance_notify_threshold_type" field's value of the User entity.
// If the User 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 *UserMutation) OldBalanceNotifyThresholdType(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldBalanceNotifyThresholdType is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldBalanceNotifyThresholdType requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldBalanceNotifyThresholdType: %w", err)
}
return oldValue.BalanceNotifyThresholdType, nil
}
// ResetBalanceNotifyThresholdType resets all changes to the "balance_notify_threshold_type" field.
func (m *UserMutation) ResetBalanceNotifyThresholdType() {
m.balance_notify_threshold_type = nil
}
// SetBalanceNotifyThreshold sets the "balance_notify_threshold" field. // SetBalanceNotifyThreshold sets the "balance_notify_threshold" field.
func (m *UserMutation) SetBalanceNotifyThreshold(f float64) { func (m *UserMutation) SetBalanceNotifyThreshold(f float64) {
m.balance_notify_threshold = &f m.balance_notify_threshold = &f
...@@ -29073,6 +29112,62 @@ func (m *UserMutation) ResetBalanceNotifyExtraEmails() { ...@@ -29073,6 +29112,62 @@ func (m *UserMutation) ResetBalanceNotifyExtraEmails() {
m.balance_notify_extra_emails = nil m.balance_notify_extra_emails = nil
} }
   
// SetTotalRecharged sets the "total_recharged" field.
func (m *UserMutation) SetTotalRecharged(f float64) {
m.total_recharged = &f
m.addtotal_recharged = nil
}
// TotalRecharged returns the value of the "total_recharged" field in the mutation.
func (m *UserMutation) TotalRecharged() (r float64, exists bool) {
v := m.total_recharged
if v == nil {
return
}
return *v, true
}
// OldTotalRecharged returns the old "total_recharged" field's value of the User entity.
// If the User 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 *UserMutation) OldTotalRecharged(ctx context.Context) (v float64, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldTotalRecharged is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldTotalRecharged requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldTotalRecharged: %w", err)
}
return oldValue.TotalRecharged, nil
}
// AddTotalRecharged adds f to the "total_recharged" field.
func (m *UserMutation) AddTotalRecharged(f float64) {
if m.addtotal_recharged != nil {
*m.addtotal_recharged += f
} else {
m.addtotal_recharged = &f
}
}
// AddedTotalRecharged returns the value that was added to the "total_recharged" field in this mutation.
func (m *UserMutation) AddedTotalRecharged() (r float64, exists bool) {
v := m.addtotal_recharged
if v == nil {
return
}
return *v, true
}
// ResetTotalRecharged resets all changes to the "total_recharged" field.
func (m *UserMutation) ResetTotalRecharged() {
m.total_recharged = nil
m.addtotal_recharged = nil
}
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by ids. // AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by ids.
func (m *UserMutation) AddAPIKeyIDs(ids ...int64) { func (m *UserMutation) AddAPIKeyIDs(ids ...int64) {
if m.api_keys == nil { if m.api_keys == nil {
...@@ -29647,7 +29742,7 @@ func (m *UserMutation) Type() string { ...@@ -29647,7 +29742,7 @@ func (m *UserMutation) 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 *UserMutation) Fields() []string { func (m *UserMutation) Fields() []string {
fields := make([]string, 0, 17) fields := make([]string, 0, 19)
if m.created_at != nil { if m.created_at != nil {
fields = append(fields, user.FieldCreatedAt) fields = append(fields, user.FieldCreatedAt)
} }
...@@ -29693,12 +29788,18 @@ func (m *UserMutation) Fields() []string { ...@@ -29693,12 +29788,18 @@ func (m *UserMutation) Fields() []string {
if m.balance_notify_enabled != nil { if m.balance_notify_enabled != nil {
fields = append(fields, user.FieldBalanceNotifyEnabled) fields = append(fields, user.FieldBalanceNotifyEnabled)
} }
if m.balance_notify_threshold_type != nil {
fields = append(fields, user.FieldBalanceNotifyThresholdType)
}
if m.balance_notify_threshold != nil { if m.balance_notify_threshold != nil {
fields = append(fields, user.FieldBalanceNotifyThreshold) fields = append(fields, user.FieldBalanceNotifyThreshold)
} }
if m.balance_notify_extra_emails != nil { if m.balance_notify_extra_emails != nil {
fields = append(fields, user.FieldBalanceNotifyExtraEmails) fields = append(fields, user.FieldBalanceNotifyExtraEmails)
} }
if m.total_recharged != nil {
fields = append(fields, user.FieldTotalRecharged)
}
return fields return fields
} }
   
...@@ -29737,10 +29838,14 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) { ...@@ -29737,10 +29838,14 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) {
return m.TotpEnabledAt() return m.TotpEnabledAt()
case user.FieldBalanceNotifyEnabled: case user.FieldBalanceNotifyEnabled:
return m.BalanceNotifyEnabled() return m.BalanceNotifyEnabled()
case user.FieldBalanceNotifyThresholdType:
return m.BalanceNotifyThresholdType()
case user.FieldBalanceNotifyThreshold: case user.FieldBalanceNotifyThreshold:
return m.BalanceNotifyThreshold() return m.BalanceNotifyThreshold()
case user.FieldBalanceNotifyExtraEmails: case user.FieldBalanceNotifyExtraEmails:
return m.BalanceNotifyExtraEmails() return m.BalanceNotifyExtraEmails()
case user.FieldTotalRecharged:
return m.TotalRecharged()
} }
return nil, false return nil, false
} }
...@@ -29780,10 +29885,14 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er ...@@ -29780,10 +29885,14 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er
return m.OldTotpEnabledAt(ctx) return m.OldTotpEnabledAt(ctx)
case user.FieldBalanceNotifyEnabled: case user.FieldBalanceNotifyEnabled:
return m.OldBalanceNotifyEnabled(ctx) return m.OldBalanceNotifyEnabled(ctx)
case user.FieldBalanceNotifyThresholdType:
return m.OldBalanceNotifyThresholdType(ctx)
case user.FieldBalanceNotifyThreshold: case user.FieldBalanceNotifyThreshold:
return m.OldBalanceNotifyThreshold(ctx) return m.OldBalanceNotifyThreshold(ctx)
case user.FieldBalanceNotifyExtraEmails: case user.FieldBalanceNotifyExtraEmails:
return m.OldBalanceNotifyExtraEmails(ctx) return m.OldBalanceNotifyExtraEmails(ctx)
case user.FieldTotalRecharged:
return m.OldTotalRecharged(ctx)
} }
return nil, fmt.Errorf("unknown User field %s", name) return nil, fmt.Errorf("unknown User field %s", name)
} }
...@@ -29898,6 +30007,13 @@ func (m *UserMutation) SetField(name string, value ent.Value) error { ...@@ -29898,6 +30007,13 @@ func (m *UserMutation) SetField(name string, value ent.Value) error {
} }
m.SetBalanceNotifyEnabled(v) m.SetBalanceNotifyEnabled(v)
return nil return nil
case user.FieldBalanceNotifyThresholdType:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetBalanceNotifyThresholdType(v)
return nil
case user.FieldBalanceNotifyThreshold: case user.FieldBalanceNotifyThreshold:
v, ok := value.(float64) v, ok := value.(float64)
if !ok { if !ok {
...@@ -29912,6 +30028,13 @@ func (m *UserMutation) SetField(name string, value ent.Value) error { ...@@ -29912,6 +30028,13 @@ func (m *UserMutation) SetField(name string, value ent.Value) error {
} }
m.SetBalanceNotifyExtraEmails(v) m.SetBalanceNotifyExtraEmails(v)
return nil return nil
case user.FieldTotalRecharged:
v, ok := value.(float64)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetTotalRecharged(v)
return nil
} }
return fmt.Errorf("unknown User field %s", name) return fmt.Errorf("unknown User field %s", name)
} }
...@@ -29929,6 +30052,9 @@ func (m *UserMutation) AddedFields() []string { ...@@ -29929,6 +30052,9 @@ func (m *UserMutation) AddedFields() []string {
if m.addbalance_notify_threshold != nil { if m.addbalance_notify_threshold != nil {
fields = append(fields, user.FieldBalanceNotifyThreshold) fields = append(fields, user.FieldBalanceNotifyThreshold)
} }
if m.addtotal_recharged != nil {
fields = append(fields, user.FieldTotalRecharged)
}
return fields return fields
} }
   
...@@ -29943,6 +30069,8 @@ func (m *UserMutation) AddedField(name string) (ent.Value, bool) { ...@@ -29943,6 +30069,8 @@ func (m *UserMutation) AddedField(name string) (ent.Value, bool) {
return m.AddedConcurrency() return m.AddedConcurrency()
case user.FieldBalanceNotifyThreshold: case user.FieldBalanceNotifyThreshold:
return m.AddedBalanceNotifyThreshold() return m.AddedBalanceNotifyThreshold()
case user.FieldTotalRecharged:
return m.AddedTotalRecharged()
} }
return nil, false return nil, false
} }
...@@ -29973,6 +30101,13 @@ func (m *UserMutation) AddField(name string, value ent.Value) error { ...@@ -29973,6 +30101,13 @@ func (m *UserMutation) AddField(name string, value ent.Value) error {
} }
m.AddBalanceNotifyThreshold(v) m.AddBalanceNotifyThreshold(v)
return nil return nil
case user.FieldTotalRecharged:
v, ok := value.(float64)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.AddTotalRecharged(v)
return nil
} }
return fmt.Errorf("unknown User numeric field %s", name) return fmt.Errorf("unknown User numeric field %s", name)
} }
...@@ -30072,12 +30207,18 @@ func (m *UserMutation) ResetField(name string) error { ...@@ -30072,12 +30207,18 @@ func (m *UserMutation) ResetField(name string) error {
case user.FieldBalanceNotifyEnabled: case user.FieldBalanceNotifyEnabled:
m.ResetBalanceNotifyEnabled() m.ResetBalanceNotifyEnabled()
return nil return nil
case user.FieldBalanceNotifyThresholdType:
m.ResetBalanceNotifyThresholdType()
return nil
case user.FieldBalanceNotifyThreshold: case user.FieldBalanceNotifyThreshold:
m.ResetBalanceNotifyThreshold() m.ResetBalanceNotifyThreshold()
return nil return nil
case user.FieldBalanceNotifyExtraEmails: case user.FieldBalanceNotifyExtraEmails:
m.ResetBalanceNotifyExtraEmails() m.ResetBalanceNotifyExtraEmails()
return nil return nil
case user.FieldTotalRecharged:
m.ResetTotalRecharged()
return nil
} }
return fmt.Errorf("unknown User field %s", name) return fmt.Errorf("unknown User field %s", name)
} }
...@@ -1297,10 +1297,18 @@ func init() { ...@@ -1297,10 +1297,18 @@ func init() {
userDescBalanceNotifyEnabled := userFields[11].Descriptor() userDescBalanceNotifyEnabled := userFields[11].Descriptor()
// user.DefaultBalanceNotifyEnabled holds the default value on creation for the balance_notify_enabled field. // user.DefaultBalanceNotifyEnabled holds the default value on creation for the balance_notify_enabled field.
user.DefaultBalanceNotifyEnabled = userDescBalanceNotifyEnabled.Default.(bool) user.DefaultBalanceNotifyEnabled = userDescBalanceNotifyEnabled.Default.(bool)
// userDescBalanceNotifyThresholdType is the schema descriptor for balance_notify_threshold_type field.
userDescBalanceNotifyThresholdType := userFields[12].Descriptor()
// user.DefaultBalanceNotifyThresholdType holds the default value on creation for the balance_notify_threshold_type field.
user.DefaultBalanceNotifyThresholdType = userDescBalanceNotifyThresholdType.Default.(string)
// userDescBalanceNotifyExtraEmails is the schema descriptor for balance_notify_extra_emails field. // userDescBalanceNotifyExtraEmails is the schema descriptor for balance_notify_extra_emails field.
userDescBalanceNotifyExtraEmails := userFields[13].Descriptor() userDescBalanceNotifyExtraEmails := userFields[14].Descriptor()
// user.DefaultBalanceNotifyExtraEmails holds the default value on creation for the balance_notify_extra_emails field. // user.DefaultBalanceNotifyExtraEmails holds the default value on creation for the balance_notify_extra_emails field.
user.DefaultBalanceNotifyExtraEmails = userDescBalanceNotifyExtraEmails.Default.(string) user.DefaultBalanceNotifyExtraEmails = userDescBalanceNotifyExtraEmails.Default.(string)
// userDescTotalRecharged is the schema descriptor for total_recharged field.
userDescTotalRecharged := userFields[15].Descriptor()
// user.DefaultTotalRecharged holds the default value on creation for the total_recharged field.
user.DefaultTotalRecharged = userDescTotalRecharged.Default.(float64)
userallowedgroupFields := schema.UserAllowedGroup{}.Fields() userallowedgroupFields := schema.UserAllowedGroup{}.Fields()
_ = userallowedgroupFields _ = userallowedgroupFields
// userallowedgroupDescCreatedAt is the schema descriptor for created_at field. // userallowedgroupDescCreatedAt is the schema descriptor for created_at field.
......
...@@ -76,6 +76,8 @@ func (User) Fields() []ent.Field { ...@@ -76,6 +76,8 @@ func (User) Fields() []ent.Field {
// 余额不足通知 // 余额不足通知
field.Bool("balance_notify_enabled"). field.Bool("balance_notify_enabled").
Default(true), Default(true),
field.String("balance_notify_threshold_type").
Default("fixed"), // "fixed" | "percentage"
field.Float("balance_notify_threshold"). field.Float("balance_notify_threshold").
SchemaType(map[string]string{dialect.Postgres: "decimal(20,8)"}). SchemaType(map[string]string{dialect.Postgres: "decimal(20,8)"}).
Optional(). Optional().
...@@ -83,6 +85,9 @@ func (User) Fields() []ent.Field { ...@@ -83,6 +85,9 @@ func (User) Fields() []ent.Field {
field.String("balance_notify_extra_emails"). field.String("balance_notify_extra_emails").
SchemaType(map[string]string{dialect.Postgres: "text"}). SchemaType(map[string]string{dialect.Postgres: "text"}).
Default("[]"), Default("[]"),
field.Float("total_recharged").
SchemaType(map[string]string{dialect.Postgres: "decimal(20,8)"}).
Default(0),
} }
} }
......
...@@ -47,10 +47,14 @@ type User struct { ...@@ -47,10 +47,14 @@ type User struct {
TotpEnabledAt *time.Time `json:"totp_enabled_at,omitempty"` TotpEnabledAt *time.Time `json:"totp_enabled_at,omitempty"`
// BalanceNotifyEnabled holds the value of the "balance_notify_enabled" field. // BalanceNotifyEnabled holds the value of the "balance_notify_enabled" field.
BalanceNotifyEnabled bool `json:"balance_notify_enabled,omitempty"` BalanceNotifyEnabled bool `json:"balance_notify_enabled,omitempty"`
// BalanceNotifyThresholdType holds the value of the "balance_notify_threshold_type" field.
BalanceNotifyThresholdType string `json:"balance_notify_threshold_type,omitempty"`
// BalanceNotifyThreshold holds the value of the "balance_notify_threshold" field. // BalanceNotifyThreshold holds the value of the "balance_notify_threshold" field.
BalanceNotifyThreshold *float64 `json:"balance_notify_threshold,omitempty"` BalanceNotifyThreshold *float64 `json:"balance_notify_threshold,omitempty"`
// BalanceNotifyExtraEmails holds the value of the "balance_notify_extra_emails" field. // BalanceNotifyExtraEmails holds the value of the "balance_notify_extra_emails" field.
BalanceNotifyExtraEmails string `json:"balance_notify_extra_emails,omitempty"` BalanceNotifyExtraEmails string `json:"balance_notify_extra_emails,omitempty"`
// TotalRecharged holds the value of the "total_recharged" field.
TotalRecharged float64 `json:"total_recharged,omitempty"`
// Edges holds the relations/edges for other nodes in the graph. // Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the UserQuery when eager-loading is set. // The values are being populated by the UserQuery when eager-loading is set.
Edges UserEdges `json:"edges"` Edges UserEdges `json:"edges"`
...@@ -192,11 +196,11 @@ func (*User) scanValues(columns []string) ([]any, error) { ...@@ -192,11 +196,11 @@ func (*User) scanValues(columns []string) ([]any, error) {
switch columns[i] { switch columns[i] {
case user.FieldTotpEnabled, user.FieldBalanceNotifyEnabled: case user.FieldTotpEnabled, user.FieldBalanceNotifyEnabled:
values[i] = new(sql.NullBool) values[i] = new(sql.NullBool)
case user.FieldBalance, user.FieldBalanceNotifyThreshold: case user.FieldBalance, user.FieldBalanceNotifyThreshold, user.FieldTotalRecharged:
values[i] = new(sql.NullFloat64) values[i] = new(sql.NullFloat64)
case user.FieldID, user.FieldConcurrency: case user.FieldID, user.FieldConcurrency:
values[i] = new(sql.NullInt64) values[i] = new(sql.NullInt64)
case user.FieldEmail, user.FieldPasswordHash, user.FieldRole, user.FieldStatus, user.FieldUsername, user.FieldNotes, user.FieldTotpSecretEncrypted, user.FieldBalanceNotifyExtraEmails: case user.FieldEmail, user.FieldPasswordHash, user.FieldRole, user.FieldStatus, user.FieldUsername, user.FieldNotes, user.FieldTotpSecretEncrypted, user.FieldBalanceNotifyThresholdType, user.FieldBalanceNotifyExtraEmails:
values[i] = new(sql.NullString) values[i] = new(sql.NullString)
case user.FieldCreatedAt, user.FieldUpdatedAt, user.FieldDeletedAt, user.FieldTotpEnabledAt: case user.FieldCreatedAt, user.FieldUpdatedAt, user.FieldDeletedAt, user.FieldTotpEnabledAt:
values[i] = new(sql.NullTime) values[i] = new(sql.NullTime)
...@@ -314,6 +318,12 @@ func (_m *User) assignValues(columns []string, values []any) error { ...@@ -314,6 +318,12 @@ func (_m *User) assignValues(columns []string, values []any) error {
} else if value.Valid { } else if value.Valid {
_m.BalanceNotifyEnabled = value.Bool _m.BalanceNotifyEnabled = value.Bool
} }
case user.FieldBalanceNotifyThresholdType:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field balance_notify_threshold_type", values[i])
} else if value.Valid {
_m.BalanceNotifyThresholdType = value.String
}
case user.FieldBalanceNotifyThreshold: case user.FieldBalanceNotifyThreshold:
if value, ok := values[i].(*sql.NullFloat64); !ok { if value, ok := values[i].(*sql.NullFloat64); !ok {
return fmt.Errorf("unexpected type %T for field balance_notify_threshold", values[i]) return fmt.Errorf("unexpected type %T for field balance_notify_threshold", values[i])
...@@ -327,6 +337,12 @@ func (_m *User) assignValues(columns []string, values []any) error { ...@@ -327,6 +337,12 @@ func (_m *User) assignValues(columns []string, values []any) error {
} else if value.Valid { } else if value.Valid {
_m.BalanceNotifyExtraEmails = value.String _m.BalanceNotifyExtraEmails = value.String
} }
case user.FieldTotalRecharged:
if value, ok := values[i].(*sql.NullFloat64); !ok {
return fmt.Errorf("unexpected type %T for field total_recharged", values[i])
} else if value.Valid {
_m.TotalRecharged = value.Float64
}
default: default:
_m.selectValues.Set(columns[i], values[i]) _m.selectValues.Set(columns[i], values[i])
} }
...@@ -469,6 +485,9 @@ func (_m *User) String() string { ...@@ -469,6 +485,9 @@ func (_m *User) String() string {
builder.WriteString("balance_notify_enabled=") builder.WriteString("balance_notify_enabled=")
builder.WriteString(fmt.Sprintf("%v", _m.BalanceNotifyEnabled)) builder.WriteString(fmt.Sprintf("%v", _m.BalanceNotifyEnabled))
builder.WriteString(", ") builder.WriteString(", ")
builder.WriteString("balance_notify_threshold_type=")
builder.WriteString(_m.BalanceNotifyThresholdType)
builder.WriteString(", ")
if v := _m.BalanceNotifyThreshold; v != nil { if v := _m.BalanceNotifyThreshold; v != nil {
builder.WriteString("balance_notify_threshold=") builder.WriteString("balance_notify_threshold=")
builder.WriteString(fmt.Sprintf("%v", *v)) builder.WriteString(fmt.Sprintf("%v", *v))
...@@ -476,6 +495,9 @@ func (_m *User) String() string { ...@@ -476,6 +495,9 @@ func (_m *User) String() string {
builder.WriteString(", ") builder.WriteString(", ")
builder.WriteString("balance_notify_extra_emails=") builder.WriteString("balance_notify_extra_emails=")
builder.WriteString(_m.BalanceNotifyExtraEmails) builder.WriteString(_m.BalanceNotifyExtraEmails)
builder.WriteString(", ")
builder.WriteString("total_recharged=")
builder.WriteString(fmt.Sprintf("%v", _m.TotalRecharged))
builder.WriteByte(')') builder.WriteByte(')')
return builder.String() return builder.String()
} }
......
...@@ -45,10 +45,14 @@ const ( ...@@ -45,10 +45,14 @@ const (
FieldTotpEnabledAt = "totp_enabled_at" FieldTotpEnabledAt = "totp_enabled_at"
// FieldBalanceNotifyEnabled holds the string denoting the balance_notify_enabled field in the database. // FieldBalanceNotifyEnabled holds the string denoting the balance_notify_enabled field in the database.
FieldBalanceNotifyEnabled = "balance_notify_enabled" FieldBalanceNotifyEnabled = "balance_notify_enabled"
// FieldBalanceNotifyThresholdType holds the string denoting the balance_notify_threshold_type field in the database.
FieldBalanceNotifyThresholdType = "balance_notify_threshold_type"
// FieldBalanceNotifyThreshold holds the string denoting the balance_notify_threshold field in the database. // FieldBalanceNotifyThreshold holds the string denoting the balance_notify_threshold field in the database.
FieldBalanceNotifyThreshold = "balance_notify_threshold" FieldBalanceNotifyThreshold = "balance_notify_threshold"
// FieldBalanceNotifyExtraEmails holds the string denoting the balance_notify_extra_emails field in the database. // FieldBalanceNotifyExtraEmails holds the string denoting the balance_notify_extra_emails field in the database.
FieldBalanceNotifyExtraEmails = "balance_notify_extra_emails" FieldBalanceNotifyExtraEmails = "balance_notify_extra_emails"
// FieldTotalRecharged holds the string denoting the total_recharged field in the database.
FieldTotalRecharged = "total_recharged"
// EdgeAPIKeys holds the string denoting the api_keys edge name in mutations. // EdgeAPIKeys holds the string denoting the api_keys edge name in mutations.
EdgeAPIKeys = "api_keys" EdgeAPIKeys = "api_keys"
// EdgeRedeemCodes holds the string denoting the redeem_codes edge name in mutations. // EdgeRedeemCodes holds the string denoting the redeem_codes edge name in mutations.
...@@ -168,8 +172,10 @@ var Columns = []string{ ...@@ -168,8 +172,10 @@ var Columns = []string{
FieldTotpEnabled, FieldTotpEnabled,
FieldTotpEnabledAt, FieldTotpEnabledAt,
FieldBalanceNotifyEnabled, FieldBalanceNotifyEnabled,
FieldBalanceNotifyThresholdType,
FieldBalanceNotifyThreshold, FieldBalanceNotifyThreshold,
FieldBalanceNotifyExtraEmails, FieldBalanceNotifyExtraEmails,
FieldTotalRecharged,
} }
var ( var (
...@@ -228,8 +234,12 @@ var ( ...@@ -228,8 +234,12 @@ var (
DefaultTotpEnabled bool DefaultTotpEnabled bool
// DefaultBalanceNotifyEnabled holds the default value on creation for the "balance_notify_enabled" field. // DefaultBalanceNotifyEnabled holds the default value on creation for the "balance_notify_enabled" field.
DefaultBalanceNotifyEnabled bool DefaultBalanceNotifyEnabled bool
// DefaultBalanceNotifyThresholdType holds the default value on creation for the "balance_notify_threshold_type" field.
DefaultBalanceNotifyThresholdType string
// DefaultBalanceNotifyExtraEmails holds the default value on creation for the "balance_notify_extra_emails" field. // DefaultBalanceNotifyExtraEmails holds the default value on creation for the "balance_notify_extra_emails" field.
DefaultBalanceNotifyExtraEmails string DefaultBalanceNotifyExtraEmails string
// DefaultTotalRecharged holds the default value on creation for the "total_recharged" field.
DefaultTotalRecharged float64
) )
// OrderOption defines the ordering options for the User queries. // OrderOption defines the ordering options for the User queries.
...@@ -315,6 +325,11 @@ func ByBalanceNotifyEnabled(opts ...sql.OrderTermOption) OrderOption { ...@@ -315,6 +325,11 @@ func ByBalanceNotifyEnabled(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldBalanceNotifyEnabled, opts...).ToFunc() return sql.OrderByField(FieldBalanceNotifyEnabled, opts...).ToFunc()
} }
// ByBalanceNotifyThresholdType orders the results by the balance_notify_threshold_type field.
func ByBalanceNotifyThresholdType(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldBalanceNotifyThresholdType, opts...).ToFunc()
}
// ByBalanceNotifyThreshold orders the results by the balance_notify_threshold field. // ByBalanceNotifyThreshold orders the results by the balance_notify_threshold field.
func ByBalanceNotifyThreshold(opts ...sql.OrderTermOption) OrderOption { func ByBalanceNotifyThreshold(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldBalanceNotifyThreshold, opts...).ToFunc() return sql.OrderByField(FieldBalanceNotifyThreshold, opts...).ToFunc()
...@@ -325,6 +340,11 @@ func ByBalanceNotifyExtraEmails(opts ...sql.OrderTermOption) OrderOption { ...@@ -325,6 +340,11 @@ func ByBalanceNotifyExtraEmails(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldBalanceNotifyExtraEmails, opts...).ToFunc() return sql.OrderByField(FieldBalanceNotifyExtraEmails, opts...).ToFunc()
} }
// ByTotalRecharged orders the results by the total_recharged field.
func ByTotalRecharged(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldTotalRecharged, opts...).ToFunc()
}
// ByAPIKeysCount orders the results by api_keys count. // ByAPIKeysCount orders the results by api_keys count.
func ByAPIKeysCount(opts ...sql.OrderTermOption) OrderOption { func ByAPIKeysCount(opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) { return func(s *sql.Selector) {
......
...@@ -130,6 +130,11 @@ func BalanceNotifyEnabled(v bool) predicate.User { ...@@ -130,6 +130,11 @@ func BalanceNotifyEnabled(v bool) predicate.User {
return predicate.User(sql.FieldEQ(FieldBalanceNotifyEnabled, v)) return predicate.User(sql.FieldEQ(FieldBalanceNotifyEnabled, v))
} }
// BalanceNotifyThresholdType applies equality check predicate on the "balance_notify_threshold_type" field. It's identical to BalanceNotifyThresholdTypeEQ.
func BalanceNotifyThresholdType(v string) predicate.User {
return predicate.User(sql.FieldEQ(FieldBalanceNotifyThresholdType, v))
}
// BalanceNotifyThreshold applies equality check predicate on the "balance_notify_threshold" field. It's identical to BalanceNotifyThresholdEQ. // BalanceNotifyThreshold applies equality check predicate on the "balance_notify_threshold" field. It's identical to BalanceNotifyThresholdEQ.
func BalanceNotifyThreshold(v float64) predicate.User { func BalanceNotifyThreshold(v float64) predicate.User {
return predicate.User(sql.FieldEQ(FieldBalanceNotifyThreshold, v)) return predicate.User(sql.FieldEQ(FieldBalanceNotifyThreshold, v))
...@@ -140,6 +145,11 @@ func BalanceNotifyExtraEmails(v string) predicate.User { ...@@ -140,6 +145,11 @@ func BalanceNotifyExtraEmails(v string) predicate.User {
return predicate.User(sql.FieldEQ(FieldBalanceNotifyExtraEmails, v)) return predicate.User(sql.FieldEQ(FieldBalanceNotifyExtraEmails, v))
} }
// TotalRecharged applies equality check predicate on the "total_recharged" field. It's identical to TotalRechargedEQ.
func TotalRecharged(v float64) predicate.User {
return predicate.User(sql.FieldEQ(FieldTotalRecharged, v))
}
// CreatedAtEQ applies the EQ predicate on the "created_at" field. // CreatedAtEQ applies the EQ predicate on the "created_at" field.
func CreatedAtEQ(v time.Time) predicate.User { func CreatedAtEQ(v time.Time) predicate.User {
return predicate.User(sql.FieldEQ(FieldCreatedAt, v)) return predicate.User(sql.FieldEQ(FieldCreatedAt, v))
...@@ -885,6 +895,71 @@ func BalanceNotifyEnabledNEQ(v bool) predicate.User { ...@@ -885,6 +895,71 @@ func BalanceNotifyEnabledNEQ(v bool) predicate.User {
return predicate.User(sql.FieldNEQ(FieldBalanceNotifyEnabled, v)) return predicate.User(sql.FieldNEQ(FieldBalanceNotifyEnabled, v))
} }
// BalanceNotifyThresholdTypeEQ applies the EQ predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeEQ(v string) predicate.User {
return predicate.User(sql.FieldEQ(FieldBalanceNotifyThresholdType, v))
}
// BalanceNotifyThresholdTypeNEQ applies the NEQ predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeNEQ(v string) predicate.User {
return predicate.User(sql.FieldNEQ(FieldBalanceNotifyThresholdType, v))
}
// BalanceNotifyThresholdTypeIn applies the In predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeIn(vs ...string) predicate.User {
return predicate.User(sql.FieldIn(FieldBalanceNotifyThresholdType, vs...))
}
// BalanceNotifyThresholdTypeNotIn applies the NotIn predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeNotIn(vs ...string) predicate.User {
return predicate.User(sql.FieldNotIn(FieldBalanceNotifyThresholdType, vs...))
}
// BalanceNotifyThresholdTypeGT applies the GT predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeGT(v string) predicate.User {
return predicate.User(sql.FieldGT(FieldBalanceNotifyThresholdType, v))
}
// BalanceNotifyThresholdTypeGTE applies the GTE predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeGTE(v string) predicate.User {
return predicate.User(sql.FieldGTE(FieldBalanceNotifyThresholdType, v))
}
// BalanceNotifyThresholdTypeLT applies the LT predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeLT(v string) predicate.User {
return predicate.User(sql.FieldLT(FieldBalanceNotifyThresholdType, v))
}
// BalanceNotifyThresholdTypeLTE applies the LTE predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeLTE(v string) predicate.User {
return predicate.User(sql.FieldLTE(FieldBalanceNotifyThresholdType, v))
}
// BalanceNotifyThresholdTypeContains applies the Contains predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeContains(v string) predicate.User {
return predicate.User(sql.FieldContains(FieldBalanceNotifyThresholdType, v))
}
// BalanceNotifyThresholdTypeHasPrefix applies the HasPrefix predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeHasPrefix(v string) predicate.User {
return predicate.User(sql.FieldHasPrefix(FieldBalanceNotifyThresholdType, v))
}
// BalanceNotifyThresholdTypeHasSuffix applies the HasSuffix predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeHasSuffix(v string) predicate.User {
return predicate.User(sql.FieldHasSuffix(FieldBalanceNotifyThresholdType, v))
}
// BalanceNotifyThresholdTypeEqualFold applies the EqualFold predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeEqualFold(v string) predicate.User {
return predicate.User(sql.FieldEqualFold(FieldBalanceNotifyThresholdType, v))
}
// BalanceNotifyThresholdTypeContainsFold applies the ContainsFold predicate on the "balance_notify_threshold_type" field.
func BalanceNotifyThresholdTypeContainsFold(v string) predicate.User {
return predicate.User(sql.FieldContainsFold(FieldBalanceNotifyThresholdType, v))
}
// BalanceNotifyThresholdEQ applies the EQ predicate on the "balance_notify_threshold" field. // BalanceNotifyThresholdEQ applies the EQ predicate on the "balance_notify_threshold" field.
func BalanceNotifyThresholdEQ(v float64) predicate.User { func BalanceNotifyThresholdEQ(v float64) predicate.User {
return predicate.User(sql.FieldEQ(FieldBalanceNotifyThreshold, v)) return predicate.User(sql.FieldEQ(FieldBalanceNotifyThreshold, v))
...@@ -1000,6 +1075,46 @@ func BalanceNotifyExtraEmailsContainsFold(v string) predicate.User { ...@@ -1000,6 +1075,46 @@ func BalanceNotifyExtraEmailsContainsFold(v string) predicate.User {
return predicate.User(sql.FieldContainsFold(FieldBalanceNotifyExtraEmails, v)) return predicate.User(sql.FieldContainsFold(FieldBalanceNotifyExtraEmails, v))
} }
// TotalRechargedEQ applies the EQ predicate on the "total_recharged" field.
func TotalRechargedEQ(v float64) predicate.User {
return predicate.User(sql.FieldEQ(FieldTotalRecharged, v))
}
// TotalRechargedNEQ applies the NEQ predicate on the "total_recharged" field.
func TotalRechargedNEQ(v float64) predicate.User {
return predicate.User(sql.FieldNEQ(FieldTotalRecharged, v))
}
// TotalRechargedIn applies the In predicate on the "total_recharged" field.
func TotalRechargedIn(vs ...float64) predicate.User {
return predicate.User(sql.FieldIn(FieldTotalRecharged, vs...))
}
// TotalRechargedNotIn applies the NotIn predicate on the "total_recharged" field.
func TotalRechargedNotIn(vs ...float64) predicate.User {
return predicate.User(sql.FieldNotIn(FieldTotalRecharged, vs...))
}
// TotalRechargedGT applies the GT predicate on the "total_recharged" field.
func TotalRechargedGT(v float64) predicate.User {
return predicate.User(sql.FieldGT(FieldTotalRecharged, v))
}
// TotalRechargedGTE applies the GTE predicate on the "total_recharged" field.
func TotalRechargedGTE(v float64) predicate.User {
return predicate.User(sql.FieldGTE(FieldTotalRecharged, v))
}
// TotalRechargedLT applies the LT predicate on the "total_recharged" field.
func TotalRechargedLT(v float64) predicate.User {
return predicate.User(sql.FieldLT(FieldTotalRecharged, v))
}
// TotalRechargedLTE applies the LTE predicate on the "total_recharged" field.
func TotalRechargedLTE(v float64) predicate.User {
return predicate.User(sql.FieldLTE(FieldTotalRecharged, v))
}
// HasAPIKeys applies the HasEdge predicate on the "api_keys" edge. // HasAPIKeys applies the HasEdge predicate on the "api_keys" edge.
func HasAPIKeys() predicate.User { func HasAPIKeys() predicate.User {
return predicate.User(func(s *sql.Selector) { return predicate.User(func(s *sql.Selector) {
......
...@@ -225,6 +225,20 @@ func (_c *UserCreate) SetNillableBalanceNotifyEnabled(v *bool) *UserCreate { ...@@ -225,6 +225,20 @@ func (_c *UserCreate) SetNillableBalanceNotifyEnabled(v *bool) *UserCreate {
return _c return _c
} }
// SetBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field.
func (_c *UserCreate) SetBalanceNotifyThresholdType(v string) *UserCreate {
_c.mutation.SetBalanceNotifyThresholdType(v)
return _c
}
// SetNillableBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field if the given value is not nil.
func (_c *UserCreate) SetNillableBalanceNotifyThresholdType(v *string) *UserCreate {
if v != nil {
_c.SetBalanceNotifyThresholdType(*v)
}
return _c
}
// SetBalanceNotifyThreshold sets the "balance_notify_threshold" field. // SetBalanceNotifyThreshold sets the "balance_notify_threshold" field.
func (_c *UserCreate) SetBalanceNotifyThreshold(v float64) *UserCreate { func (_c *UserCreate) SetBalanceNotifyThreshold(v float64) *UserCreate {
_c.mutation.SetBalanceNotifyThreshold(v) _c.mutation.SetBalanceNotifyThreshold(v)
...@@ -253,6 +267,20 @@ func (_c *UserCreate) SetNillableBalanceNotifyExtraEmails(v *string) *UserCreate ...@@ -253,6 +267,20 @@ func (_c *UserCreate) SetNillableBalanceNotifyExtraEmails(v *string) *UserCreate
return _c return _c
} }
// SetTotalRecharged sets the "total_recharged" field.
func (_c *UserCreate) SetTotalRecharged(v float64) *UserCreate {
_c.mutation.SetTotalRecharged(v)
return _c
}
// SetNillableTotalRecharged sets the "total_recharged" field if the given value is not nil.
func (_c *UserCreate) SetNillableTotalRecharged(v *float64) *UserCreate {
if v != nil {
_c.SetTotalRecharged(*v)
}
return _c
}
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs. // AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func (_c *UserCreate) AddAPIKeyIDs(ids ...int64) *UserCreate { func (_c *UserCreate) AddAPIKeyIDs(ids ...int64) *UserCreate {
_c.mutation.AddAPIKeyIDs(ids...) _c.mutation.AddAPIKeyIDs(ids...)
...@@ -486,10 +514,18 @@ func (_c *UserCreate) defaults() error { ...@@ -486,10 +514,18 @@ func (_c *UserCreate) defaults() error {
v := user.DefaultBalanceNotifyEnabled v := user.DefaultBalanceNotifyEnabled
_c.mutation.SetBalanceNotifyEnabled(v) _c.mutation.SetBalanceNotifyEnabled(v)
} }
if _, ok := _c.mutation.BalanceNotifyThresholdType(); !ok {
v := user.DefaultBalanceNotifyThresholdType
_c.mutation.SetBalanceNotifyThresholdType(v)
}
if _, ok := _c.mutation.BalanceNotifyExtraEmails(); !ok { if _, ok := _c.mutation.BalanceNotifyExtraEmails(); !ok {
v := user.DefaultBalanceNotifyExtraEmails v := user.DefaultBalanceNotifyExtraEmails
_c.mutation.SetBalanceNotifyExtraEmails(v) _c.mutation.SetBalanceNotifyExtraEmails(v)
} }
if _, ok := _c.mutation.TotalRecharged(); !ok {
v := user.DefaultTotalRecharged
_c.mutation.SetTotalRecharged(v)
}
return nil return nil
} }
...@@ -556,9 +592,15 @@ func (_c *UserCreate) check() error { ...@@ -556,9 +592,15 @@ func (_c *UserCreate) check() error {
if _, ok := _c.mutation.BalanceNotifyEnabled(); !ok { if _, ok := _c.mutation.BalanceNotifyEnabled(); !ok {
return &ValidationError{Name: "balance_notify_enabled", err: errors.New(`ent: missing required field "User.balance_notify_enabled"`)} return &ValidationError{Name: "balance_notify_enabled", err: errors.New(`ent: missing required field "User.balance_notify_enabled"`)}
} }
if _, ok := _c.mutation.BalanceNotifyThresholdType(); !ok {
return &ValidationError{Name: "balance_notify_threshold_type", err: errors.New(`ent: missing required field "User.balance_notify_threshold_type"`)}
}
if _, ok := _c.mutation.BalanceNotifyExtraEmails(); !ok { if _, ok := _c.mutation.BalanceNotifyExtraEmails(); !ok {
return &ValidationError{Name: "balance_notify_extra_emails", err: errors.New(`ent: missing required field "User.balance_notify_extra_emails"`)} return &ValidationError{Name: "balance_notify_extra_emails", err: errors.New(`ent: missing required field "User.balance_notify_extra_emails"`)}
} }
if _, ok := _c.mutation.TotalRecharged(); !ok {
return &ValidationError{Name: "total_recharged", err: errors.New(`ent: missing required field "User.total_recharged"`)}
}
return nil return nil
} }
...@@ -646,6 +688,10 @@ func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { ...@@ -646,6 +688,10 @@ func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
_spec.SetField(user.FieldBalanceNotifyEnabled, field.TypeBool, value) _spec.SetField(user.FieldBalanceNotifyEnabled, field.TypeBool, value)
_node.BalanceNotifyEnabled = value _node.BalanceNotifyEnabled = value
} }
if value, ok := _c.mutation.BalanceNotifyThresholdType(); ok {
_spec.SetField(user.FieldBalanceNotifyThresholdType, field.TypeString, value)
_node.BalanceNotifyThresholdType = value
}
if value, ok := _c.mutation.BalanceNotifyThreshold(); ok { if value, ok := _c.mutation.BalanceNotifyThreshold(); ok {
_spec.SetField(user.FieldBalanceNotifyThreshold, field.TypeFloat64, value) _spec.SetField(user.FieldBalanceNotifyThreshold, field.TypeFloat64, value)
_node.BalanceNotifyThreshold = &value _node.BalanceNotifyThreshold = &value
...@@ -654,6 +700,10 @@ func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { ...@@ -654,6 +700,10 @@ func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
_spec.SetField(user.FieldBalanceNotifyExtraEmails, field.TypeString, value) _spec.SetField(user.FieldBalanceNotifyExtraEmails, field.TypeString, value)
_node.BalanceNotifyExtraEmails = value _node.BalanceNotifyExtraEmails = value
} }
if value, ok := _c.mutation.TotalRecharged(); ok {
_spec.SetField(user.FieldTotalRecharged, field.TypeFloat64, value)
_node.TotalRecharged = value
}
if nodes := _c.mutation.APIKeysIDs(); len(nodes) > 0 { if nodes := _c.mutation.APIKeysIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{ edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M, Rel: sqlgraph.O2M,
...@@ -1068,6 +1118,18 @@ func (u *UserUpsert) UpdateBalanceNotifyEnabled() *UserUpsert { ...@@ -1068,6 +1118,18 @@ func (u *UserUpsert) UpdateBalanceNotifyEnabled() *UserUpsert {
return u return u
} }
// SetBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field.
func (u *UserUpsert) SetBalanceNotifyThresholdType(v string) *UserUpsert {
u.Set(user.FieldBalanceNotifyThresholdType, v)
return u
}
// UpdateBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field to the value that was provided on create.
func (u *UserUpsert) UpdateBalanceNotifyThresholdType() *UserUpsert {
u.SetExcluded(user.FieldBalanceNotifyThresholdType)
return u
}
// SetBalanceNotifyThreshold sets the "balance_notify_threshold" field. // SetBalanceNotifyThreshold sets the "balance_notify_threshold" field.
func (u *UserUpsert) SetBalanceNotifyThreshold(v float64) *UserUpsert { func (u *UserUpsert) SetBalanceNotifyThreshold(v float64) *UserUpsert {
u.Set(user.FieldBalanceNotifyThreshold, v) u.Set(user.FieldBalanceNotifyThreshold, v)
...@@ -1104,6 +1166,24 @@ func (u *UserUpsert) UpdateBalanceNotifyExtraEmails() *UserUpsert { ...@@ -1104,6 +1166,24 @@ func (u *UserUpsert) UpdateBalanceNotifyExtraEmails() *UserUpsert {
return u return u
} }
// SetTotalRecharged sets the "total_recharged" field.
func (u *UserUpsert) SetTotalRecharged(v float64) *UserUpsert {
u.Set(user.FieldTotalRecharged, v)
return u
}
// UpdateTotalRecharged sets the "total_recharged" field to the value that was provided on create.
func (u *UserUpsert) UpdateTotalRecharged() *UserUpsert {
u.SetExcluded(user.FieldTotalRecharged)
return u
}
// AddTotalRecharged adds v to the "total_recharged" field.
func (u *UserUpsert) AddTotalRecharged(v float64) *UserUpsert {
u.Add(user.FieldTotalRecharged, v)
return u
}
// UpdateNewValues updates the mutable fields using the new values that were set on create. // UpdateNewValues updates the mutable fields using the new values that were set on create.
// Using this option is equivalent to using: // Using this option is equivalent to using:
// //
...@@ -1380,6 +1460,20 @@ func (u *UserUpsertOne) UpdateBalanceNotifyEnabled() *UserUpsertOne { ...@@ -1380,6 +1460,20 @@ func (u *UserUpsertOne) UpdateBalanceNotifyEnabled() *UserUpsertOne {
}) })
} }
// SetBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field.
func (u *UserUpsertOne) SetBalanceNotifyThresholdType(v string) *UserUpsertOne {
return u.Update(func(s *UserUpsert) {
s.SetBalanceNotifyThresholdType(v)
})
}
// UpdateBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field to the value that was provided on create.
func (u *UserUpsertOne) UpdateBalanceNotifyThresholdType() *UserUpsertOne {
return u.Update(func(s *UserUpsert) {
s.UpdateBalanceNotifyThresholdType()
})
}
// SetBalanceNotifyThreshold sets the "balance_notify_threshold" field. // SetBalanceNotifyThreshold sets the "balance_notify_threshold" field.
func (u *UserUpsertOne) SetBalanceNotifyThreshold(v float64) *UserUpsertOne { func (u *UserUpsertOne) SetBalanceNotifyThreshold(v float64) *UserUpsertOne {
return u.Update(func(s *UserUpsert) { return u.Update(func(s *UserUpsert) {
...@@ -1422,6 +1516,27 @@ func (u *UserUpsertOne) UpdateBalanceNotifyExtraEmails() *UserUpsertOne { ...@@ -1422,6 +1516,27 @@ func (u *UserUpsertOne) UpdateBalanceNotifyExtraEmails() *UserUpsertOne {
}) })
} }
// SetTotalRecharged sets the "total_recharged" field.
func (u *UserUpsertOne) SetTotalRecharged(v float64) *UserUpsertOne {
return u.Update(func(s *UserUpsert) {
s.SetTotalRecharged(v)
})
}
// AddTotalRecharged adds v to the "total_recharged" field.
func (u *UserUpsertOne) AddTotalRecharged(v float64) *UserUpsertOne {
return u.Update(func(s *UserUpsert) {
s.AddTotalRecharged(v)
})
}
// UpdateTotalRecharged sets the "total_recharged" field to the value that was provided on create.
func (u *UserUpsertOne) UpdateTotalRecharged() *UserUpsertOne {
return u.Update(func(s *UserUpsert) {
s.UpdateTotalRecharged()
})
}
// Exec executes the query. // Exec executes the query.
func (u *UserUpsertOne) Exec(ctx context.Context) error { func (u *UserUpsertOne) Exec(ctx context.Context) error {
if len(u.create.conflict) == 0 { if len(u.create.conflict) == 0 {
...@@ -1864,6 +1979,20 @@ func (u *UserUpsertBulk) UpdateBalanceNotifyEnabled() *UserUpsertBulk { ...@@ -1864,6 +1979,20 @@ func (u *UserUpsertBulk) UpdateBalanceNotifyEnabled() *UserUpsertBulk {
}) })
} }
// SetBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field.
func (u *UserUpsertBulk) SetBalanceNotifyThresholdType(v string) *UserUpsertBulk {
return u.Update(func(s *UserUpsert) {
s.SetBalanceNotifyThresholdType(v)
})
}
// UpdateBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field to the value that was provided on create.
func (u *UserUpsertBulk) UpdateBalanceNotifyThresholdType() *UserUpsertBulk {
return u.Update(func(s *UserUpsert) {
s.UpdateBalanceNotifyThresholdType()
})
}
// SetBalanceNotifyThreshold sets the "balance_notify_threshold" field. // SetBalanceNotifyThreshold sets the "balance_notify_threshold" field.
func (u *UserUpsertBulk) SetBalanceNotifyThreshold(v float64) *UserUpsertBulk { func (u *UserUpsertBulk) SetBalanceNotifyThreshold(v float64) *UserUpsertBulk {
return u.Update(func(s *UserUpsert) { return u.Update(func(s *UserUpsert) {
...@@ -1906,6 +2035,27 @@ func (u *UserUpsertBulk) UpdateBalanceNotifyExtraEmails() *UserUpsertBulk { ...@@ -1906,6 +2035,27 @@ func (u *UserUpsertBulk) UpdateBalanceNotifyExtraEmails() *UserUpsertBulk {
}) })
} }
// SetTotalRecharged sets the "total_recharged" field.
func (u *UserUpsertBulk) SetTotalRecharged(v float64) *UserUpsertBulk {
return u.Update(func(s *UserUpsert) {
s.SetTotalRecharged(v)
})
}
// AddTotalRecharged adds v to the "total_recharged" field.
func (u *UserUpsertBulk) AddTotalRecharged(v float64) *UserUpsertBulk {
return u.Update(func(s *UserUpsert) {
s.AddTotalRecharged(v)
})
}
// UpdateTotalRecharged sets the "total_recharged" field to the value that was provided on create.
func (u *UserUpsertBulk) UpdateTotalRecharged() *UserUpsertBulk {
return u.Update(func(s *UserUpsert) {
s.UpdateTotalRecharged()
})
}
// Exec executes the query. // Exec executes the query.
func (u *UserUpsertBulk) Exec(ctx context.Context) error { func (u *UserUpsertBulk) Exec(ctx context.Context) error {
if u.create.err != nil { if u.create.err != nil {
......
...@@ -257,6 +257,20 @@ func (_u *UserUpdate) SetNillableBalanceNotifyEnabled(v *bool) *UserUpdate { ...@@ -257,6 +257,20 @@ func (_u *UserUpdate) SetNillableBalanceNotifyEnabled(v *bool) *UserUpdate {
return _u return _u
} }
// SetBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field.
func (_u *UserUpdate) SetBalanceNotifyThresholdType(v string) *UserUpdate {
_u.mutation.SetBalanceNotifyThresholdType(v)
return _u
}
// SetNillableBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field if the given value is not nil.
func (_u *UserUpdate) SetNillableBalanceNotifyThresholdType(v *string) *UserUpdate {
if v != nil {
_u.SetBalanceNotifyThresholdType(*v)
}
return _u
}
// SetBalanceNotifyThreshold sets the "balance_notify_threshold" field. // SetBalanceNotifyThreshold sets the "balance_notify_threshold" field.
func (_u *UserUpdate) SetBalanceNotifyThreshold(v float64) *UserUpdate { func (_u *UserUpdate) SetBalanceNotifyThreshold(v float64) *UserUpdate {
_u.mutation.ResetBalanceNotifyThreshold() _u.mutation.ResetBalanceNotifyThreshold()
...@@ -298,6 +312,27 @@ func (_u *UserUpdate) SetNillableBalanceNotifyExtraEmails(v *string) *UserUpdate ...@@ -298,6 +312,27 @@ func (_u *UserUpdate) SetNillableBalanceNotifyExtraEmails(v *string) *UserUpdate
return _u return _u
} }
// SetTotalRecharged sets the "total_recharged" field.
func (_u *UserUpdate) SetTotalRecharged(v float64) *UserUpdate {
_u.mutation.ResetTotalRecharged()
_u.mutation.SetTotalRecharged(v)
return _u
}
// SetNillableTotalRecharged sets the "total_recharged" field if the given value is not nil.
func (_u *UserUpdate) SetNillableTotalRecharged(v *float64) *UserUpdate {
if v != nil {
_u.SetTotalRecharged(*v)
}
return _u
}
// AddTotalRecharged adds value to the "total_recharged" field.
func (_u *UserUpdate) AddTotalRecharged(v float64) *UserUpdate {
_u.mutation.AddTotalRecharged(v)
return _u
}
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs. // AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func (_u *UserUpdate) AddAPIKeyIDs(ids ...int64) *UserUpdate { func (_u *UserUpdate) AddAPIKeyIDs(ids ...int64) *UserUpdate {
_u.mutation.AddAPIKeyIDs(ids...) _u.mutation.AddAPIKeyIDs(ids...)
...@@ -804,6 +839,9 @@ func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) { ...@@ -804,6 +839,9 @@ func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) {
if value, ok := _u.mutation.BalanceNotifyEnabled(); ok { if value, ok := _u.mutation.BalanceNotifyEnabled(); ok {
_spec.SetField(user.FieldBalanceNotifyEnabled, field.TypeBool, value) _spec.SetField(user.FieldBalanceNotifyEnabled, field.TypeBool, value)
} }
if value, ok := _u.mutation.BalanceNotifyThresholdType(); ok {
_spec.SetField(user.FieldBalanceNotifyThresholdType, field.TypeString, value)
}
if value, ok := _u.mutation.BalanceNotifyThreshold(); ok { if value, ok := _u.mutation.BalanceNotifyThreshold(); ok {
_spec.SetField(user.FieldBalanceNotifyThreshold, field.TypeFloat64, value) _spec.SetField(user.FieldBalanceNotifyThreshold, field.TypeFloat64, value)
} }
...@@ -816,6 +854,12 @@ func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) { ...@@ -816,6 +854,12 @@ func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) {
if value, ok := _u.mutation.BalanceNotifyExtraEmails(); ok { if value, ok := _u.mutation.BalanceNotifyExtraEmails(); ok {
_spec.SetField(user.FieldBalanceNotifyExtraEmails, field.TypeString, value) _spec.SetField(user.FieldBalanceNotifyExtraEmails, field.TypeString, value)
} }
if value, ok := _u.mutation.TotalRecharged(); ok {
_spec.SetField(user.FieldTotalRecharged, field.TypeFloat64, value)
}
if value, ok := _u.mutation.AddedTotalRecharged(); ok {
_spec.AddField(user.FieldTotalRecharged, field.TypeFloat64, value)
}
if _u.mutation.APIKeysCleared() { if _u.mutation.APIKeysCleared() {
edge := &sqlgraph.EdgeSpec{ edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M, Rel: sqlgraph.O2M,
...@@ -1518,6 +1562,20 @@ func (_u *UserUpdateOne) SetNillableBalanceNotifyEnabled(v *bool) *UserUpdateOne ...@@ -1518,6 +1562,20 @@ func (_u *UserUpdateOne) SetNillableBalanceNotifyEnabled(v *bool) *UserUpdateOne
return _u return _u
} }
// SetBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field.
func (_u *UserUpdateOne) SetBalanceNotifyThresholdType(v string) *UserUpdateOne {
_u.mutation.SetBalanceNotifyThresholdType(v)
return _u
}
// SetNillableBalanceNotifyThresholdType sets the "balance_notify_threshold_type" field if the given value is not nil.
func (_u *UserUpdateOne) SetNillableBalanceNotifyThresholdType(v *string) *UserUpdateOne {
if v != nil {
_u.SetBalanceNotifyThresholdType(*v)
}
return _u
}
// SetBalanceNotifyThreshold sets the "balance_notify_threshold" field. // SetBalanceNotifyThreshold sets the "balance_notify_threshold" field.
func (_u *UserUpdateOne) SetBalanceNotifyThreshold(v float64) *UserUpdateOne { func (_u *UserUpdateOne) SetBalanceNotifyThreshold(v float64) *UserUpdateOne {
_u.mutation.ResetBalanceNotifyThreshold() _u.mutation.ResetBalanceNotifyThreshold()
...@@ -1559,6 +1617,27 @@ func (_u *UserUpdateOne) SetNillableBalanceNotifyExtraEmails(v *string) *UserUpd ...@@ -1559,6 +1617,27 @@ func (_u *UserUpdateOne) SetNillableBalanceNotifyExtraEmails(v *string) *UserUpd
return _u return _u
} }
// SetTotalRecharged sets the "total_recharged" field.
func (_u *UserUpdateOne) SetTotalRecharged(v float64) *UserUpdateOne {
_u.mutation.ResetTotalRecharged()
_u.mutation.SetTotalRecharged(v)
return _u
}
// SetNillableTotalRecharged sets the "total_recharged" field if the given value is not nil.
func (_u *UserUpdateOne) SetNillableTotalRecharged(v *float64) *UserUpdateOne {
if v != nil {
_u.SetTotalRecharged(*v)
}
return _u
}
// AddTotalRecharged adds value to the "total_recharged" field.
func (_u *UserUpdateOne) AddTotalRecharged(v float64) *UserUpdateOne {
_u.mutation.AddTotalRecharged(v)
return _u
}
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs. // AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func (_u *UserUpdateOne) AddAPIKeyIDs(ids ...int64) *UserUpdateOne { func (_u *UserUpdateOne) AddAPIKeyIDs(ids ...int64) *UserUpdateOne {
_u.mutation.AddAPIKeyIDs(ids...) _u.mutation.AddAPIKeyIDs(ids...)
...@@ -2095,6 +2174,9 @@ func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) { ...@@ -2095,6 +2174,9 @@ func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) {
if value, ok := _u.mutation.BalanceNotifyEnabled(); ok { if value, ok := _u.mutation.BalanceNotifyEnabled(); ok {
_spec.SetField(user.FieldBalanceNotifyEnabled, field.TypeBool, value) _spec.SetField(user.FieldBalanceNotifyEnabled, field.TypeBool, value)
} }
if value, ok := _u.mutation.BalanceNotifyThresholdType(); ok {
_spec.SetField(user.FieldBalanceNotifyThresholdType, field.TypeString, value)
}
if value, ok := _u.mutation.BalanceNotifyThreshold(); ok { if value, ok := _u.mutation.BalanceNotifyThreshold(); ok {
_spec.SetField(user.FieldBalanceNotifyThreshold, field.TypeFloat64, value) _spec.SetField(user.FieldBalanceNotifyThreshold, field.TypeFloat64, value)
} }
...@@ -2107,6 +2189,12 @@ func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) { ...@@ -2107,6 +2189,12 @@ func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) {
if value, ok := _u.mutation.BalanceNotifyExtraEmails(); ok { if value, ok := _u.mutation.BalanceNotifyExtraEmails(); ok {
_spec.SetField(user.FieldBalanceNotifyExtraEmails, field.TypeString, value) _spec.SetField(user.FieldBalanceNotifyExtraEmails, field.TypeString, value)
} }
if value, ok := _u.mutation.TotalRecharged(); ok {
_spec.SetField(user.FieldTotalRecharged, field.TypeFloat64, value)
}
if value, ok := _u.mutation.AddedTotalRecharged(); ok {
_spec.AddField(user.FieldTotalRecharged, field.TypeFloat64, value)
}
if _u.mutation.APIKeysCleared() { if _u.mutation.APIKeysCleared() {
edge := &sqlgraph.EdgeSpec{ edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M, Rel: sqlgraph.O2M,
......
...@@ -176,6 +176,10 @@ func (h *SettingHandler) GetSettings(c *gin.Context) { ...@@ -176,6 +176,10 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
EnableMetadataPassthrough: settings.EnableMetadataPassthrough, EnableMetadataPassthrough: settings.EnableMetadataPassthrough,
EnableCCHSigning: settings.EnableCCHSigning, EnableCCHSigning: settings.EnableCCHSigning,
WebSearchEmulationEnabled: settings.WebSearchEmulationEnabled, WebSearchEmulationEnabled: settings.WebSearchEmulationEnabled,
BalanceLowNotifyEnabled: settings.BalanceLowNotifyEnabled,
BalanceLowNotifyThresholdType: settings.BalanceLowNotifyThresholdType,
BalanceLowNotifyThreshold: settings.BalanceLowNotifyThreshold,
AccountQuotaNotifyEmails: settings.AccountQuotaNotifyEmails,
PaymentEnabled: paymentCfg.Enabled, PaymentEnabled: paymentCfg.Enabled,
PaymentMinAmount: paymentCfg.MinAmount, PaymentMinAmount: paymentCfg.MinAmount,
PaymentMaxAmount: paymentCfg.MaxAmount, PaymentMaxAmount: paymentCfg.MaxAmount,
...@@ -305,6 +309,12 @@ type UpdateSettingsRequest struct { ...@@ -305,6 +309,12 @@ type UpdateSettingsRequest struct {
EnableMetadataPassthrough *bool `json:"enable_metadata_passthrough"` EnableMetadataPassthrough *bool `json:"enable_metadata_passthrough"`
EnableCCHSigning *bool `json:"enable_cch_signing"` EnableCCHSigning *bool `json:"enable_cch_signing"`
// Balance low notification
BalanceLowNotifyEnabled *bool `json:"balance_low_notify_enabled"`
BalanceLowNotifyThresholdType *string `json:"balance_low_notify_threshold_type"`
BalanceLowNotifyThreshold *float64 `json:"balance_low_notify_threshold"`
AccountQuotaNotifyEmails *[]string `json:"account_quota_notify_emails"`
// Payment configuration (integrated into settings, full replace) // Payment configuration (integrated into settings, full replace)
PaymentEnabled *bool `json:"payment_enabled"` PaymentEnabled *bool `json:"payment_enabled"`
PaymentMinAmount *float64 `json:"payment_min_amount"` PaymentMinAmount *float64 `json:"payment_min_amount"`
...@@ -882,6 +892,30 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) { ...@@ -882,6 +892,30 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
} }
return previousSettings.EnableCCHSigning return previousSettings.EnableCCHSigning
}(), }(),
BalanceLowNotifyEnabled: func() bool {
if req.BalanceLowNotifyEnabled != nil {
return *req.BalanceLowNotifyEnabled
}
return previousSettings.BalanceLowNotifyEnabled
}(),
BalanceLowNotifyThresholdType: func() string {
if req.BalanceLowNotifyThresholdType != nil {
return *req.BalanceLowNotifyThresholdType
}
return previousSettings.BalanceLowNotifyThresholdType
}(),
BalanceLowNotifyThreshold: func() float64 {
if req.BalanceLowNotifyThreshold != nil {
return *req.BalanceLowNotifyThreshold
}
return previousSettings.BalanceLowNotifyThreshold
}(),
AccountQuotaNotifyEmails: func() []string {
if req.AccountQuotaNotifyEmails != nil {
return *req.AccountQuotaNotifyEmails
}
return previousSettings.AccountQuotaNotifyEmails
}(),
} }
if err := h.settingService.UpdateSettings(c.Request.Context(), settings); err != nil { if err := h.settingService.UpdateSettings(c.Request.Context(), settings); err != nil {
...@@ -1028,6 +1062,10 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) { ...@@ -1028,6 +1062,10 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
EnableFingerprintUnification: updatedSettings.EnableFingerprintUnification, EnableFingerprintUnification: updatedSettings.EnableFingerprintUnification,
EnableMetadataPassthrough: updatedSettings.EnableMetadataPassthrough, EnableMetadataPassthrough: updatedSettings.EnableMetadataPassthrough,
EnableCCHSigning: updatedSettings.EnableCCHSigning, EnableCCHSigning: updatedSettings.EnableCCHSigning,
BalanceLowNotifyEnabled: updatedSettings.BalanceLowNotifyEnabled,
BalanceLowNotifyThresholdType: updatedSettings.BalanceLowNotifyThresholdType,
BalanceLowNotifyThreshold: updatedSettings.BalanceLowNotifyThreshold,
AccountQuotaNotifyEmails: updatedSettings.AccountQuotaNotifyEmails,
PaymentEnabled: updatedPaymentCfg.Enabled, PaymentEnabled: updatedPaymentCfg.Enabled,
PaymentMinAmount: updatedPaymentCfg.MinAmount, PaymentMinAmount: updatedPaymentCfg.MinAmount,
PaymentMaxAmount: updatedPaymentCfg.MaxAmount, PaymentMaxAmount: updatedPaymentCfg.MaxAmount,
......
...@@ -13,19 +13,21 @@ func UserFromServiceShallow(u *service.User) *User { ...@@ -13,19 +13,21 @@ func UserFromServiceShallow(u *service.User) *User {
return nil return nil
} }
return &User{ return &User{
ID: u.ID, ID: u.ID,
Email: u.Email, Email: u.Email,
Username: u.Username, Username: u.Username,
Role: u.Role, Role: u.Role,
Balance: u.Balance, Balance: u.Balance,
Concurrency: u.Concurrency, Concurrency: u.Concurrency,
Status: u.Status, Status: u.Status,
AllowedGroups: u.AllowedGroups, AllowedGroups: u.AllowedGroups,
CreatedAt: u.CreatedAt, CreatedAt: u.CreatedAt,
UpdatedAt: u.UpdatedAt, UpdatedAt: u.UpdatedAt,
BalanceNotifyEnabled: u.BalanceNotifyEnabled, BalanceNotifyEnabled: u.BalanceNotifyEnabled,
BalanceNotifyThreshold: u.BalanceNotifyThreshold, BalanceNotifyThresholdType: u.BalanceNotifyThresholdType,
BalanceNotifyExtraEmails: u.BalanceNotifyExtraEmails, BalanceNotifyThreshold: u.BalanceNotifyThreshold,
BalanceNotifyExtraEmails: u.BalanceNotifyExtraEmails,
TotalRecharged: u.TotalRecharged,
} }
} }
......
...@@ -150,9 +150,10 @@ type SystemSettings struct { ...@@ -150,9 +150,10 @@ type SystemSettings struct {
PaymentCancelRateLimitMode string `json:"payment_cancel_rate_limit_window_mode"` PaymentCancelRateLimitMode string `json:"payment_cancel_rate_limit_window_mode"`
// Balance low notification // Balance low notification
BalanceLowNotifyEnabled bool `json:"balance_low_notify_enabled"` BalanceLowNotifyEnabled bool `json:"balance_low_notify_enabled"`
BalanceLowNotifyThreshold float64 `json:"balance_low_notify_threshold"` BalanceLowNotifyThresholdType string `json:"balance_low_notify_threshold_type"`
AccountQuotaNotifyEmails []string `json:"account_quota_notify_emails"` BalanceLowNotifyThreshold float64 `json:"balance_low_notify_threshold"`
AccountQuotaNotifyEmails []string `json:"account_quota_notify_emails"`
} }
type DefaultSubscriptionSetting struct { type DefaultSubscriptionSetting struct {
......
...@@ -19,9 +19,11 @@ type User struct { ...@@ -19,9 +19,11 @@ type User struct {
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
// 余额不足通知 // 余额不足通知
BalanceNotifyEnabled bool `json:"balance_notify_enabled"` BalanceNotifyEnabled bool `json:"balance_notify_enabled"`
BalanceNotifyThreshold *float64 `json:"balance_notify_threshold"` BalanceNotifyThresholdType string `json:"balance_notify_threshold_type"`
BalanceNotifyExtraEmails []string `json:"balance_notify_extra_emails"` BalanceNotifyThreshold *float64 `json:"balance_notify_threshold"`
BalanceNotifyExtraEmails []string `json:"balance_notify_extra_emails"`
TotalRecharged float64 `json:"total_recharged"`
APIKeys []APIKey `json:"api_keys,omitempty"` APIKeys []APIKey `json:"api_keys,omitempty"`
Subscriptions []UserSubscription `json:"subscriptions,omitempty"` Subscriptions []UserSubscription `json:"subscriptions,omitempty"`
......
...@@ -33,9 +33,10 @@ type ChangePasswordRequest struct { ...@@ -33,9 +33,10 @@ type ChangePasswordRequest struct {
// UpdateProfileRequest represents the update profile request payload // UpdateProfileRequest represents the update profile request payload
type UpdateProfileRequest struct { type UpdateProfileRequest struct {
Username *string `json:"username"` Username *string `json:"username"`
BalanceNotifyEnabled *bool `json:"balance_notify_enabled"` BalanceNotifyEnabled *bool `json:"balance_notify_enabled"`
BalanceNotifyThreshold *float64 `json:"balance_notify_threshold"` BalanceNotifyThresholdType *string `json:"balance_notify_threshold_type"`
BalanceNotifyThreshold *float64 `json:"balance_notify_threshold"`
} }
// GetProfile handles getting user profile // GetProfile handles getting user profile
...@@ -100,9 +101,10 @@ func (h *UserHandler) UpdateProfile(c *gin.Context) { ...@@ -100,9 +101,10 @@ func (h *UserHandler) UpdateProfile(c *gin.Context) {
} }
svcReq := service.UpdateProfileRequest{ svcReq := service.UpdateProfileRequest{
Username: req.Username, Username: req.Username,
BalanceNotifyEnabled: req.BalanceNotifyEnabled, BalanceNotifyEnabled: req.BalanceNotifyEnabled,
BalanceNotifyThreshold: req.BalanceNotifyThreshold, BalanceNotifyThresholdType: req.BalanceNotifyThresholdType,
BalanceNotifyThreshold: req.BalanceNotifyThreshold,
} }
updatedUser, err := h.userService.UpdateProfile(c.Request.Context(), subject.UserID, svcReq) updatedUser, err := h.userService.UpdateProfile(c.Request.Context(), subject.UserID, svcReq)
if err != nil { if err != nil {
......
...@@ -641,22 +641,24 @@ func userEntityToService(u *dbent.User) *service.User { ...@@ -641,22 +641,24 @@ func userEntityToService(u *dbent.User) *service.User {
return nil return nil
} }
out := &service.User{ out := &service.User{
ID: u.ID, ID: u.ID,
Email: u.Email, Email: u.Email,
Username: u.Username, Username: u.Username,
Notes: u.Notes, Notes: u.Notes,
PasswordHash: u.PasswordHash, PasswordHash: u.PasswordHash,
Role: u.Role, Role: u.Role,
Balance: u.Balance, Balance: u.Balance,
Concurrency: u.Concurrency, Concurrency: u.Concurrency,
Status: u.Status, Status: u.Status,
TotpSecretEncrypted: u.TotpSecretEncrypted, TotpSecretEncrypted: u.TotpSecretEncrypted,
TotpEnabled: u.TotpEnabled, TotpEnabled: u.TotpEnabled,
TotpEnabledAt: u.TotpEnabledAt, TotpEnabledAt: u.TotpEnabledAt,
BalanceNotifyEnabled: u.BalanceNotifyEnabled, BalanceNotifyEnabled: u.BalanceNotifyEnabled,
BalanceNotifyThreshold: u.BalanceNotifyThreshold, BalanceNotifyThresholdType: u.BalanceNotifyThresholdType,
CreatedAt: u.CreatedAt, BalanceNotifyThreshold: u.BalanceNotifyThreshold,
UpdatedAt: u.UpdatedAt, TotalRecharged: u.TotalRecharged,
CreatedAt: u.CreatedAt,
UpdatedAt: u.UpdatedAt,
} }
// Parse extra emails JSON array // Parse extra emails JSON array
if u.BalanceNotifyExtraEmails != "" && u.BalanceNotifyExtraEmails != "[]" { if u.BalanceNotifyExtraEmails != "" && u.BalanceNotifyExtraEmails != "[]" {
......
...@@ -148,6 +148,7 @@ func (r *userRepository) Update(ctx context.Context, userIn *service.User) error ...@@ -148,6 +148,7 @@ func (r *userRepository) Update(ctx context.Context, userIn *service.User) error
SetConcurrency(userIn.Concurrency). SetConcurrency(userIn.Concurrency).
SetStatus(userIn.Status). SetStatus(userIn.Status).
SetBalanceNotifyEnabled(userIn.BalanceNotifyEnabled). SetBalanceNotifyEnabled(userIn.BalanceNotifyEnabled).
SetBalanceNotifyThresholdType(userIn.BalanceNotifyThresholdType).
SetNillableBalanceNotifyThreshold(userIn.BalanceNotifyThreshold). SetNillableBalanceNotifyThreshold(userIn.BalanceNotifyThreshold).
SetBalanceNotifyExtraEmails(marshalExtraEmails(userIn.BalanceNotifyExtraEmails)) SetBalanceNotifyExtraEmails(marshalExtraEmails(userIn.BalanceNotifyExtraEmails))
if userIn.BalanceNotifyThreshold == nil { if userIn.BalanceNotifyThreshold == nil {
...@@ -389,7 +390,12 @@ func (r *userRepository) filterUsersByAttributes(ctx context.Context, attrs map[ ...@@ -389,7 +390,12 @@ func (r *userRepository) filterUsersByAttributes(ctx context.Context, attrs map[
func (r *userRepository) UpdateBalance(ctx context.Context, id int64, amount float64) error { func (r *userRepository) UpdateBalance(ctx context.Context, id int64, amount float64) error {
client := clientFromContext(ctx, r.client) client := clientFromContext(ctx, r.client)
n, err := client.User.Update().Where(dbuser.IDEQ(id)).AddBalance(amount).Save(ctx) update := client.User.Update().Where(dbuser.IDEQ(id)).AddBalance(amount)
// Track cumulative recharge amount for percentage-based notifications
if amount > 0 {
update = update.AddTotalRecharged(amount)
}
n, err := update.Save(ctx)
if err != nil { if err != nil {
return translatePersistenceError(err, service.ErrUserNotFound, nil) return translatePersistenceError(err, service.ErrUserNotFound, nil)
} }
......
...@@ -47,30 +47,21 @@ func (s *BalanceNotifyService) CheckBalanceAfterDeduction(ctx context.Context, u ...@@ -47,30 +47,21 @@ func (s *BalanceNotifyService) CheckBalanceAfterDeduction(ctx context.Context, u
if user == nil || s.emailService == nil || s.settingRepo == nil { if user == nil || s.emailService == nil || s.settingRepo == nil {
return return
} }
// Check user-level switch
if !user.BalanceNotifyEnabled { if !user.BalanceNotifyEnabled {
return return
} }
// Check global switch globalEnabled, globalThresholdType, globalThresholdValue := s.getBalanceNotifyConfig(ctx)
globalEnabled, threshold := s.getBalanceNotifyConfig(ctx)
if !globalEnabled { if !globalEnabled {
return return
} }
// User custom threshold overrides system default threshold := s.resolveEffectiveThreshold(user, globalThresholdType, globalThresholdValue)
if user.BalanceNotifyThreshold != nil {
threshold = *user.BalanceNotifyThreshold
}
if threshold <= 0 { if threshold <= 0 {
return return
} }
newBalance := oldBalance - cost newBalance := oldBalance - cost
// Only notify on first crossing
if oldBalance >= threshold && newBalance < threshold { if oldBalance >= threshold && newBalance < threshold {
siteName := s.getSiteName(ctx) siteName := s.getSiteName(ctx)
recipients := s.collectBalanceNotifyRecipients(user) recipients := s.collectBalanceNotifyRecipients(user)
...@@ -85,6 +76,30 @@ func (s *BalanceNotifyService) CheckBalanceAfterDeduction(ctx context.Context, u ...@@ -85,6 +76,30 @@ func (s *BalanceNotifyService) CheckBalanceAfterDeduction(ctx context.Context, u
} }
} }
// resolveEffectiveThreshold computes the actual USD threshold based on type and user settings.
func (s *BalanceNotifyService) resolveEffectiveThreshold(user *User, globalType string, globalValue float64) float64 {
// User-level override takes full precedence
if user.BalanceNotifyThreshold != nil {
thresholdType := user.BalanceNotifyThresholdType
if thresholdType == "" {
thresholdType = globalType
}
return computeThreshold(thresholdType, *user.BalanceNotifyThreshold, user.TotalRecharged)
}
return computeThreshold(globalType, globalValue, user.TotalRecharged)
}
// computeThreshold converts a threshold value to USD based on type.
func computeThreshold(thresholdType string, value, totalRecharged float64) float64 {
if thresholdType == ThresholdTypePercentage {
if totalRecharged <= 0 {
return 0 // no recharge history → skip percentage check
}
return totalRecharged * value / 100
}
return value // fixed USD amount
}
// quotaDim describes one quota dimension for notification checking. // quotaDim describes one quota dimension for notification checking.
type quotaDim struct { type quotaDim struct {
name string name string
...@@ -139,13 +154,21 @@ func (s *BalanceNotifyService) asyncSendQuotaAlert(adminEmails []string, account ...@@ -139,13 +154,21 @@ func (s *BalanceNotifyService) asyncSendQuotaAlert(adminEmails []string, account
} }
// getBalanceNotifyConfig reads global balance notification settings. // getBalanceNotifyConfig reads global balance notification settings.
func (s *BalanceNotifyService) getBalanceNotifyConfig(ctx context.Context) (enabled bool, threshold float64) { func (s *BalanceNotifyService) getBalanceNotifyConfig(ctx context.Context) (enabled bool, thresholdType string, threshold float64) {
keys := []string{SettingKeyBalanceLowNotifyEnabled, SettingKeyBalanceLowNotifyThreshold} keys := []string{
SettingKeyBalanceLowNotifyEnabled,
SettingKeyBalanceLowNotifyThresholdType,
SettingKeyBalanceLowNotifyThreshold,
}
settings, err := s.settingRepo.GetMultiple(ctx, keys) settings, err := s.settingRepo.GetMultiple(ctx, keys)
if err != nil { if err != nil {
return false, 0 return false, ThresholdTypeFixed, 0
} }
enabled = settings[SettingKeyBalanceLowNotifyEnabled] == "true" enabled = settings[SettingKeyBalanceLowNotifyEnabled] == "true"
thresholdType = settings[SettingKeyBalanceLowNotifyThresholdType]
if thresholdType == "" {
thresholdType = ThresholdTypeFixed
}
if v := settings[SettingKeyBalanceLowNotifyThreshold]; v != "" { if v := settings[SettingKeyBalanceLowNotifyThreshold]; v != "" {
if f, err := strconv.ParseFloat(v, 64); err == nil { if f, err := strconv.ParseFloat(v, 64); err == nil {
threshold = f threshold = f
......
...@@ -251,8 +251,13 @@ const ( ...@@ -251,8 +251,13 @@ const (
SettingKeyEnableCCHSigning = "enable_cch_signing" SettingKeyEnableCCHSigning = "enable_cch_signing"
// Balance Low Notification // Balance Low Notification
SettingKeyBalanceLowNotifyEnabled = "balance_low_notify_enabled" // 全局开关 SettingKeyBalanceLowNotifyEnabled = "balance_low_notify_enabled" // 全局开关
SettingKeyBalanceLowNotifyThreshold = "balance_low_notify_threshold" // 默认阈值(USD) SettingKeyBalanceLowNotifyThresholdType = "balance_low_notify_threshold_type" // "fixed" | "percentage"
SettingKeyBalanceLowNotifyThreshold = "balance_low_notify_threshold" // 默认阈值(USD 或百分比)
// Threshold type constants
ThresholdTypeFixed = "fixed"
ThresholdTypePercentage = "percentage"
// Account Quota Notification // Account Quota Notification
SettingKeyAccountQuotaNotifyEmails = "account_quota_notify_emails" // 管理员通知邮箱列表(JSON 数组) SettingKeyAccountQuotaNotifyEmails = "account_quota_notify_emails" // 管理员通知邮箱列表(JSON 数组)
......
...@@ -597,6 +597,11 @@ func (s *SettingService) UpdateSettings(ctx context.Context, settings *SystemSet ...@@ -597,6 +597,11 @@ func (s *SettingService) UpdateSettings(ctx context.Context, settings *SystemSet
// Balance low notification // Balance low notification
updates[SettingKeyBalanceLowNotifyEnabled] = strconv.FormatBool(settings.BalanceLowNotifyEnabled) updates[SettingKeyBalanceLowNotifyEnabled] = strconv.FormatBool(settings.BalanceLowNotifyEnabled)
thresholdType := settings.BalanceLowNotifyThresholdType
if thresholdType == "" {
thresholdType = ThresholdTypeFixed
}
updates[SettingKeyBalanceLowNotifyThresholdType] = thresholdType
updates[SettingKeyBalanceLowNotifyThreshold] = strconv.FormatFloat(settings.BalanceLowNotifyThreshold, 'f', 8, 64) updates[SettingKeyBalanceLowNotifyThreshold] = strconv.FormatFloat(settings.BalanceLowNotifyThreshold, 'f', 8, 64)
accountQuotaNotifyEmailsJSON, err := json.Marshal(settings.AccountQuotaNotifyEmails) accountQuotaNotifyEmailsJSON, err := json.Marshal(settings.AccountQuotaNotifyEmails)
if err != nil { if err != nil {
...@@ -1228,6 +1233,10 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin ...@@ -1228,6 +1233,10 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin
// Balance low notification // Balance low notification
result.BalanceLowNotifyEnabled = settings[SettingKeyBalanceLowNotifyEnabled] == "true" result.BalanceLowNotifyEnabled = settings[SettingKeyBalanceLowNotifyEnabled] == "true"
result.BalanceLowNotifyThresholdType = settings[SettingKeyBalanceLowNotifyThresholdType]
if result.BalanceLowNotifyThresholdType == "" {
result.BalanceLowNotifyThresholdType = ThresholdTypeFixed
}
if v, err := strconv.ParseFloat(settings[SettingKeyBalanceLowNotifyThreshold], 64); err == nil && v >= 0 { if v, err := strconv.ParseFloat(settings[SettingKeyBalanceLowNotifyThreshold], 64); err == nil && v >= 0 {
result.BalanceLowNotifyThreshold = v result.BalanceLowNotifyThreshold = v
} }
......
...@@ -108,8 +108,9 @@ type SystemSettings struct { ...@@ -108,8 +108,9 @@ type SystemSettings struct {
EnableCCHSigning bool // 是否对 billing header cch 进行签名(默认 false) EnableCCHSigning bool // 是否对 billing header cch 进行签名(默认 false)
// Balance low notification // Balance low notification
BalanceLowNotifyEnabled bool BalanceLowNotifyEnabled bool
BalanceLowNotifyThreshold float64 BalanceLowNotifyThresholdType string // "fixed" (default) | "percentage"
BalanceLowNotifyThreshold float64
// Account quota notification // Account quota notification
AccountQuotaNotifyEmails []string AccountQuotaNotifyEmails []string
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment