Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
377bffe2
Commit
377bffe2
authored
Feb 03, 2026
by
yangjianbo
Browse files
Merge branch 'main' into test
parents
99250ec5
31fe0178
Changes
235
Hide whitespace changes
Inline
Side-by-side
backend/ent/schema/user_subscription.go
View file @
377bffe2
...
...
@@ -4,7 +4,7 @@ import (
"time"
"github.com/Wei-Shaw/sub2api/ent/schema/mixins"
"github.com/Wei-Shaw/sub2api/internal/
service
"
"github.com/Wei-Shaw/sub2api/internal/
domain
"
"entgo.io/ent"
"entgo.io/ent/dialect"
...
...
@@ -44,7 +44,7 @@ func (UserSubscription) Fields() []ent.Field {
SchemaType
(
map
[
string
]
string
{
dialect
.
Postgres
:
"timestamptz"
}),
field
.
String
(
"status"
)
.
MaxLen
(
20
)
.
Default
(
service
.
SubscriptionStatusActive
),
Default
(
domain
.
SubscriptionStatusActive
),
field
.
Time
(
"daily_window_start"
)
.
Optional
()
.
...
...
backend/ent/tx.go
View file @
377bffe2
...
...
@@ -20,6 +20,10 @@ type Tx struct {
Account
*
AccountClient
// AccountGroup is the client for interacting with the AccountGroup builders.
AccountGroup
*
AccountGroupClient
// Announcement is the client for interacting with the Announcement builders.
Announcement
*
AnnouncementClient
// AnnouncementRead is the client for interacting with the AnnouncementRead builders.
AnnouncementRead
*
AnnouncementReadClient
// Group is the client for interacting with the Group builders.
Group
*
GroupClient
// PromoCode is the client for interacting with the PromoCode builders.
...
...
@@ -180,6 +184,8 @@ func (tx *Tx) init() {
tx
.
APIKey
=
NewAPIKeyClient
(
tx
.
config
)
tx
.
Account
=
NewAccountClient
(
tx
.
config
)
tx
.
AccountGroup
=
NewAccountGroupClient
(
tx
.
config
)
tx
.
Announcement
=
NewAnnouncementClient
(
tx
.
config
)
tx
.
AnnouncementRead
=
NewAnnouncementReadClient
(
tx
.
config
)
tx
.
Group
=
NewGroupClient
(
tx
.
config
)
tx
.
PromoCode
=
NewPromoCodeClient
(
tx
.
config
)
tx
.
PromoCodeUsage
=
NewPromoCodeUsageClient
(
tx
.
config
)
...
...
backend/ent/user.go
View file @
377bffe2
...
...
@@ -39,6 +39,12 @@ type User struct {
Username
string
`json:"username,omitempty"`
// Notes holds the value of the "notes" field.
Notes
string
`json:"notes,omitempty"`
// TotpSecretEncrypted holds the value of the "totp_secret_encrypted" field.
TotpSecretEncrypted
*
string
`json:"totp_secret_encrypted,omitempty"`
// TotpEnabled holds the value of the "totp_enabled" field.
TotpEnabled
bool
`json:"totp_enabled,omitempty"`
// TotpEnabledAt holds the value of the "totp_enabled_at" field.
TotpEnabledAt
*
time
.
Time
`json:"totp_enabled_at,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the UserQuery when eager-loading is set.
Edges
UserEdges
`json:"edges"`
...
...
@@ -55,6 +61,8 @@ type UserEdges struct {
Subscriptions
[]
*
UserSubscription
`json:"subscriptions,omitempty"`
// AssignedSubscriptions holds the value of the assigned_subscriptions edge.
AssignedSubscriptions
[]
*
UserSubscription
`json:"assigned_subscriptions,omitempty"`
// AnnouncementReads holds the value of the announcement_reads edge.
AnnouncementReads
[]
*
AnnouncementRead
`json:"announcement_reads,omitempty"`
// AllowedGroups holds the value of the allowed_groups edge.
AllowedGroups
[]
*
Group
`json:"allowed_groups,omitempty"`
// UsageLogs holds the value of the usage_logs edge.
...
...
@@ -67,7 +75,7 @@ type UserEdges struct {
UserAllowedGroups
[]
*
UserAllowedGroup
`json:"user_allowed_groups,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes
[
9
]
bool
loadedTypes
[
10
]
bool
}
// APIKeysOrErr returns the APIKeys value or an error if the edge
...
...
@@ -106,10 +114,19 @@ func (e UserEdges) AssignedSubscriptionsOrErr() ([]*UserSubscription, error) {
return
nil
,
&
NotLoadedError
{
edge
:
"assigned_subscriptions"
}
}
// AnnouncementReadsOrErr returns the AnnouncementReads value or an error if the edge
// was not loaded in eager-loading.
func
(
e
UserEdges
)
AnnouncementReadsOrErr
()
([]
*
AnnouncementRead
,
error
)
{
if
e
.
loadedTypes
[
4
]
{
return
e
.
AnnouncementReads
,
nil
}
return
nil
,
&
NotLoadedError
{
edge
:
"announcement_reads"
}
}
// AllowedGroupsOrErr returns the AllowedGroups value or an error if the edge
// was not loaded in eager-loading.
func
(
e
UserEdges
)
AllowedGroupsOrErr
()
([]
*
Group
,
error
)
{
if
e
.
loadedTypes
[
4
]
{
if
e
.
loadedTypes
[
5
]
{
return
e
.
AllowedGroups
,
nil
}
return
nil
,
&
NotLoadedError
{
edge
:
"allowed_groups"
}
...
...
@@ -118,7 +135,7 @@ func (e UserEdges) AllowedGroupsOrErr() ([]*Group, error) {
// UsageLogsOrErr returns the UsageLogs value or an error if the edge
// was not loaded in eager-loading.
func
(
e
UserEdges
)
UsageLogsOrErr
()
([]
*
UsageLog
,
error
)
{
if
e
.
loadedTypes
[
5
]
{
if
e
.
loadedTypes
[
6
]
{
return
e
.
UsageLogs
,
nil
}
return
nil
,
&
NotLoadedError
{
edge
:
"usage_logs"
}
...
...
@@ -127,7 +144,7 @@ func (e UserEdges) UsageLogsOrErr() ([]*UsageLog, error) {
// AttributeValuesOrErr returns the AttributeValues value or an error if the edge
// was not loaded in eager-loading.
func
(
e
UserEdges
)
AttributeValuesOrErr
()
([]
*
UserAttributeValue
,
error
)
{
if
e
.
loadedTypes
[
6
]
{
if
e
.
loadedTypes
[
7
]
{
return
e
.
AttributeValues
,
nil
}
return
nil
,
&
NotLoadedError
{
edge
:
"attribute_values"
}
...
...
@@ -136,7 +153,7 @@ func (e UserEdges) AttributeValuesOrErr() ([]*UserAttributeValue, error) {
// PromoCodeUsagesOrErr returns the PromoCodeUsages value or an error if the edge
// was not loaded in eager-loading.
func
(
e
UserEdges
)
PromoCodeUsagesOrErr
()
([]
*
PromoCodeUsage
,
error
)
{
if
e
.
loadedTypes
[
7
]
{
if
e
.
loadedTypes
[
8
]
{
return
e
.
PromoCodeUsages
,
nil
}
return
nil
,
&
NotLoadedError
{
edge
:
"promo_code_usages"
}
...
...
@@ -145,7 +162,7 @@ func (e UserEdges) PromoCodeUsagesOrErr() ([]*PromoCodeUsage, error) {
// UserAllowedGroupsOrErr returns the UserAllowedGroups value or an error if the edge
// was not loaded in eager-loading.
func
(
e
UserEdges
)
UserAllowedGroupsOrErr
()
([]
*
UserAllowedGroup
,
error
)
{
if
e
.
loadedTypes
[
8
]
{
if
e
.
loadedTypes
[
9
]
{
return
e
.
UserAllowedGroups
,
nil
}
return
nil
,
&
NotLoadedError
{
edge
:
"user_allowed_groups"
}
...
...
@@ -156,13 +173,15 @@ func (*User) scanValues(columns []string) ([]any, error) {
values
:=
make
([]
any
,
len
(
columns
))
for
i
:=
range
columns
{
switch
columns
[
i
]
{
case
user
.
FieldTotpEnabled
:
values
[
i
]
=
new
(
sql
.
NullBool
)
case
user
.
FieldBalance
:
values
[
i
]
=
new
(
sql
.
NullFloat64
)
case
user
.
FieldID
,
user
.
FieldConcurrency
:
values
[
i
]
=
new
(
sql
.
NullInt64
)
case
user
.
FieldEmail
,
user
.
FieldPasswordHash
,
user
.
FieldRole
,
user
.
FieldStatus
,
user
.
FieldUsername
,
user
.
FieldNotes
:
case
user
.
FieldEmail
,
user
.
FieldPasswordHash
,
user
.
FieldRole
,
user
.
FieldStatus
,
user
.
FieldUsername
,
user
.
FieldNotes
,
user
.
FieldTotpSecretEncrypted
:
values
[
i
]
=
new
(
sql
.
NullString
)
case
user
.
FieldCreatedAt
,
user
.
FieldUpdatedAt
,
user
.
FieldDeletedAt
:
case
user
.
FieldCreatedAt
,
user
.
FieldUpdatedAt
,
user
.
FieldDeletedAt
,
user
.
FieldTotpEnabledAt
:
values
[
i
]
=
new
(
sql
.
NullTime
)
default
:
values
[
i
]
=
new
(
sql
.
UnknownType
)
...
...
@@ -252,6 +271,26 @@ func (_m *User) assignValues(columns []string, values []any) error {
}
else
if
value
.
Valid
{
_m
.
Notes
=
value
.
String
}
case
user
.
FieldTotpSecretEncrypted
:
if
value
,
ok
:=
values
[
i
]
.
(
*
sql
.
NullString
);
!
ok
{
return
fmt
.
Errorf
(
"unexpected type %T for field totp_secret_encrypted"
,
values
[
i
])
}
else
if
value
.
Valid
{
_m
.
TotpSecretEncrypted
=
new
(
string
)
*
_m
.
TotpSecretEncrypted
=
value
.
String
}
case
user
.
FieldTotpEnabled
:
if
value
,
ok
:=
values
[
i
]
.
(
*
sql
.
NullBool
);
!
ok
{
return
fmt
.
Errorf
(
"unexpected type %T for field totp_enabled"
,
values
[
i
])
}
else
if
value
.
Valid
{
_m
.
TotpEnabled
=
value
.
Bool
}
case
user
.
FieldTotpEnabledAt
:
if
value
,
ok
:=
values
[
i
]
.
(
*
sql
.
NullTime
);
!
ok
{
return
fmt
.
Errorf
(
"unexpected type %T for field totp_enabled_at"
,
values
[
i
])
}
else
if
value
.
Valid
{
_m
.
TotpEnabledAt
=
new
(
time
.
Time
)
*
_m
.
TotpEnabledAt
=
value
.
Time
}
default
:
_m
.
selectValues
.
Set
(
columns
[
i
],
values
[
i
])
}
...
...
@@ -285,6 +324,11 @@ func (_m *User) QueryAssignedSubscriptions() *UserSubscriptionQuery {
return
NewUserClient
(
_m
.
config
)
.
QueryAssignedSubscriptions
(
_m
)
}
// QueryAnnouncementReads queries the "announcement_reads" edge of the User entity.
func
(
_m
*
User
)
QueryAnnouncementReads
()
*
AnnouncementReadQuery
{
return
NewUserClient
(
_m
.
config
)
.
QueryAnnouncementReads
(
_m
)
}
// QueryAllowedGroups queries the "allowed_groups" edge of the User entity.
func
(
_m
*
User
)
QueryAllowedGroups
()
*
GroupQuery
{
return
NewUserClient
(
_m
.
config
)
.
QueryAllowedGroups
(
_m
)
...
...
@@ -367,6 +411,19 @@ func (_m *User) String() string {
builder
.
WriteString
(
", "
)
builder
.
WriteString
(
"notes="
)
builder
.
WriteString
(
_m
.
Notes
)
builder
.
WriteString
(
", "
)
if
v
:=
_m
.
TotpSecretEncrypted
;
v
!=
nil
{
builder
.
WriteString
(
"totp_secret_encrypted="
)
builder
.
WriteString
(
*
v
)
}
builder
.
WriteString
(
", "
)
builder
.
WriteString
(
"totp_enabled="
)
builder
.
WriteString
(
fmt
.
Sprintf
(
"%v"
,
_m
.
TotpEnabled
))
builder
.
WriteString
(
", "
)
if
v
:=
_m
.
TotpEnabledAt
;
v
!=
nil
{
builder
.
WriteString
(
"totp_enabled_at="
)
builder
.
WriteString
(
v
.
Format
(
time
.
ANSIC
))
}
builder
.
WriteByte
(
')'
)
return
builder
.
String
()
}
...
...
backend/ent/user/user.go
View file @
377bffe2
...
...
@@ -37,6 +37,12 @@ const (
FieldUsername
=
"username"
// FieldNotes holds the string denoting the notes field in the database.
FieldNotes
=
"notes"
// FieldTotpSecretEncrypted holds the string denoting the totp_secret_encrypted field in the database.
FieldTotpSecretEncrypted
=
"totp_secret_encrypted"
// FieldTotpEnabled holds the string denoting the totp_enabled field in the database.
FieldTotpEnabled
=
"totp_enabled"
// FieldTotpEnabledAt holds the string denoting the totp_enabled_at field in the database.
FieldTotpEnabledAt
=
"totp_enabled_at"
// EdgeAPIKeys holds the string denoting the api_keys edge name in mutations.
EdgeAPIKeys
=
"api_keys"
// EdgeRedeemCodes holds the string denoting the redeem_codes edge name in mutations.
...
...
@@ -45,6 +51,8 @@ const (
EdgeSubscriptions
=
"subscriptions"
// EdgeAssignedSubscriptions holds the string denoting the assigned_subscriptions edge name in mutations.
EdgeAssignedSubscriptions
=
"assigned_subscriptions"
// EdgeAnnouncementReads holds the string denoting the announcement_reads edge name in mutations.
EdgeAnnouncementReads
=
"announcement_reads"
// EdgeAllowedGroups holds the string denoting the allowed_groups edge name in mutations.
EdgeAllowedGroups
=
"allowed_groups"
// EdgeUsageLogs holds the string denoting the usage_logs edge name in mutations.
...
...
@@ -85,6 +93,13 @@ const (
AssignedSubscriptionsInverseTable
=
"user_subscriptions"
// AssignedSubscriptionsColumn is the table column denoting the assigned_subscriptions relation/edge.
AssignedSubscriptionsColumn
=
"assigned_by"
// AnnouncementReadsTable is the table that holds the announcement_reads relation/edge.
AnnouncementReadsTable
=
"announcement_reads"
// AnnouncementReadsInverseTable is the table name for the AnnouncementRead entity.
// It exists in this package in order to avoid circular dependency with the "announcementread" package.
AnnouncementReadsInverseTable
=
"announcement_reads"
// AnnouncementReadsColumn is the table column denoting the announcement_reads relation/edge.
AnnouncementReadsColumn
=
"user_id"
// AllowedGroupsTable is the table that holds the allowed_groups relation/edge. The primary key declared below.
AllowedGroupsTable
=
"user_allowed_groups"
// AllowedGroupsInverseTable is the table name for the Group entity.
...
...
@@ -134,6 +149,9 @@ var Columns = []string{
FieldStatus
,
FieldUsername
,
FieldNotes
,
FieldTotpSecretEncrypted
,
FieldTotpEnabled
,
FieldTotpEnabledAt
,
}
var
(
...
...
@@ -188,6 +206,8 @@ var (
UsernameValidator
func
(
string
)
error
// DefaultNotes holds the default value on creation for the "notes" field.
DefaultNotes
string
// DefaultTotpEnabled holds the default value on creation for the "totp_enabled" field.
DefaultTotpEnabled
bool
)
// OrderOption defines the ordering options for the User queries.
...
...
@@ -253,6 +273,21 @@ func ByNotes(opts ...sql.OrderTermOption) OrderOption {
return
sql
.
OrderByField
(
FieldNotes
,
opts
...
)
.
ToFunc
()
}
// ByTotpSecretEncrypted orders the results by the totp_secret_encrypted field.
func
ByTotpSecretEncrypted
(
opts
...
sql
.
OrderTermOption
)
OrderOption
{
return
sql
.
OrderByField
(
FieldTotpSecretEncrypted
,
opts
...
)
.
ToFunc
()
}
// ByTotpEnabled orders the results by the totp_enabled field.
func
ByTotpEnabled
(
opts
...
sql
.
OrderTermOption
)
OrderOption
{
return
sql
.
OrderByField
(
FieldTotpEnabled
,
opts
...
)
.
ToFunc
()
}
// ByTotpEnabledAt orders the results by the totp_enabled_at field.
func
ByTotpEnabledAt
(
opts
...
sql
.
OrderTermOption
)
OrderOption
{
return
sql
.
OrderByField
(
FieldTotpEnabledAt
,
opts
...
)
.
ToFunc
()
}
// ByAPIKeysCount orders the results by api_keys count.
func
ByAPIKeysCount
(
opts
...
sql
.
OrderTermOption
)
OrderOption
{
return
func
(
s
*
sql
.
Selector
)
{
...
...
@@ -309,6 +344,20 @@ func ByAssignedSubscriptions(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOp
}
}
// ByAnnouncementReadsCount orders the results by announcement_reads count.
func
ByAnnouncementReadsCount
(
opts
...
sql
.
OrderTermOption
)
OrderOption
{
return
func
(
s
*
sql
.
Selector
)
{
sqlgraph
.
OrderByNeighborsCount
(
s
,
newAnnouncementReadsStep
(),
opts
...
)
}
}
// ByAnnouncementReads orders the results by announcement_reads terms.
func
ByAnnouncementReads
(
term
sql
.
OrderTerm
,
terms
...
sql
.
OrderTerm
)
OrderOption
{
return
func
(
s
*
sql
.
Selector
)
{
sqlgraph
.
OrderByNeighborTerms
(
s
,
newAnnouncementReadsStep
(),
append
([]
sql
.
OrderTerm
{
term
},
terms
...
)
...
)
}
}
// ByAllowedGroupsCount orders the results by allowed_groups count.
func
ByAllowedGroupsCount
(
opts
...
sql
.
OrderTermOption
)
OrderOption
{
return
func
(
s
*
sql
.
Selector
)
{
...
...
@@ -406,6 +455,13 @@ func newAssignedSubscriptionsStep() *sqlgraph.Step {
sqlgraph
.
Edge
(
sqlgraph
.
O2M
,
false
,
AssignedSubscriptionsTable
,
AssignedSubscriptionsColumn
),
)
}
func
newAnnouncementReadsStep
()
*
sqlgraph
.
Step
{
return
sqlgraph
.
NewStep
(
sqlgraph
.
From
(
Table
,
FieldID
),
sqlgraph
.
To
(
AnnouncementReadsInverseTable
,
FieldID
),
sqlgraph
.
Edge
(
sqlgraph
.
O2M
,
false
,
AnnouncementReadsTable
,
AnnouncementReadsColumn
),
)
}
func
newAllowedGroupsStep
()
*
sqlgraph
.
Step
{
return
sqlgraph
.
NewStep
(
sqlgraph
.
From
(
Table
,
FieldID
),
...
...
backend/ent/user/where.go
View file @
377bffe2
...
...
@@ -110,6 +110,21 @@ func Notes(v string) predicate.User {
return
predicate
.
User
(
sql
.
FieldEQ
(
FieldNotes
,
v
))
}
// TotpSecretEncrypted applies equality check predicate on the "totp_secret_encrypted" field. It's identical to TotpSecretEncryptedEQ.
func
TotpSecretEncrypted
(
v
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldEQ
(
FieldTotpSecretEncrypted
,
v
))
}
// TotpEnabled applies equality check predicate on the "totp_enabled" field. It's identical to TotpEnabledEQ.
func
TotpEnabled
(
v
bool
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldEQ
(
FieldTotpEnabled
,
v
))
}
// TotpEnabledAt applies equality check predicate on the "totp_enabled_at" field. It's identical to TotpEnabledAtEQ.
func
TotpEnabledAt
(
v
time
.
Time
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldEQ
(
FieldTotpEnabledAt
,
v
))
}
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
func
CreatedAtEQ
(
v
time
.
Time
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldEQ
(
FieldCreatedAt
,
v
))
...
...
@@ -710,6 +725,141 @@ func NotesContainsFold(v string) predicate.User {
return
predicate
.
User
(
sql
.
FieldContainsFold
(
FieldNotes
,
v
))
}
// TotpSecretEncryptedEQ applies the EQ predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedEQ
(
v
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldEQ
(
FieldTotpSecretEncrypted
,
v
))
}
// TotpSecretEncryptedNEQ applies the NEQ predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedNEQ
(
v
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldNEQ
(
FieldTotpSecretEncrypted
,
v
))
}
// TotpSecretEncryptedIn applies the In predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedIn
(
vs
...
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldIn
(
FieldTotpSecretEncrypted
,
vs
...
))
}
// TotpSecretEncryptedNotIn applies the NotIn predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedNotIn
(
vs
...
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldNotIn
(
FieldTotpSecretEncrypted
,
vs
...
))
}
// TotpSecretEncryptedGT applies the GT predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedGT
(
v
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldGT
(
FieldTotpSecretEncrypted
,
v
))
}
// TotpSecretEncryptedGTE applies the GTE predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedGTE
(
v
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldGTE
(
FieldTotpSecretEncrypted
,
v
))
}
// TotpSecretEncryptedLT applies the LT predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedLT
(
v
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldLT
(
FieldTotpSecretEncrypted
,
v
))
}
// TotpSecretEncryptedLTE applies the LTE predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedLTE
(
v
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldLTE
(
FieldTotpSecretEncrypted
,
v
))
}
// TotpSecretEncryptedContains applies the Contains predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedContains
(
v
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldContains
(
FieldTotpSecretEncrypted
,
v
))
}
// TotpSecretEncryptedHasPrefix applies the HasPrefix predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedHasPrefix
(
v
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldHasPrefix
(
FieldTotpSecretEncrypted
,
v
))
}
// TotpSecretEncryptedHasSuffix applies the HasSuffix predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedHasSuffix
(
v
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldHasSuffix
(
FieldTotpSecretEncrypted
,
v
))
}
// TotpSecretEncryptedIsNil applies the IsNil predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedIsNil
()
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldIsNull
(
FieldTotpSecretEncrypted
))
}
// TotpSecretEncryptedNotNil applies the NotNil predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedNotNil
()
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldNotNull
(
FieldTotpSecretEncrypted
))
}
// TotpSecretEncryptedEqualFold applies the EqualFold predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedEqualFold
(
v
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldEqualFold
(
FieldTotpSecretEncrypted
,
v
))
}
// TotpSecretEncryptedContainsFold applies the ContainsFold predicate on the "totp_secret_encrypted" field.
func
TotpSecretEncryptedContainsFold
(
v
string
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldContainsFold
(
FieldTotpSecretEncrypted
,
v
))
}
// TotpEnabledEQ applies the EQ predicate on the "totp_enabled" field.
func
TotpEnabledEQ
(
v
bool
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldEQ
(
FieldTotpEnabled
,
v
))
}
// TotpEnabledNEQ applies the NEQ predicate on the "totp_enabled" field.
func
TotpEnabledNEQ
(
v
bool
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldNEQ
(
FieldTotpEnabled
,
v
))
}
// TotpEnabledAtEQ applies the EQ predicate on the "totp_enabled_at" field.
func
TotpEnabledAtEQ
(
v
time
.
Time
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldEQ
(
FieldTotpEnabledAt
,
v
))
}
// TotpEnabledAtNEQ applies the NEQ predicate on the "totp_enabled_at" field.
func
TotpEnabledAtNEQ
(
v
time
.
Time
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldNEQ
(
FieldTotpEnabledAt
,
v
))
}
// TotpEnabledAtIn applies the In predicate on the "totp_enabled_at" field.
func
TotpEnabledAtIn
(
vs
...
time
.
Time
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldIn
(
FieldTotpEnabledAt
,
vs
...
))
}
// TotpEnabledAtNotIn applies the NotIn predicate on the "totp_enabled_at" field.
func
TotpEnabledAtNotIn
(
vs
...
time
.
Time
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldNotIn
(
FieldTotpEnabledAt
,
vs
...
))
}
// TotpEnabledAtGT applies the GT predicate on the "totp_enabled_at" field.
func
TotpEnabledAtGT
(
v
time
.
Time
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldGT
(
FieldTotpEnabledAt
,
v
))
}
// TotpEnabledAtGTE applies the GTE predicate on the "totp_enabled_at" field.
func
TotpEnabledAtGTE
(
v
time
.
Time
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldGTE
(
FieldTotpEnabledAt
,
v
))
}
// TotpEnabledAtLT applies the LT predicate on the "totp_enabled_at" field.
func
TotpEnabledAtLT
(
v
time
.
Time
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldLT
(
FieldTotpEnabledAt
,
v
))
}
// TotpEnabledAtLTE applies the LTE predicate on the "totp_enabled_at" field.
func
TotpEnabledAtLTE
(
v
time
.
Time
)
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldLTE
(
FieldTotpEnabledAt
,
v
))
}
// TotpEnabledAtIsNil applies the IsNil predicate on the "totp_enabled_at" field.
func
TotpEnabledAtIsNil
()
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldIsNull
(
FieldTotpEnabledAt
))
}
// TotpEnabledAtNotNil applies the NotNil predicate on the "totp_enabled_at" field.
func
TotpEnabledAtNotNil
()
predicate
.
User
{
return
predicate
.
User
(
sql
.
FieldNotNull
(
FieldTotpEnabledAt
))
}
// HasAPIKeys applies the HasEdge predicate on the "api_keys" edge.
func
HasAPIKeys
()
predicate
.
User
{
return
predicate
.
User
(
func
(
s
*
sql
.
Selector
)
{
...
...
@@ -802,6 +952,29 @@ func HasAssignedSubscriptionsWith(preds ...predicate.UserSubscription) predicate
})
}
// HasAnnouncementReads applies the HasEdge predicate on the "announcement_reads" edge.
func
HasAnnouncementReads
()
predicate
.
User
{
return
predicate
.
User
(
func
(
s
*
sql
.
Selector
)
{
step
:=
sqlgraph
.
NewStep
(
sqlgraph
.
From
(
Table
,
FieldID
),
sqlgraph
.
Edge
(
sqlgraph
.
O2M
,
false
,
AnnouncementReadsTable
,
AnnouncementReadsColumn
),
)
sqlgraph
.
HasNeighbors
(
s
,
step
)
})
}
// HasAnnouncementReadsWith applies the HasEdge predicate on the "announcement_reads" edge with a given conditions (other predicates).
func
HasAnnouncementReadsWith
(
preds
...
predicate
.
AnnouncementRead
)
predicate
.
User
{
return
predicate
.
User
(
func
(
s
*
sql
.
Selector
)
{
step
:=
newAnnouncementReadsStep
()
sqlgraph
.
HasNeighborsWith
(
s
,
step
,
func
(
s
*
sql
.
Selector
)
{
for
_
,
p
:=
range
preds
{
p
(
s
)
}
})
})
}
// HasAllowedGroups applies the HasEdge predicate on the "allowed_groups" edge.
func
HasAllowedGroups
()
predicate
.
User
{
return
predicate
.
User
(
func
(
s
*
sql
.
Selector
)
{
...
...
backend/ent/user_create.go
View file @
377bffe2
...
...
@@ -11,6 +11,7 @@ import (
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/Wei-Shaw/sub2api/ent/announcementread"
"github.com/Wei-Shaw/sub2api/ent/apikey"
"github.com/Wei-Shaw/sub2api/ent/group"
"github.com/Wei-Shaw/sub2api/ent/promocodeusage"
...
...
@@ -167,6 +168,48 @@ func (_c *UserCreate) SetNillableNotes(v *string) *UserCreate {
return
_c
}
// SetTotpSecretEncrypted sets the "totp_secret_encrypted" field.
func
(
_c
*
UserCreate
)
SetTotpSecretEncrypted
(
v
string
)
*
UserCreate
{
_c
.
mutation
.
SetTotpSecretEncrypted
(
v
)
return
_c
}
// SetNillableTotpSecretEncrypted sets the "totp_secret_encrypted" field if the given value is not nil.
func
(
_c
*
UserCreate
)
SetNillableTotpSecretEncrypted
(
v
*
string
)
*
UserCreate
{
if
v
!=
nil
{
_c
.
SetTotpSecretEncrypted
(
*
v
)
}
return
_c
}
// SetTotpEnabled sets the "totp_enabled" field.
func
(
_c
*
UserCreate
)
SetTotpEnabled
(
v
bool
)
*
UserCreate
{
_c
.
mutation
.
SetTotpEnabled
(
v
)
return
_c
}
// SetNillableTotpEnabled sets the "totp_enabled" field if the given value is not nil.
func
(
_c
*
UserCreate
)
SetNillableTotpEnabled
(
v
*
bool
)
*
UserCreate
{
if
v
!=
nil
{
_c
.
SetTotpEnabled
(
*
v
)
}
return
_c
}
// SetTotpEnabledAt sets the "totp_enabled_at" field.
func
(
_c
*
UserCreate
)
SetTotpEnabledAt
(
v
time
.
Time
)
*
UserCreate
{
_c
.
mutation
.
SetTotpEnabledAt
(
v
)
return
_c
}
// SetNillableTotpEnabledAt sets the "totp_enabled_at" field if the given value is not nil.
func
(
_c
*
UserCreate
)
SetNillableTotpEnabledAt
(
v
*
time
.
Time
)
*
UserCreate
{
if
v
!=
nil
{
_c
.
SetTotpEnabledAt
(
*
v
)
}
return
_c
}
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func
(
_c
*
UserCreate
)
AddAPIKeyIDs
(
ids
...
int64
)
*
UserCreate
{
_c
.
mutation
.
AddAPIKeyIDs
(
ids
...
)
...
...
@@ -227,6 +270,21 @@ func (_c *UserCreate) AddAssignedSubscriptions(v ...*UserSubscription) *UserCrea
return
_c
.
AddAssignedSubscriptionIDs
(
ids
...
)
}
// AddAnnouncementReadIDs adds the "announcement_reads" edge to the AnnouncementRead entity by IDs.
func
(
_c
*
UserCreate
)
AddAnnouncementReadIDs
(
ids
...
int64
)
*
UserCreate
{
_c
.
mutation
.
AddAnnouncementReadIDs
(
ids
...
)
return
_c
}
// AddAnnouncementReads adds the "announcement_reads" edges to the AnnouncementRead entity.
func
(
_c
*
UserCreate
)
AddAnnouncementReads
(
v
...*
AnnouncementRead
)
*
UserCreate
{
ids
:=
make
([]
int64
,
len
(
v
))
for
i
:=
range
v
{
ids
[
i
]
=
v
[
i
]
.
ID
}
return
_c
.
AddAnnouncementReadIDs
(
ids
...
)
}
// AddAllowedGroupIDs adds the "allowed_groups" edge to the Group entity by IDs.
func
(
_c
*
UserCreate
)
AddAllowedGroupIDs
(
ids
...
int64
)
*
UserCreate
{
_c
.
mutation
.
AddAllowedGroupIDs
(
ids
...
)
...
...
@@ -362,6 +420,10 @@ func (_c *UserCreate) defaults() error {
v
:=
user
.
DefaultNotes
_c
.
mutation
.
SetNotes
(
v
)
}
if
_
,
ok
:=
_c
.
mutation
.
TotpEnabled
();
!
ok
{
v
:=
user
.
DefaultTotpEnabled
_c
.
mutation
.
SetTotpEnabled
(
v
)
}
return
nil
}
...
...
@@ -422,6 +484,9 @@ func (_c *UserCreate) check() error {
if
_
,
ok
:=
_c
.
mutation
.
Notes
();
!
ok
{
return
&
ValidationError
{
Name
:
"notes"
,
err
:
errors
.
New
(
`ent: missing required field "User.notes"`
)}
}
if
_
,
ok
:=
_c
.
mutation
.
TotpEnabled
();
!
ok
{
return
&
ValidationError
{
Name
:
"totp_enabled"
,
err
:
errors
.
New
(
`ent: missing required field "User.totp_enabled"`
)}
}
return
nil
}
...
...
@@ -493,6 +558,18 @@ func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
_spec
.
SetField
(
user
.
FieldNotes
,
field
.
TypeString
,
value
)
_node
.
Notes
=
value
}
if
value
,
ok
:=
_c
.
mutation
.
TotpSecretEncrypted
();
ok
{
_spec
.
SetField
(
user
.
FieldTotpSecretEncrypted
,
field
.
TypeString
,
value
)
_node
.
TotpSecretEncrypted
=
&
value
}
if
value
,
ok
:=
_c
.
mutation
.
TotpEnabled
();
ok
{
_spec
.
SetField
(
user
.
FieldTotpEnabled
,
field
.
TypeBool
,
value
)
_node
.
TotpEnabled
=
value
}
if
value
,
ok
:=
_c
.
mutation
.
TotpEnabledAt
();
ok
{
_spec
.
SetField
(
user
.
FieldTotpEnabledAt
,
field
.
TypeTime
,
value
)
_node
.
TotpEnabledAt
=
&
value
}
if
nodes
:=
_c
.
mutation
.
APIKeysIDs
();
len
(
nodes
)
>
0
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
O2M
,
...
...
@@ -557,6 +634,22 @@ func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
}
_spec
.
Edges
=
append
(
_spec
.
Edges
,
edge
)
}
if
nodes
:=
_c
.
mutation
.
AnnouncementReadsIDs
();
len
(
nodes
)
>
0
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
O2M
,
Inverse
:
false
,
Table
:
user
.
AnnouncementReadsTable
,
Columns
:
[]
string
{
user
.
AnnouncementReadsColumn
},
Bidi
:
false
,
Target
:
&
sqlgraph
.
EdgeTarget
{
IDSpec
:
sqlgraph
.
NewFieldSpec
(
announcementread
.
FieldID
,
field
.
TypeInt64
),
},
}
for
_
,
k
:=
range
nodes
{
edge
.
Target
.
Nodes
=
append
(
edge
.
Target
.
Nodes
,
k
)
}
_spec
.
Edges
=
append
(
_spec
.
Edges
,
edge
)
}
if
nodes
:=
_c
.
mutation
.
AllowedGroupsIDs
();
len
(
nodes
)
>
0
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
M2M
,
...
...
@@ -815,6 +908,54 @@ func (u *UserUpsert) UpdateNotes() *UserUpsert {
return
u
}
// SetTotpSecretEncrypted sets the "totp_secret_encrypted" field.
func
(
u
*
UserUpsert
)
SetTotpSecretEncrypted
(
v
string
)
*
UserUpsert
{
u
.
Set
(
user
.
FieldTotpSecretEncrypted
,
v
)
return
u
}
// UpdateTotpSecretEncrypted sets the "totp_secret_encrypted" field to the value that was provided on create.
func
(
u
*
UserUpsert
)
UpdateTotpSecretEncrypted
()
*
UserUpsert
{
u
.
SetExcluded
(
user
.
FieldTotpSecretEncrypted
)
return
u
}
// ClearTotpSecretEncrypted clears the value of the "totp_secret_encrypted" field.
func
(
u
*
UserUpsert
)
ClearTotpSecretEncrypted
()
*
UserUpsert
{
u
.
SetNull
(
user
.
FieldTotpSecretEncrypted
)
return
u
}
// SetTotpEnabled sets the "totp_enabled" field.
func
(
u
*
UserUpsert
)
SetTotpEnabled
(
v
bool
)
*
UserUpsert
{
u
.
Set
(
user
.
FieldTotpEnabled
,
v
)
return
u
}
// UpdateTotpEnabled sets the "totp_enabled" field to the value that was provided on create.
func
(
u
*
UserUpsert
)
UpdateTotpEnabled
()
*
UserUpsert
{
u
.
SetExcluded
(
user
.
FieldTotpEnabled
)
return
u
}
// SetTotpEnabledAt sets the "totp_enabled_at" field.
func
(
u
*
UserUpsert
)
SetTotpEnabledAt
(
v
time
.
Time
)
*
UserUpsert
{
u
.
Set
(
user
.
FieldTotpEnabledAt
,
v
)
return
u
}
// UpdateTotpEnabledAt sets the "totp_enabled_at" field to the value that was provided on create.
func
(
u
*
UserUpsert
)
UpdateTotpEnabledAt
()
*
UserUpsert
{
u
.
SetExcluded
(
user
.
FieldTotpEnabledAt
)
return
u
}
// ClearTotpEnabledAt clears the value of the "totp_enabled_at" field.
func
(
u
*
UserUpsert
)
ClearTotpEnabledAt
()
*
UserUpsert
{
u
.
SetNull
(
user
.
FieldTotpEnabledAt
)
return
u
}
// UpdateNewValues updates the mutable fields using the new values that were set on create.
// Using this option is equivalent to using:
//
...
...
@@ -1021,6 +1162,62 @@ func (u *UserUpsertOne) UpdateNotes() *UserUpsertOne {
})
}
// SetTotpSecretEncrypted sets the "totp_secret_encrypted" field.
func
(
u
*
UserUpsertOne
)
SetTotpSecretEncrypted
(
v
string
)
*
UserUpsertOne
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
SetTotpSecretEncrypted
(
v
)
})
}
// UpdateTotpSecretEncrypted sets the "totp_secret_encrypted" field to the value that was provided on create.
func
(
u
*
UserUpsertOne
)
UpdateTotpSecretEncrypted
()
*
UserUpsertOne
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
UpdateTotpSecretEncrypted
()
})
}
// ClearTotpSecretEncrypted clears the value of the "totp_secret_encrypted" field.
func
(
u
*
UserUpsertOne
)
ClearTotpSecretEncrypted
()
*
UserUpsertOne
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
ClearTotpSecretEncrypted
()
})
}
// SetTotpEnabled sets the "totp_enabled" field.
func
(
u
*
UserUpsertOne
)
SetTotpEnabled
(
v
bool
)
*
UserUpsertOne
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
SetTotpEnabled
(
v
)
})
}
// UpdateTotpEnabled sets the "totp_enabled" field to the value that was provided on create.
func
(
u
*
UserUpsertOne
)
UpdateTotpEnabled
()
*
UserUpsertOne
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
UpdateTotpEnabled
()
})
}
// SetTotpEnabledAt sets the "totp_enabled_at" field.
func
(
u
*
UserUpsertOne
)
SetTotpEnabledAt
(
v
time
.
Time
)
*
UserUpsertOne
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
SetTotpEnabledAt
(
v
)
})
}
// UpdateTotpEnabledAt sets the "totp_enabled_at" field to the value that was provided on create.
func
(
u
*
UserUpsertOne
)
UpdateTotpEnabledAt
()
*
UserUpsertOne
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
UpdateTotpEnabledAt
()
})
}
// ClearTotpEnabledAt clears the value of the "totp_enabled_at" field.
func
(
u
*
UserUpsertOne
)
ClearTotpEnabledAt
()
*
UserUpsertOne
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
ClearTotpEnabledAt
()
})
}
// Exec executes the query.
func
(
u
*
UserUpsertOne
)
Exec
(
ctx
context
.
Context
)
error
{
if
len
(
u
.
create
.
conflict
)
==
0
{
...
...
@@ -1393,6 +1590,62 @@ func (u *UserUpsertBulk) UpdateNotes() *UserUpsertBulk {
})
}
// SetTotpSecretEncrypted sets the "totp_secret_encrypted" field.
func
(
u
*
UserUpsertBulk
)
SetTotpSecretEncrypted
(
v
string
)
*
UserUpsertBulk
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
SetTotpSecretEncrypted
(
v
)
})
}
// UpdateTotpSecretEncrypted sets the "totp_secret_encrypted" field to the value that was provided on create.
func
(
u
*
UserUpsertBulk
)
UpdateTotpSecretEncrypted
()
*
UserUpsertBulk
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
UpdateTotpSecretEncrypted
()
})
}
// ClearTotpSecretEncrypted clears the value of the "totp_secret_encrypted" field.
func
(
u
*
UserUpsertBulk
)
ClearTotpSecretEncrypted
()
*
UserUpsertBulk
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
ClearTotpSecretEncrypted
()
})
}
// SetTotpEnabled sets the "totp_enabled" field.
func
(
u
*
UserUpsertBulk
)
SetTotpEnabled
(
v
bool
)
*
UserUpsertBulk
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
SetTotpEnabled
(
v
)
})
}
// UpdateTotpEnabled sets the "totp_enabled" field to the value that was provided on create.
func
(
u
*
UserUpsertBulk
)
UpdateTotpEnabled
()
*
UserUpsertBulk
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
UpdateTotpEnabled
()
})
}
// SetTotpEnabledAt sets the "totp_enabled_at" field.
func
(
u
*
UserUpsertBulk
)
SetTotpEnabledAt
(
v
time
.
Time
)
*
UserUpsertBulk
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
SetTotpEnabledAt
(
v
)
})
}
// UpdateTotpEnabledAt sets the "totp_enabled_at" field to the value that was provided on create.
func
(
u
*
UserUpsertBulk
)
UpdateTotpEnabledAt
()
*
UserUpsertBulk
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
UpdateTotpEnabledAt
()
})
}
// ClearTotpEnabledAt clears the value of the "totp_enabled_at" field.
func
(
u
*
UserUpsertBulk
)
ClearTotpEnabledAt
()
*
UserUpsertBulk
{
return
u
.
Update
(
func
(
s
*
UserUpsert
)
{
s
.
ClearTotpEnabledAt
()
})
}
// Exec executes the query.
func
(
u
*
UserUpsertBulk
)
Exec
(
ctx
context
.
Context
)
error
{
if
u
.
create
.
err
!=
nil
{
...
...
backend/ent/user_query.go
View file @
377bffe2
...
...
@@ -13,6 +13,7 @@ import (
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/Wei-Shaw/sub2api/ent/announcementread"
"github.com/Wei-Shaw/sub2api/ent/apikey"
"github.com/Wei-Shaw/sub2api/ent/group"
"github.com/Wei-Shaw/sub2api/ent/predicate"
...
...
@@ -36,6 +37,7 @@ type UserQuery struct {
withRedeemCodes
*
RedeemCodeQuery
withSubscriptions
*
UserSubscriptionQuery
withAssignedSubscriptions
*
UserSubscriptionQuery
withAnnouncementReads
*
AnnouncementReadQuery
withAllowedGroups
*
GroupQuery
withUsageLogs
*
UsageLogQuery
withAttributeValues
*
UserAttributeValueQuery
...
...
@@ -166,6 +168,28 @@ func (_q *UserQuery) QueryAssignedSubscriptions() *UserSubscriptionQuery {
return
query
}
// QueryAnnouncementReads chains the current query on the "announcement_reads" edge.
func
(
_q
*
UserQuery
)
QueryAnnouncementReads
()
*
AnnouncementReadQuery
{
query
:=
(
&
AnnouncementReadClient
{
config
:
_q
.
config
})
.
Query
()
query
.
path
=
func
(
ctx
context
.
Context
)
(
fromU
*
sql
.
Selector
,
err
error
)
{
if
err
:=
_q
.
prepareQuery
(
ctx
);
err
!=
nil
{
return
nil
,
err
}
selector
:=
_q
.
sqlQuery
(
ctx
)
if
err
:=
selector
.
Err
();
err
!=
nil
{
return
nil
,
err
}
step
:=
sqlgraph
.
NewStep
(
sqlgraph
.
From
(
user
.
Table
,
user
.
FieldID
,
selector
),
sqlgraph
.
To
(
announcementread
.
Table
,
announcementread
.
FieldID
),
sqlgraph
.
Edge
(
sqlgraph
.
O2M
,
false
,
user
.
AnnouncementReadsTable
,
user
.
AnnouncementReadsColumn
),
)
fromU
=
sqlgraph
.
SetNeighbors
(
_q
.
driver
.
Dialect
(),
step
)
return
fromU
,
nil
}
return
query
}
// QueryAllowedGroups chains the current query on the "allowed_groups" edge.
func
(
_q
*
UserQuery
)
QueryAllowedGroups
()
*
GroupQuery
{
query
:=
(
&
GroupClient
{
config
:
_q
.
config
})
.
Query
()
...
...
@@ -472,6 +496,7 @@ func (_q *UserQuery) Clone() *UserQuery {
withRedeemCodes
:
_q
.
withRedeemCodes
.
Clone
(),
withSubscriptions
:
_q
.
withSubscriptions
.
Clone
(),
withAssignedSubscriptions
:
_q
.
withAssignedSubscriptions
.
Clone
(),
withAnnouncementReads
:
_q
.
withAnnouncementReads
.
Clone
(),
withAllowedGroups
:
_q
.
withAllowedGroups
.
Clone
(),
withUsageLogs
:
_q
.
withUsageLogs
.
Clone
(),
withAttributeValues
:
_q
.
withAttributeValues
.
Clone
(),
...
...
@@ -527,6 +552,17 @@ func (_q *UserQuery) WithAssignedSubscriptions(opts ...func(*UserSubscriptionQue
return
_q
}
// WithAnnouncementReads tells the query-builder to eager-load the nodes that are connected to
// the "announcement_reads" edge. The optional arguments are used to configure the query builder of the edge.
func
(
_q
*
UserQuery
)
WithAnnouncementReads
(
opts
...
func
(
*
AnnouncementReadQuery
))
*
UserQuery
{
query
:=
(
&
AnnouncementReadClient
{
config
:
_q
.
config
})
.
Query
()
for
_
,
opt
:=
range
opts
{
opt
(
query
)
}
_q
.
withAnnouncementReads
=
query
return
_q
}
// WithAllowedGroups tells the query-builder to eager-load the nodes that are connected to
// the "allowed_groups" edge. The optional arguments are used to configure the query builder of the edge.
func
(
_q
*
UserQuery
)
WithAllowedGroups
(
opts
...
func
(
*
GroupQuery
))
*
UserQuery
{
...
...
@@ -660,11 +696,12 @@ func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
var
(
nodes
=
[]
*
User
{}
_spec
=
_q
.
querySpec
()
loadedTypes
=
[
9
]
bool
{
loadedTypes
=
[
10
]
bool
{
_q
.
withAPIKeys
!=
nil
,
_q
.
withRedeemCodes
!=
nil
,
_q
.
withSubscriptions
!=
nil
,
_q
.
withAssignedSubscriptions
!=
nil
,
_q
.
withAnnouncementReads
!=
nil
,
_q
.
withAllowedGroups
!=
nil
,
_q
.
withUsageLogs
!=
nil
,
_q
.
withAttributeValues
!=
nil
,
...
...
@@ -723,6 +760,13 @@ func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
return
nil
,
err
}
}
if
query
:=
_q
.
withAnnouncementReads
;
query
!=
nil
{
if
err
:=
_q
.
loadAnnouncementReads
(
ctx
,
query
,
nodes
,
func
(
n
*
User
)
{
n
.
Edges
.
AnnouncementReads
=
[]
*
AnnouncementRead
{}
},
func
(
n
*
User
,
e
*
AnnouncementRead
)
{
n
.
Edges
.
AnnouncementReads
=
append
(
n
.
Edges
.
AnnouncementReads
,
e
)
});
err
!=
nil
{
return
nil
,
err
}
}
if
query
:=
_q
.
withAllowedGroups
;
query
!=
nil
{
if
err
:=
_q
.
loadAllowedGroups
(
ctx
,
query
,
nodes
,
func
(
n
*
User
)
{
n
.
Edges
.
AllowedGroups
=
[]
*
Group
{}
},
...
...
@@ -887,6 +931,36 @@ func (_q *UserQuery) loadAssignedSubscriptions(ctx context.Context, query *UserS
}
return
nil
}
func
(
_q
*
UserQuery
)
loadAnnouncementReads
(
ctx
context
.
Context
,
query
*
AnnouncementReadQuery
,
nodes
[]
*
User
,
init
func
(
*
User
),
assign
func
(
*
User
,
*
AnnouncementRead
))
error
{
fks
:=
make
([]
driver
.
Value
,
0
,
len
(
nodes
))
nodeids
:=
make
(
map
[
int64
]
*
User
)
for
i
:=
range
nodes
{
fks
=
append
(
fks
,
nodes
[
i
]
.
ID
)
nodeids
[
nodes
[
i
]
.
ID
]
=
nodes
[
i
]
if
init
!=
nil
{
init
(
nodes
[
i
])
}
}
if
len
(
query
.
ctx
.
Fields
)
>
0
{
query
.
ctx
.
AppendFieldOnce
(
announcementread
.
FieldUserID
)
}
query
.
Where
(
predicate
.
AnnouncementRead
(
func
(
s
*
sql
.
Selector
)
{
s
.
Where
(
sql
.
InValues
(
s
.
C
(
user
.
AnnouncementReadsColumn
),
fks
...
))
}))
neighbors
,
err
:=
query
.
All
(
ctx
)
if
err
!=
nil
{
return
err
}
for
_
,
n
:=
range
neighbors
{
fk
:=
n
.
UserID
node
,
ok
:=
nodeids
[
fk
]
if
!
ok
{
return
fmt
.
Errorf
(
`unexpected referenced foreign-key "user_id" returned %v for node %v`
,
fk
,
n
.
ID
)
}
assign
(
node
,
n
)
}
return
nil
}
func
(
_q
*
UserQuery
)
loadAllowedGroups
(
ctx
context
.
Context
,
query
*
GroupQuery
,
nodes
[]
*
User
,
init
func
(
*
User
),
assign
func
(
*
User
,
*
Group
))
error
{
edgeIDs
:=
make
([]
driver
.
Value
,
len
(
nodes
))
byID
:=
make
(
map
[
int64
]
*
User
)
...
...
backend/ent/user_update.go
View file @
377bffe2
...
...
@@ -11,6 +11,7 @@ import (
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/Wei-Shaw/sub2api/ent/announcementread"
"github.com/Wei-Shaw/sub2api/ent/apikey"
"github.com/Wei-Shaw/sub2api/ent/group"
"github.com/Wei-Shaw/sub2api/ent/predicate"
...
...
@@ -187,6 +188,60 @@ func (_u *UserUpdate) SetNillableNotes(v *string) *UserUpdate {
return
_u
}
// SetTotpSecretEncrypted sets the "totp_secret_encrypted" field.
func
(
_u
*
UserUpdate
)
SetTotpSecretEncrypted
(
v
string
)
*
UserUpdate
{
_u
.
mutation
.
SetTotpSecretEncrypted
(
v
)
return
_u
}
// SetNillableTotpSecretEncrypted sets the "totp_secret_encrypted" field if the given value is not nil.
func
(
_u
*
UserUpdate
)
SetNillableTotpSecretEncrypted
(
v
*
string
)
*
UserUpdate
{
if
v
!=
nil
{
_u
.
SetTotpSecretEncrypted
(
*
v
)
}
return
_u
}
// ClearTotpSecretEncrypted clears the value of the "totp_secret_encrypted" field.
func
(
_u
*
UserUpdate
)
ClearTotpSecretEncrypted
()
*
UserUpdate
{
_u
.
mutation
.
ClearTotpSecretEncrypted
()
return
_u
}
// SetTotpEnabled sets the "totp_enabled" field.
func
(
_u
*
UserUpdate
)
SetTotpEnabled
(
v
bool
)
*
UserUpdate
{
_u
.
mutation
.
SetTotpEnabled
(
v
)
return
_u
}
// SetNillableTotpEnabled sets the "totp_enabled" field if the given value is not nil.
func
(
_u
*
UserUpdate
)
SetNillableTotpEnabled
(
v
*
bool
)
*
UserUpdate
{
if
v
!=
nil
{
_u
.
SetTotpEnabled
(
*
v
)
}
return
_u
}
// SetTotpEnabledAt sets the "totp_enabled_at" field.
func
(
_u
*
UserUpdate
)
SetTotpEnabledAt
(
v
time
.
Time
)
*
UserUpdate
{
_u
.
mutation
.
SetTotpEnabledAt
(
v
)
return
_u
}
// SetNillableTotpEnabledAt sets the "totp_enabled_at" field if the given value is not nil.
func
(
_u
*
UserUpdate
)
SetNillableTotpEnabledAt
(
v
*
time
.
Time
)
*
UserUpdate
{
if
v
!=
nil
{
_u
.
SetTotpEnabledAt
(
*
v
)
}
return
_u
}
// ClearTotpEnabledAt clears the value of the "totp_enabled_at" field.
func
(
_u
*
UserUpdate
)
ClearTotpEnabledAt
()
*
UserUpdate
{
_u
.
mutation
.
ClearTotpEnabledAt
()
return
_u
}
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func
(
_u
*
UserUpdate
)
AddAPIKeyIDs
(
ids
...
int64
)
*
UserUpdate
{
_u
.
mutation
.
AddAPIKeyIDs
(
ids
...
)
...
...
@@ -247,6 +302,21 @@ func (_u *UserUpdate) AddAssignedSubscriptions(v ...*UserSubscription) *UserUpda
return
_u
.
AddAssignedSubscriptionIDs
(
ids
...
)
}
// AddAnnouncementReadIDs adds the "announcement_reads" edge to the AnnouncementRead entity by IDs.
func
(
_u
*
UserUpdate
)
AddAnnouncementReadIDs
(
ids
...
int64
)
*
UserUpdate
{
_u
.
mutation
.
AddAnnouncementReadIDs
(
ids
...
)
return
_u
}
// AddAnnouncementReads adds the "announcement_reads" edges to the AnnouncementRead entity.
func
(
_u
*
UserUpdate
)
AddAnnouncementReads
(
v
...*
AnnouncementRead
)
*
UserUpdate
{
ids
:=
make
([]
int64
,
len
(
v
))
for
i
:=
range
v
{
ids
[
i
]
=
v
[
i
]
.
ID
}
return
_u
.
AddAnnouncementReadIDs
(
ids
...
)
}
// AddAllowedGroupIDs adds the "allowed_groups" edge to the Group entity by IDs.
func
(
_u
*
UserUpdate
)
AddAllowedGroupIDs
(
ids
...
int64
)
*
UserUpdate
{
_u
.
mutation
.
AddAllowedGroupIDs
(
ids
...
)
...
...
@@ -396,6 +466,27 @@ func (_u *UserUpdate) RemoveAssignedSubscriptions(v ...*UserSubscription) *UserU
return
_u
.
RemoveAssignedSubscriptionIDs
(
ids
...
)
}
// ClearAnnouncementReads clears all "announcement_reads" edges to the AnnouncementRead entity.
func
(
_u
*
UserUpdate
)
ClearAnnouncementReads
()
*
UserUpdate
{
_u
.
mutation
.
ClearAnnouncementReads
()
return
_u
}
// RemoveAnnouncementReadIDs removes the "announcement_reads" edge to AnnouncementRead entities by IDs.
func
(
_u
*
UserUpdate
)
RemoveAnnouncementReadIDs
(
ids
...
int64
)
*
UserUpdate
{
_u
.
mutation
.
RemoveAnnouncementReadIDs
(
ids
...
)
return
_u
}
// RemoveAnnouncementReads removes "announcement_reads" edges to AnnouncementRead entities.
func
(
_u
*
UserUpdate
)
RemoveAnnouncementReads
(
v
...*
AnnouncementRead
)
*
UserUpdate
{
ids
:=
make
([]
int64
,
len
(
v
))
for
i
:=
range
v
{
ids
[
i
]
=
v
[
i
]
.
ID
}
return
_u
.
RemoveAnnouncementReadIDs
(
ids
...
)
}
// ClearAllowedGroups clears all "allowed_groups" edges to the Group entity.
func
(
_u
*
UserUpdate
)
ClearAllowedGroups
()
*
UserUpdate
{
_u
.
mutation
.
ClearAllowedGroups
()
...
...
@@ -603,6 +694,21 @@ func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) {
if
value
,
ok
:=
_u
.
mutation
.
Notes
();
ok
{
_spec
.
SetField
(
user
.
FieldNotes
,
field
.
TypeString
,
value
)
}
if
value
,
ok
:=
_u
.
mutation
.
TotpSecretEncrypted
();
ok
{
_spec
.
SetField
(
user
.
FieldTotpSecretEncrypted
,
field
.
TypeString
,
value
)
}
if
_u
.
mutation
.
TotpSecretEncryptedCleared
()
{
_spec
.
ClearField
(
user
.
FieldTotpSecretEncrypted
,
field
.
TypeString
)
}
if
value
,
ok
:=
_u
.
mutation
.
TotpEnabled
();
ok
{
_spec
.
SetField
(
user
.
FieldTotpEnabled
,
field
.
TypeBool
,
value
)
}
if
value
,
ok
:=
_u
.
mutation
.
TotpEnabledAt
();
ok
{
_spec
.
SetField
(
user
.
FieldTotpEnabledAt
,
field
.
TypeTime
,
value
)
}
if
_u
.
mutation
.
TotpEnabledAtCleared
()
{
_spec
.
ClearField
(
user
.
FieldTotpEnabledAt
,
field
.
TypeTime
)
}
if
_u
.
mutation
.
APIKeysCleared
()
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
O2M
,
...
...
@@ -783,6 +889,51 @@ func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) {
}
_spec
.
Edges
.
Add
=
append
(
_spec
.
Edges
.
Add
,
edge
)
}
if
_u
.
mutation
.
AnnouncementReadsCleared
()
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
O2M
,
Inverse
:
false
,
Table
:
user
.
AnnouncementReadsTable
,
Columns
:
[]
string
{
user
.
AnnouncementReadsColumn
},
Bidi
:
false
,
Target
:
&
sqlgraph
.
EdgeTarget
{
IDSpec
:
sqlgraph
.
NewFieldSpec
(
announcementread
.
FieldID
,
field
.
TypeInt64
),
},
}
_spec
.
Edges
.
Clear
=
append
(
_spec
.
Edges
.
Clear
,
edge
)
}
if
nodes
:=
_u
.
mutation
.
RemovedAnnouncementReadsIDs
();
len
(
nodes
)
>
0
&&
!
_u
.
mutation
.
AnnouncementReadsCleared
()
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
O2M
,
Inverse
:
false
,
Table
:
user
.
AnnouncementReadsTable
,
Columns
:
[]
string
{
user
.
AnnouncementReadsColumn
},
Bidi
:
false
,
Target
:
&
sqlgraph
.
EdgeTarget
{
IDSpec
:
sqlgraph
.
NewFieldSpec
(
announcementread
.
FieldID
,
field
.
TypeInt64
),
},
}
for
_
,
k
:=
range
nodes
{
edge
.
Target
.
Nodes
=
append
(
edge
.
Target
.
Nodes
,
k
)
}
_spec
.
Edges
.
Clear
=
append
(
_spec
.
Edges
.
Clear
,
edge
)
}
if
nodes
:=
_u
.
mutation
.
AnnouncementReadsIDs
();
len
(
nodes
)
>
0
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
O2M
,
Inverse
:
false
,
Table
:
user
.
AnnouncementReadsTable
,
Columns
:
[]
string
{
user
.
AnnouncementReadsColumn
},
Bidi
:
false
,
Target
:
&
sqlgraph
.
EdgeTarget
{
IDSpec
:
sqlgraph
.
NewFieldSpec
(
announcementread
.
FieldID
,
field
.
TypeInt64
),
},
}
for
_
,
k
:=
range
nodes
{
edge
.
Target
.
Nodes
=
append
(
edge
.
Target
.
Nodes
,
k
)
}
_spec
.
Edges
.
Add
=
append
(
_spec
.
Edges
.
Add
,
edge
)
}
if
_u
.
mutation
.
AllowedGroupsCleared
()
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
M2M
,
...
...
@@ -1147,6 +1298,60 @@ func (_u *UserUpdateOne) SetNillableNotes(v *string) *UserUpdateOne {
return
_u
}
// SetTotpSecretEncrypted sets the "totp_secret_encrypted" field.
func
(
_u
*
UserUpdateOne
)
SetTotpSecretEncrypted
(
v
string
)
*
UserUpdateOne
{
_u
.
mutation
.
SetTotpSecretEncrypted
(
v
)
return
_u
}
// SetNillableTotpSecretEncrypted sets the "totp_secret_encrypted" field if the given value is not nil.
func
(
_u
*
UserUpdateOne
)
SetNillableTotpSecretEncrypted
(
v
*
string
)
*
UserUpdateOne
{
if
v
!=
nil
{
_u
.
SetTotpSecretEncrypted
(
*
v
)
}
return
_u
}
// ClearTotpSecretEncrypted clears the value of the "totp_secret_encrypted" field.
func
(
_u
*
UserUpdateOne
)
ClearTotpSecretEncrypted
()
*
UserUpdateOne
{
_u
.
mutation
.
ClearTotpSecretEncrypted
()
return
_u
}
// SetTotpEnabled sets the "totp_enabled" field.
func
(
_u
*
UserUpdateOne
)
SetTotpEnabled
(
v
bool
)
*
UserUpdateOne
{
_u
.
mutation
.
SetTotpEnabled
(
v
)
return
_u
}
// SetNillableTotpEnabled sets the "totp_enabled" field if the given value is not nil.
func
(
_u
*
UserUpdateOne
)
SetNillableTotpEnabled
(
v
*
bool
)
*
UserUpdateOne
{
if
v
!=
nil
{
_u
.
SetTotpEnabled
(
*
v
)
}
return
_u
}
// SetTotpEnabledAt sets the "totp_enabled_at" field.
func
(
_u
*
UserUpdateOne
)
SetTotpEnabledAt
(
v
time
.
Time
)
*
UserUpdateOne
{
_u
.
mutation
.
SetTotpEnabledAt
(
v
)
return
_u
}
// SetNillableTotpEnabledAt sets the "totp_enabled_at" field if the given value is not nil.
func
(
_u
*
UserUpdateOne
)
SetNillableTotpEnabledAt
(
v
*
time
.
Time
)
*
UserUpdateOne
{
if
v
!=
nil
{
_u
.
SetTotpEnabledAt
(
*
v
)
}
return
_u
}
// ClearTotpEnabledAt clears the value of the "totp_enabled_at" field.
func
(
_u
*
UserUpdateOne
)
ClearTotpEnabledAt
()
*
UserUpdateOne
{
_u
.
mutation
.
ClearTotpEnabledAt
()
return
_u
}
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func
(
_u
*
UserUpdateOne
)
AddAPIKeyIDs
(
ids
...
int64
)
*
UserUpdateOne
{
_u
.
mutation
.
AddAPIKeyIDs
(
ids
...
)
...
...
@@ -1207,6 +1412,21 @@ func (_u *UserUpdateOne) AddAssignedSubscriptions(v ...*UserSubscription) *UserU
return
_u
.
AddAssignedSubscriptionIDs
(
ids
...
)
}
// AddAnnouncementReadIDs adds the "announcement_reads" edge to the AnnouncementRead entity by IDs.
func
(
_u
*
UserUpdateOne
)
AddAnnouncementReadIDs
(
ids
...
int64
)
*
UserUpdateOne
{
_u
.
mutation
.
AddAnnouncementReadIDs
(
ids
...
)
return
_u
}
// AddAnnouncementReads adds the "announcement_reads" edges to the AnnouncementRead entity.
func
(
_u
*
UserUpdateOne
)
AddAnnouncementReads
(
v
...*
AnnouncementRead
)
*
UserUpdateOne
{
ids
:=
make
([]
int64
,
len
(
v
))
for
i
:=
range
v
{
ids
[
i
]
=
v
[
i
]
.
ID
}
return
_u
.
AddAnnouncementReadIDs
(
ids
...
)
}
// AddAllowedGroupIDs adds the "allowed_groups" edge to the Group entity by IDs.
func
(
_u
*
UserUpdateOne
)
AddAllowedGroupIDs
(
ids
...
int64
)
*
UserUpdateOne
{
_u
.
mutation
.
AddAllowedGroupIDs
(
ids
...
)
...
...
@@ -1356,6 +1576,27 @@ func (_u *UserUpdateOne) RemoveAssignedSubscriptions(v ...*UserSubscription) *Us
return
_u
.
RemoveAssignedSubscriptionIDs
(
ids
...
)
}
// ClearAnnouncementReads clears all "announcement_reads" edges to the AnnouncementRead entity.
func
(
_u
*
UserUpdateOne
)
ClearAnnouncementReads
()
*
UserUpdateOne
{
_u
.
mutation
.
ClearAnnouncementReads
()
return
_u
}
// RemoveAnnouncementReadIDs removes the "announcement_reads" edge to AnnouncementRead entities by IDs.
func
(
_u
*
UserUpdateOne
)
RemoveAnnouncementReadIDs
(
ids
...
int64
)
*
UserUpdateOne
{
_u
.
mutation
.
RemoveAnnouncementReadIDs
(
ids
...
)
return
_u
}
// RemoveAnnouncementReads removes "announcement_reads" edges to AnnouncementRead entities.
func
(
_u
*
UserUpdateOne
)
RemoveAnnouncementReads
(
v
...*
AnnouncementRead
)
*
UserUpdateOne
{
ids
:=
make
([]
int64
,
len
(
v
))
for
i
:=
range
v
{
ids
[
i
]
=
v
[
i
]
.
ID
}
return
_u
.
RemoveAnnouncementReadIDs
(
ids
...
)
}
// ClearAllowedGroups clears all "allowed_groups" edges to the Group entity.
func
(
_u
*
UserUpdateOne
)
ClearAllowedGroups
()
*
UserUpdateOne
{
_u
.
mutation
.
ClearAllowedGroups
()
...
...
@@ -1593,6 +1834,21 @@ func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) {
if
value
,
ok
:=
_u
.
mutation
.
Notes
();
ok
{
_spec
.
SetField
(
user
.
FieldNotes
,
field
.
TypeString
,
value
)
}
if
value
,
ok
:=
_u
.
mutation
.
TotpSecretEncrypted
();
ok
{
_spec
.
SetField
(
user
.
FieldTotpSecretEncrypted
,
field
.
TypeString
,
value
)
}
if
_u
.
mutation
.
TotpSecretEncryptedCleared
()
{
_spec
.
ClearField
(
user
.
FieldTotpSecretEncrypted
,
field
.
TypeString
)
}
if
value
,
ok
:=
_u
.
mutation
.
TotpEnabled
();
ok
{
_spec
.
SetField
(
user
.
FieldTotpEnabled
,
field
.
TypeBool
,
value
)
}
if
value
,
ok
:=
_u
.
mutation
.
TotpEnabledAt
();
ok
{
_spec
.
SetField
(
user
.
FieldTotpEnabledAt
,
field
.
TypeTime
,
value
)
}
if
_u
.
mutation
.
TotpEnabledAtCleared
()
{
_spec
.
ClearField
(
user
.
FieldTotpEnabledAt
,
field
.
TypeTime
)
}
if
_u
.
mutation
.
APIKeysCleared
()
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
O2M
,
...
...
@@ -1773,6 +2029,51 @@ func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) {
}
_spec
.
Edges
.
Add
=
append
(
_spec
.
Edges
.
Add
,
edge
)
}
if
_u
.
mutation
.
AnnouncementReadsCleared
()
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
O2M
,
Inverse
:
false
,
Table
:
user
.
AnnouncementReadsTable
,
Columns
:
[]
string
{
user
.
AnnouncementReadsColumn
},
Bidi
:
false
,
Target
:
&
sqlgraph
.
EdgeTarget
{
IDSpec
:
sqlgraph
.
NewFieldSpec
(
announcementread
.
FieldID
,
field
.
TypeInt64
),
},
}
_spec
.
Edges
.
Clear
=
append
(
_spec
.
Edges
.
Clear
,
edge
)
}
if
nodes
:=
_u
.
mutation
.
RemovedAnnouncementReadsIDs
();
len
(
nodes
)
>
0
&&
!
_u
.
mutation
.
AnnouncementReadsCleared
()
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
O2M
,
Inverse
:
false
,
Table
:
user
.
AnnouncementReadsTable
,
Columns
:
[]
string
{
user
.
AnnouncementReadsColumn
},
Bidi
:
false
,
Target
:
&
sqlgraph
.
EdgeTarget
{
IDSpec
:
sqlgraph
.
NewFieldSpec
(
announcementread
.
FieldID
,
field
.
TypeInt64
),
},
}
for
_
,
k
:=
range
nodes
{
edge
.
Target
.
Nodes
=
append
(
edge
.
Target
.
Nodes
,
k
)
}
_spec
.
Edges
.
Clear
=
append
(
_spec
.
Edges
.
Clear
,
edge
)
}
if
nodes
:=
_u
.
mutation
.
AnnouncementReadsIDs
();
len
(
nodes
)
>
0
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
O2M
,
Inverse
:
false
,
Table
:
user
.
AnnouncementReadsTable
,
Columns
:
[]
string
{
user
.
AnnouncementReadsColumn
},
Bidi
:
false
,
Target
:
&
sqlgraph
.
EdgeTarget
{
IDSpec
:
sqlgraph
.
NewFieldSpec
(
announcementread
.
FieldID
,
field
.
TypeInt64
),
},
}
for
_
,
k
:=
range
nodes
{
edge
.
Target
.
Nodes
=
append
(
edge
.
Target
.
Nodes
,
k
)
}
_spec
.
Edges
.
Add
=
append
(
_spec
.
Edges
.
Add
,
edge
)
}
if
_u
.
mutation
.
AllowedGroupsCleared
()
{
edge
:=
&
sqlgraph
.
EdgeSpec
{
Rel
:
sqlgraph
.
M2M
,
...
...
backend/go.mod
View file @
377bffe2
module github.com/Wei-Shaw/sub2api
go 1.25.
5
go 1.25.
6
require (
entgo.io/ent v0.14.5
...
...
@@ -37,6 +37,7 @@ require (
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/bmatcuk/doublestar v1.3.4 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
...
...
@@ -106,6 +107,7 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/pquerna/otp v1.5.0 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.57.1 // indirect
github.com/refraction-networking/utls v1.8.1 // indirect
...
...
backend/go.sum
View file @
377bffe2
...
...
@@ -20,6 +20,8 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
...
...
@@ -217,6 +219,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
...
...
backend/internal/config/config.go
View file @
377bffe2
...
...
@@ -47,6 +47,7 @@ type Config struct {
Redis
RedisConfig
`mapstructure:"redis"`
Ops
OpsConfig
`mapstructure:"ops"`
JWT
JWTConfig
`mapstructure:"jwt"`
Totp
TotpConfig
`mapstructure:"totp"`
LinuxDo
LinuxDoConnectConfig
`mapstructure:"linuxdo_connect"`
Default
DefaultConfig
`mapstructure:"default"`
RateLimit
RateLimitConfig
`mapstructure:"rate_limit"`
...
...
@@ -479,6 +480,8 @@ type RedisConfig struct {
PoolSize
int
`mapstructure:"pool_size"`
// MinIdleConns: 最小空闲连接数,保持热连接减少冷启动延迟
MinIdleConns
int
`mapstructure:"min_idle_conns"`
// EnableTLS: 是否启用 TLS/SSL 连接
EnableTLS
bool
`mapstructure:"enable_tls"`
}
func
(
r
*
RedisConfig
)
Address
()
string
{
...
...
@@ -531,6 +534,16 @@ type JWTConfig struct {
ExpireHour
int
`mapstructure:"expire_hour"`
}
// TotpConfig TOTP 双因素认证配置
type
TotpConfig
struct
{
// EncryptionKey 用于加密 TOTP 密钥的 AES-256 密钥(32 字节 hex 编码)
// 如果为空,将自动生成一个随机密钥(仅适用于开发环境)
EncryptionKey
string
`mapstructure:"encryption_key"`
// EncryptionKeyConfigured 标记加密密钥是否为手动配置(非自动生成)
// 只有手动配置了密钥才允许在管理后台启用 TOTP 功能
EncryptionKeyConfigured
bool
`mapstructure:"-"`
}
type
TurnstileConfig
struct
{
Required
bool
`mapstructure:"required"`
}
...
...
@@ -691,6 +704,20 @@ func Load() (*Config, error) {
log
.
Println
(
"Warning: JWT secret auto-generated. Consider setting a fixed secret for production."
)
}
// Auto-generate TOTP encryption key if not set (32 bytes = 64 hex chars for AES-256)
cfg
.
Totp
.
EncryptionKey
=
strings
.
TrimSpace
(
cfg
.
Totp
.
EncryptionKey
)
if
cfg
.
Totp
.
EncryptionKey
==
""
{
key
,
err
:=
generateJWTSecret
(
32
)
// Reuse the same random generation function
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"generate totp encryption key error: %w"
,
err
)
}
cfg
.
Totp
.
EncryptionKey
=
key
cfg
.
Totp
.
EncryptionKeyConfigured
=
false
log
.
Println
(
"Warning: TOTP encryption key auto-generated. Consider setting a fixed key for production."
)
}
else
{
cfg
.
Totp
.
EncryptionKeyConfigured
=
true
}
if
err
:=
cfg
.
Validate
();
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"validate config error: %w"
,
err
)
}
...
...
@@ -802,6 +829,7 @@ func setDefaults() {
viper
.
SetDefault
(
"redis.write_timeout_seconds"
,
3
)
viper
.
SetDefault
(
"redis.pool_size"
,
128
)
viper
.
SetDefault
(
"redis.min_idle_conns"
,
10
)
viper
.
SetDefault
(
"redis.enable_tls"
,
false
)
// Ops (vNext)
viper
.
SetDefault
(
"ops.enabled"
,
true
)
...
...
@@ -821,6 +849,9 @@ func setDefaults() {
viper
.
SetDefault
(
"jwt.secret"
,
""
)
viper
.
SetDefault
(
"jwt.expire_hour"
,
24
)
// TOTP
viper
.
SetDefault
(
"totp.encryption_key"
,
""
)
// Default
// Admin credentials are created via the setup flow (web wizard / CLI / AUTO_SETUP).
// Do not ship fixed defaults here to avoid insecure "known credentials" in production.
...
...
backend/internal/domain/announcement.go
0 → 100644
View file @
377bffe2
package
domain
import
(
"strings"
"time"
infraerrors
"github.com/Wei-Shaw/sub2api/internal/pkg/errors"
)
const
(
AnnouncementStatusDraft
=
"draft"
AnnouncementStatusActive
=
"active"
AnnouncementStatusArchived
=
"archived"
)
const
(
AnnouncementConditionTypeSubscription
=
"subscription"
AnnouncementConditionTypeBalance
=
"balance"
)
const
(
AnnouncementOperatorIn
=
"in"
AnnouncementOperatorGT
=
"gt"
AnnouncementOperatorGTE
=
"gte"
AnnouncementOperatorLT
=
"lt"
AnnouncementOperatorLTE
=
"lte"
AnnouncementOperatorEQ
=
"eq"
)
var
(
ErrAnnouncementNotFound
=
infraerrors
.
NotFound
(
"ANNOUNCEMENT_NOT_FOUND"
,
"announcement not found"
)
ErrAnnouncementInvalidTarget
=
infraerrors
.
BadRequest
(
"ANNOUNCEMENT_INVALID_TARGET"
,
"invalid announcement targeting rules"
)
)
type
AnnouncementTargeting
struct
{
// AnyOf 表示 OR:任意一个条件组满足即可展示。
AnyOf
[]
AnnouncementConditionGroup
`json:"any_of,omitempty"`
}
type
AnnouncementConditionGroup
struct
{
// AllOf 表示 AND:组内所有条件都满足才算命中该组。
AllOf
[]
AnnouncementCondition
`json:"all_of,omitempty"`
}
type
AnnouncementCondition
struct
{
// Type: subscription | balance
Type
string
`json:"type"`
// Operator:
// - subscription: in
// - balance: gt/gte/lt/lte/eq
Operator
string
`json:"operator"`
// subscription 条件:匹配的订阅套餐(group_id)
GroupIDs
[]
int64
`json:"group_ids,omitempty"`
// balance 条件:比较阈值
Value
float64
`json:"value,omitempty"`
}
func
(
t
AnnouncementTargeting
)
Matches
(
balance
float64
,
activeSubscriptionGroupIDs
map
[
int64
]
struct
{})
bool
{
// 空规则:展示给所有用户
if
len
(
t
.
AnyOf
)
==
0
{
return
true
}
for
_
,
group
:=
range
t
.
AnyOf
{
if
len
(
group
.
AllOf
)
==
0
{
// 空条件组不命中(避免 OR 中出现无条件 “全命中”)
continue
}
allMatched
:=
true
for
_
,
cond
:=
range
group
.
AllOf
{
if
!
cond
.
Matches
(
balance
,
activeSubscriptionGroupIDs
)
{
allMatched
=
false
break
}
}
if
allMatched
{
return
true
}
}
return
false
}
func
(
c
AnnouncementCondition
)
Matches
(
balance
float64
,
activeSubscriptionGroupIDs
map
[
int64
]
struct
{})
bool
{
switch
c
.
Type
{
case
AnnouncementConditionTypeSubscription
:
if
c
.
Operator
!=
AnnouncementOperatorIn
{
return
false
}
if
len
(
c
.
GroupIDs
)
==
0
{
return
false
}
if
len
(
activeSubscriptionGroupIDs
)
==
0
{
return
false
}
for
_
,
gid
:=
range
c
.
GroupIDs
{
if
_
,
ok
:=
activeSubscriptionGroupIDs
[
gid
];
ok
{
return
true
}
}
return
false
case
AnnouncementConditionTypeBalance
:
switch
c
.
Operator
{
case
AnnouncementOperatorGT
:
return
balance
>
c
.
Value
case
AnnouncementOperatorGTE
:
return
balance
>=
c
.
Value
case
AnnouncementOperatorLT
:
return
balance
<
c
.
Value
case
AnnouncementOperatorLTE
:
return
balance
<=
c
.
Value
case
AnnouncementOperatorEQ
:
return
balance
==
c
.
Value
default
:
return
false
}
default
:
return
false
}
}
func
(
t
AnnouncementTargeting
)
NormalizeAndValidate
()
(
AnnouncementTargeting
,
error
)
{
normalized
:=
AnnouncementTargeting
{
AnyOf
:
make
([]
AnnouncementConditionGroup
,
0
,
len
(
t
.
AnyOf
))}
// 允许空 targeting(展示给所有用户)
if
len
(
t
.
AnyOf
)
==
0
{
return
normalized
,
nil
}
if
len
(
t
.
AnyOf
)
>
50
{
return
AnnouncementTargeting
{},
ErrAnnouncementInvalidTarget
}
for
_
,
g
:=
range
t
.
AnyOf
{
if
len
(
g
.
AllOf
)
==
0
{
return
AnnouncementTargeting
{},
ErrAnnouncementInvalidTarget
}
if
len
(
g
.
AllOf
)
>
50
{
return
AnnouncementTargeting
{},
ErrAnnouncementInvalidTarget
}
group
:=
AnnouncementConditionGroup
{
AllOf
:
make
([]
AnnouncementCondition
,
0
,
len
(
g
.
AllOf
))}
for
_
,
c
:=
range
g
.
AllOf
{
cond
:=
AnnouncementCondition
{
Type
:
strings
.
TrimSpace
(
c
.
Type
),
Operator
:
strings
.
TrimSpace
(
c
.
Operator
),
Value
:
c
.
Value
,
}
for
_
,
gid
:=
range
c
.
GroupIDs
{
if
gid
<=
0
{
return
AnnouncementTargeting
{},
ErrAnnouncementInvalidTarget
}
cond
.
GroupIDs
=
append
(
cond
.
GroupIDs
,
gid
)
}
if
err
:=
cond
.
validate
();
err
!=
nil
{
return
AnnouncementTargeting
{},
err
}
group
.
AllOf
=
append
(
group
.
AllOf
,
cond
)
}
normalized
.
AnyOf
=
append
(
normalized
.
AnyOf
,
group
)
}
return
normalized
,
nil
}
func
(
c
AnnouncementCondition
)
validate
()
error
{
switch
c
.
Type
{
case
AnnouncementConditionTypeSubscription
:
if
c
.
Operator
!=
AnnouncementOperatorIn
{
return
ErrAnnouncementInvalidTarget
}
if
len
(
c
.
GroupIDs
)
==
0
{
return
ErrAnnouncementInvalidTarget
}
return
nil
case
AnnouncementConditionTypeBalance
:
switch
c
.
Operator
{
case
AnnouncementOperatorGT
,
AnnouncementOperatorGTE
,
AnnouncementOperatorLT
,
AnnouncementOperatorLTE
,
AnnouncementOperatorEQ
:
return
nil
default
:
return
ErrAnnouncementInvalidTarget
}
default
:
return
ErrAnnouncementInvalidTarget
}
}
type
Announcement
struct
{
ID
int64
Title
string
Content
string
Status
string
Targeting
AnnouncementTargeting
StartsAt
*
time
.
Time
EndsAt
*
time
.
Time
CreatedBy
*
int64
UpdatedBy
*
int64
CreatedAt
time
.
Time
UpdatedAt
time
.
Time
}
func
(
a
*
Announcement
)
IsActiveAt
(
now
time
.
Time
)
bool
{
if
a
==
nil
{
return
false
}
if
a
.
Status
!=
AnnouncementStatusActive
{
return
false
}
if
a
.
StartsAt
!=
nil
&&
now
.
Before
(
*
a
.
StartsAt
)
{
return
false
}
if
a
.
EndsAt
!=
nil
&&
!
now
.
Before
(
*
a
.
EndsAt
)
{
// ends_at 语义:到点即下线
return
false
}
return
true
}
backend/internal/domain/constants.go
0 → 100644
View file @
377bffe2
package
domain
// Status constants
const
(
StatusActive
=
"active"
StatusDisabled
=
"disabled"
StatusError
=
"error"
StatusUnused
=
"unused"
StatusUsed
=
"used"
StatusExpired
=
"expired"
)
// Role constants
const
(
RoleAdmin
=
"admin"
RoleUser
=
"user"
)
// Platform constants
const
(
PlatformAnthropic
=
"anthropic"
PlatformOpenAI
=
"openai"
PlatformGemini
=
"gemini"
PlatformAntigravity
=
"antigravity"
PlatformSora
=
"sora"
)
// Account type constants
const
(
AccountTypeOAuth
=
"oauth"
// OAuth类型账号(full scope: profile + inference)
AccountTypeSetupToken
=
"setup-token"
// Setup Token类型账号(inference only scope)
AccountTypeAPIKey
=
"apikey"
// API Key类型账号
)
// Redeem type constants
const
(
RedeemTypeBalance
=
"balance"
RedeemTypeConcurrency
=
"concurrency"
RedeemTypeSubscription
=
"subscription"
RedeemTypeInvitation
=
"invitation"
)
// PromoCode status constants
const
(
PromoCodeStatusActive
=
"active"
PromoCodeStatusDisabled
=
"disabled"
)
// Admin adjustment type constants
const
(
AdjustmentTypeAdminBalance
=
"admin_balance"
// 管理员调整余额
AdjustmentTypeAdminConcurrency
=
"admin_concurrency"
// 管理员调整并发数
)
// Group subscription type constants
const
(
SubscriptionTypeStandard
=
"standard"
// 标准计费模式(按余额扣费)
SubscriptionTypeSubscription
=
"subscription"
// 订阅模式(按限额控制)
)
// Subscription status constants
const
(
SubscriptionStatusActive
=
"active"
SubscriptionStatusExpired
=
"expired"
SubscriptionStatusSuspended
=
"suspended"
)
backend/internal/handler/admin/account_handler.go
View file @
377bffe2
...
...
@@ -547,9 +547,18 @@ func (h *AccountHandler) Refresh(c *gin.Context) {
}
}
// 如果 project_id 获取失败,先更新凭证,再标记账户为 error
// 特殊处理 project_id:如果新值为空但旧值非空,保留旧值
// 这确保了即使 LoadCodeAssist 失败,project_id 也不会丢失
if
newProjectID
,
_
:=
newCredentials
[
"project_id"
]
.
(
string
);
newProjectID
==
""
{
if
oldProjectID
:=
strings
.
TrimSpace
(
account
.
GetCredential
(
"project_id"
));
oldProjectID
!=
""
{
newCredentials
[
"project_id"
]
=
oldProjectID
}
}
// 如果 project_id 获取失败,更新凭证但不标记为 error
// LoadCodeAssist 失败可能是临时网络问题,给它机会在下次自动刷新时重试
if
tokenInfo
.
ProjectIDMissing
{
// 先更新凭证
// 先更新凭证
(token 本身刷新成功了)
_
,
updateErr
:=
h
.
adminService
.
UpdateAccount
(
c
.
Request
.
Context
(),
accountID
,
&
service
.
UpdateAccountInput
{
Credentials
:
newCredentials
,
})
...
...
@@ -557,14 +566,10 @@ func (h *AccountHandler) Refresh(c *gin.Context) {
response
.
InternalError
(
c
,
"Failed to update credentials: "
+
updateErr
.
Error
())
return
}
// 标记账户为 error
if
setErr
:=
h
.
adminService
.
SetAccountError
(
c
.
Request
.
Context
(),
accountID
,
"missing_project_id: 账户缺少project id,可能无法使用Antigravity"
);
setErr
!=
nil
{
response
.
InternalError
(
c
,
"Failed to set account error: "
+
setErr
.
Error
())
return
}
// 不标记为 error,只返回警告信息
response
.
Success
(
c
,
gin
.
H
{
"message"
:
"Token refreshed but project_id
is missing, account marked as error
"
,
"warning"
:
"missing_project_id"
,
"message"
:
"Token refreshed
successfully,
but project_id
could not be retrieved (will retry automatically)
"
,
"warning"
:
"missing_project_id
_temporary
"
,
})
return
}
...
...
backend/internal/handler/admin/admin_service_stub_test.go
View file @
377bffe2
...
...
@@ -290,5 +290,9 @@ func (s *stubAdminService) ExpireRedeemCode(ctx context.Context, id int64) (*ser
return
&
code
,
nil
}
func
(
s
*
stubAdminService
)
GetUserBalanceHistory
(
ctx
context
.
Context
,
userID
int64
,
page
,
pageSize
int
,
codeType
string
)
([]
service
.
RedeemCode
,
int64
,
float64
,
error
)
{
return
s
.
redeems
,
int64
(
len
(
s
.
redeems
)),
100.0
,
nil
}
// Ensure stub implements interface.
var
_
service
.
AdminService
=
(
*
stubAdminService
)(
nil
)
backend/internal/handler/admin/announcement_handler.go
0 → 100644
View file @
377bffe2
package
admin
import
(
"strconv"
"strings"
"time"
"github.com/Wei-Shaw/sub2api/internal/handler/dto"
"github.com/Wei-Shaw/sub2api/internal/pkg/pagination"
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
middleware2
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
)
// AnnouncementHandler handles admin announcement management
type
AnnouncementHandler
struct
{
announcementService
*
service
.
AnnouncementService
}
// NewAnnouncementHandler creates a new admin announcement handler
func
NewAnnouncementHandler
(
announcementService
*
service
.
AnnouncementService
)
*
AnnouncementHandler
{
return
&
AnnouncementHandler
{
announcementService
:
announcementService
,
}
}
type
CreateAnnouncementRequest
struct
{
Title
string
`json:"title" binding:"required"`
Content
string
`json:"content" binding:"required"`
Status
string
`json:"status" binding:"omitempty,oneof=draft active archived"`
Targeting
service
.
AnnouncementTargeting
`json:"targeting"`
StartsAt
*
int64
`json:"starts_at"`
// Unix seconds, 0/empty = immediate
EndsAt
*
int64
`json:"ends_at"`
// Unix seconds, 0/empty = never
}
type
UpdateAnnouncementRequest
struct
{
Title
*
string
`json:"title"`
Content
*
string
`json:"content"`
Status
*
string
`json:"status" binding:"omitempty,oneof=draft active archived"`
Targeting
*
service
.
AnnouncementTargeting
`json:"targeting"`
StartsAt
*
int64
`json:"starts_at"`
// Unix seconds, 0 = clear
EndsAt
*
int64
`json:"ends_at"`
// Unix seconds, 0 = clear
}
// List handles listing announcements with filters
// GET /api/v1/admin/announcements
func
(
h
*
AnnouncementHandler
)
List
(
c
*
gin
.
Context
)
{
page
,
pageSize
:=
response
.
ParsePagination
(
c
)
status
:=
strings
.
TrimSpace
(
c
.
Query
(
"status"
))
search
:=
strings
.
TrimSpace
(
c
.
Query
(
"search"
))
if
len
(
search
)
>
200
{
search
=
search
[
:
200
]
}
params
:=
pagination
.
PaginationParams
{
Page
:
page
,
PageSize
:
pageSize
,
}
items
,
paginationResult
,
err
:=
h
.
announcementService
.
List
(
c
.
Request
.
Context
(),
params
,
service
.
AnnouncementListFilters
{
Status
:
status
,
Search
:
search
},
)
if
err
!=
nil
{
response
.
ErrorFrom
(
c
,
err
)
return
}
out
:=
make
([]
dto
.
Announcement
,
0
,
len
(
items
))
for
i
:=
range
items
{
out
=
append
(
out
,
*
dto
.
AnnouncementFromService
(
&
items
[
i
]))
}
response
.
Paginated
(
c
,
out
,
paginationResult
.
Total
,
page
,
pageSize
)
}
// GetByID handles getting an announcement by ID
// GET /api/v1/admin/announcements/:id
func
(
h
*
AnnouncementHandler
)
GetByID
(
c
*
gin
.
Context
)
{
announcementID
,
err
:=
strconv
.
ParseInt
(
c
.
Param
(
"id"
),
10
,
64
)
if
err
!=
nil
||
announcementID
<=
0
{
response
.
BadRequest
(
c
,
"Invalid announcement ID"
)
return
}
item
,
err
:=
h
.
announcementService
.
GetByID
(
c
.
Request
.
Context
(),
announcementID
)
if
err
!=
nil
{
response
.
ErrorFrom
(
c
,
err
)
return
}
response
.
Success
(
c
,
dto
.
AnnouncementFromService
(
item
))
}
// Create handles creating a new announcement
// POST /api/v1/admin/announcements
func
(
h
*
AnnouncementHandler
)
Create
(
c
*
gin
.
Context
)
{
var
req
CreateAnnouncementRequest
if
err
:=
c
.
ShouldBindJSON
(
&
req
);
err
!=
nil
{
response
.
BadRequest
(
c
,
"Invalid request: "
+
err
.
Error
())
return
}
subject
,
ok
:=
middleware2
.
GetAuthSubjectFromContext
(
c
)
if
!
ok
{
response
.
Unauthorized
(
c
,
"User not found in context"
)
return
}
input
:=
&
service
.
CreateAnnouncementInput
{
Title
:
req
.
Title
,
Content
:
req
.
Content
,
Status
:
req
.
Status
,
Targeting
:
req
.
Targeting
,
ActorID
:
&
subject
.
UserID
,
}
if
req
.
StartsAt
!=
nil
&&
*
req
.
StartsAt
>
0
{
t
:=
time
.
Unix
(
*
req
.
StartsAt
,
0
)
input
.
StartsAt
=
&
t
}
if
req
.
EndsAt
!=
nil
&&
*
req
.
EndsAt
>
0
{
t
:=
time
.
Unix
(
*
req
.
EndsAt
,
0
)
input
.
EndsAt
=
&
t
}
created
,
err
:=
h
.
announcementService
.
Create
(
c
.
Request
.
Context
(),
input
)
if
err
!=
nil
{
response
.
ErrorFrom
(
c
,
err
)
return
}
response
.
Success
(
c
,
dto
.
AnnouncementFromService
(
created
))
}
// Update handles updating an announcement
// PUT /api/v1/admin/announcements/:id
func
(
h
*
AnnouncementHandler
)
Update
(
c
*
gin
.
Context
)
{
announcementID
,
err
:=
strconv
.
ParseInt
(
c
.
Param
(
"id"
),
10
,
64
)
if
err
!=
nil
||
announcementID
<=
0
{
response
.
BadRequest
(
c
,
"Invalid announcement ID"
)
return
}
var
req
UpdateAnnouncementRequest
if
err
:=
c
.
ShouldBindJSON
(
&
req
);
err
!=
nil
{
response
.
BadRequest
(
c
,
"Invalid request: "
+
err
.
Error
())
return
}
subject
,
ok
:=
middleware2
.
GetAuthSubjectFromContext
(
c
)
if
!
ok
{
response
.
Unauthorized
(
c
,
"User not found in context"
)
return
}
input
:=
&
service
.
UpdateAnnouncementInput
{
Title
:
req
.
Title
,
Content
:
req
.
Content
,
Status
:
req
.
Status
,
Targeting
:
req
.
Targeting
,
ActorID
:
&
subject
.
UserID
,
}
if
req
.
StartsAt
!=
nil
{
if
*
req
.
StartsAt
==
0
{
var
cleared
*
time
.
Time
=
nil
input
.
StartsAt
=
&
cleared
}
else
{
t
:=
time
.
Unix
(
*
req
.
StartsAt
,
0
)
ptr
:=
&
t
input
.
StartsAt
=
&
ptr
}
}
if
req
.
EndsAt
!=
nil
{
if
*
req
.
EndsAt
==
0
{
var
cleared
*
time
.
Time
=
nil
input
.
EndsAt
=
&
cleared
}
else
{
t
:=
time
.
Unix
(
*
req
.
EndsAt
,
0
)
ptr
:=
&
t
input
.
EndsAt
=
&
ptr
}
}
updated
,
err
:=
h
.
announcementService
.
Update
(
c
.
Request
.
Context
(),
announcementID
,
input
)
if
err
!=
nil
{
response
.
ErrorFrom
(
c
,
err
)
return
}
response
.
Success
(
c
,
dto
.
AnnouncementFromService
(
updated
))
}
// Delete handles deleting an announcement
// DELETE /api/v1/admin/announcements/:id
func
(
h
*
AnnouncementHandler
)
Delete
(
c
*
gin
.
Context
)
{
announcementID
,
err
:=
strconv
.
ParseInt
(
c
.
Param
(
"id"
),
10
,
64
)
if
err
!=
nil
||
announcementID
<=
0
{
response
.
BadRequest
(
c
,
"Invalid announcement ID"
)
return
}
if
err
:=
h
.
announcementService
.
Delete
(
c
.
Request
.
Context
(),
announcementID
);
err
!=
nil
{
response
.
ErrorFrom
(
c
,
err
)
return
}
response
.
Success
(
c
,
gin
.
H
{
"message"
:
"Announcement deleted successfully"
})
}
// ListReadStatus handles listing users read status for an announcement
// GET /api/v1/admin/announcements/:id/read-status
func
(
h
*
AnnouncementHandler
)
ListReadStatus
(
c
*
gin
.
Context
)
{
announcementID
,
err
:=
strconv
.
ParseInt
(
c
.
Param
(
"id"
),
10
,
64
)
if
err
!=
nil
||
announcementID
<=
0
{
response
.
BadRequest
(
c
,
"Invalid announcement ID"
)
return
}
page
,
pageSize
:=
response
.
ParsePagination
(
c
)
params
:=
pagination
.
PaginationParams
{
Page
:
page
,
PageSize
:
pageSize
,
}
search
:=
strings
.
TrimSpace
(
c
.
Query
(
"search"
))
if
len
(
search
)
>
200
{
search
=
search
[
:
200
]
}
items
,
paginationResult
,
err
:=
h
.
announcementService
.
ListUserReadStatus
(
c
.
Request
.
Context
(),
announcementID
,
params
,
search
,
)
if
err
!=
nil
{
response
.
ErrorFrom
(
c
,
err
)
return
}
response
.
Paginated
(
c
,
items
,
paginationResult
.
Total
,
page
,
pageSize
)
}
backend/internal/handler/admin/group_handler.go
View file @
377bffe2
...
...
@@ -47,6 +47,8 @@ type CreateGroupRequest struct {
// 模型路由配置(仅 anthropic 平台使用)
ModelRouting
map
[
string
][]
int64
`json:"model_routing"`
ModelRoutingEnabled
bool
`json:"model_routing_enabled"`
// 从指定分组复制账号(创建后自动绑定)
CopyAccountsFromGroupIDs
[]
int64
`json:"copy_accounts_from_group_ids"`
}
// UpdateGroupRequest represents update group request
...
...
@@ -74,6 +76,8 @@ type UpdateGroupRequest struct {
// 模型路由配置(仅 anthropic 平台使用)
ModelRouting
map
[
string
][]
int64
`json:"model_routing"`
ModelRoutingEnabled
*
bool
`json:"model_routing_enabled"`
// 从指定分组复制账号(同步操作:先清空当前分组的账号绑定,再绑定源分组的账号)
CopyAccountsFromGroupIDs
[]
int64
`json:"copy_accounts_from_group_ids"`
}
// List handles listing all groups with pagination
...
...
@@ -183,6 +187,7 @@ func (h *GroupHandler) Create(c *gin.Context) {
FallbackGroupID
:
req
.
FallbackGroupID
,
ModelRouting
:
req
.
ModelRouting
,
ModelRoutingEnabled
:
req
.
ModelRoutingEnabled
,
CopyAccountsFromGroupIDs
:
req
.
CopyAccountsFromGroupIDs
,
})
if
err
!=
nil
{
response
.
ErrorFrom
(
c
,
err
)
...
...
@@ -229,6 +234,7 @@ func (h *GroupHandler) Update(c *gin.Context) {
FallbackGroupID
:
req
.
FallbackGroupID
,
ModelRouting
:
req
.
ModelRouting
,
ModelRoutingEnabled
:
req
.
ModelRoutingEnabled
,
CopyAccountsFromGroupIDs
:
req
.
CopyAccountsFromGroupIDs
,
})
if
err
!=
nil
{
response
.
ErrorFrom
(
c
,
err
)
...
...
backend/internal/handler/admin/redeem_handler.go
View file @
377bffe2
...
...
@@ -29,7 +29,7 @@ func NewRedeemHandler(adminService service.AdminService) *RedeemHandler {
// GenerateRedeemCodesRequest represents generate redeem codes request
type
GenerateRedeemCodesRequest
struct
{
Count
int
`json:"count" binding:"required,min=1,max=100"`
Type
string
`json:"type" binding:"required,oneof=balance concurrency subscription"`
Type
string
`json:"type" binding:"required,oneof=balance concurrency subscription
invitation
"`
Value
float64
`json:"value" binding:"min=0"`
GroupID
*
int64
`json:"group_id"`
// 订阅类型必填
ValidityDays
int
`json:"validity_days" binding:"omitempty,max=36500"`
// 订阅类型使用,默认30天,最大100年
...
...
backend/internal/handler/admin/setting_handler.go
View file @
377bffe2
...
...
@@ -48,6 +48,10 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
RegistrationEnabled
:
settings
.
RegistrationEnabled
,
EmailVerifyEnabled
:
settings
.
EmailVerifyEnabled
,
PromoCodeEnabled
:
settings
.
PromoCodeEnabled
,
PasswordResetEnabled
:
settings
.
PasswordResetEnabled
,
InvitationCodeEnabled
:
settings
.
InvitationCodeEnabled
,
TotpEnabled
:
settings
.
TotpEnabled
,
TotpEncryptionKeyConfigured
:
h
.
settingService
.
IsTotpEncryptionKeyConfigured
(),
SMTPHost
:
settings
.
SMTPHost
,
SMTPPort
:
settings
.
SMTPPort
,
SMTPUsername
:
settings
.
SMTPUsername
,
...
...
@@ -70,6 +74,8 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
DocURL
:
settings
.
DocURL
,
HomeContent
:
settings
.
HomeContent
,
HideCcsImportButton
:
settings
.
HideCcsImportButton
,
PurchaseSubscriptionEnabled
:
settings
.
PurchaseSubscriptionEnabled
,
PurchaseSubscriptionURL
:
settings
.
PurchaseSubscriptionURL
,
DefaultConcurrency
:
settings
.
DefaultConcurrency
,
DefaultBalance
:
settings
.
DefaultBalance
,
EnableModelFallback
:
settings
.
EnableModelFallback
,
...
...
@@ -89,9 +95,12 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
// UpdateSettingsRequest 更新设置请求
type
UpdateSettingsRequest
struct
{
// 注册设置
RegistrationEnabled
bool
`json:"registration_enabled"`
EmailVerifyEnabled
bool
`json:"email_verify_enabled"`
PromoCodeEnabled
bool
`json:"promo_code_enabled"`
RegistrationEnabled
bool
`json:"registration_enabled"`
EmailVerifyEnabled
bool
`json:"email_verify_enabled"`
PromoCodeEnabled
bool
`json:"promo_code_enabled"`
PasswordResetEnabled
bool
`json:"password_reset_enabled"`
InvitationCodeEnabled
bool
`json:"invitation_code_enabled"`
TotpEnabled
bool
`json:"totp_enabled"`
// TOTP 双因素认证
// 邮件服务设置
SMTPHost
string
`json:"smtp_host"`
...
...
@@ -114,14 +123,16 @@ type UpdateSettingsRequest struct {
LinuxDoConnectRedirectURL
string
`json:"linuxdo_connect_redirect_url"`
// OEM设置
SiteName
string
`json:"site_name"`
SiteLogo
string
`json:"site_logo"`
SiteSubtitle
string
`json:"site_subtitle"`
APIBaseURL
string
`json:"api_base_url"`
ContactInfo
string
`json:"contact_info"`
DocURL
string
`json:"doc_url"`
HomeContent
string
`json:"home_content"`
HideCcsImportButton
bool
`json:"hide_ccs_import_button"`
SiteName
string
`json:"site_name"`
SiteLogo
string
`json:"site_logo"`
SiteSubtitle
string
`json:"site_subtitle"`
APIBaseURL
string
`json:"api_base_url"`
ContactInfo
string
`json:"contact_info"`
DocURL
string
`json:"doc_url"`
HomeContent
string
`json:"home_content"`
HideCcsImportButton
bool
`json:"hide_ccs_import_button"`
PurchaseSubscriptionEnabled
*
bool
`json:"purchase_subscription_enabled"`
PurchaseSubscriptionURL
*
string
`json:"purchase_subscription_url"`
// 默认配置
DefaultConcurrency
int
`json:"default_concurrency"`
...
...
@@ -198,6 +209,16 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
}
}
// TOTP 双因素认证参数验证
// 只有手动配置了加密密钥才允许启用 TOTP 功能
if
req
.
TotpEnabled
&&
!
previousSettings
.
TotpEnabled
{
// 尝试启用 TOTP,检查加密密钥是否已手动配置
if
!
h
.
settingService
.
IsTotpEncryptionKeyConfigured
()
{
response
.
BadRequest
(
c
,
"Cannot enable TOTP: TOTP_ENCRYPTION_KEY environment variable must be configured first. Generate a key with 'openssl rand -hex 32' and set it in your environment."
)
return
}
}
// LinuxDo Connect 参数验证
if
req
.
LinuxDoConnectEnabled
{
req
.
LinuxDoConnectClientID
=
strings
.
TrimSpace
(
req
.
LinuxDoConnectClientID
)
...
...
@@ -227,6 +248,34 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
}
}
// “购买订阅”页面配置验证
purchaseEnabled
:=
previousSettings
.
PurchaseSubscriptionEnabled
if
req
.
PurchaseSubscriptionEnabled
!=
nil
{
purchaseEnabled
=
*
req
.
PurchaseSubscriptionEnabled
}
purchaseURL
:=
previousSettings
.
PurchaseSubscriptionURL
if
req
.
PurchaseSubscriptionURL
!=
nil
{
purchaseURL
=
strings
.
TrimSpace
(
*
req
.
PurchaseSubscriptionURL
)
}
// - 启用时要求 URL 合法且非空
// - 禁用时允许为空;若提供了 URL 也做基本校验,避免误配置
if
purchaseEnabled
{
if
purchaseURL
==
""
{
response
.
BadRequest
(
c
,
"Purchase Subscription URL is required when enabled"
)
return
}
if
err
:=
config
.
ValidateAbsoluteHTTPURL
(
purchaseURL
);
err
!=
nil
{
response
.
BadRequest
(
c
,
"Purchase Subscription URL must be an absolute http(s) URL"
)
return
}
}
else
if
purchaseURL
!=
""
{
if
err
:=
config
.
ValidateAbsoluteHTTPURL
(
purchaseURL
);
err
!=
nil
{
response
.
BadRequest
(
c
,
"Purchase Subscription URL must be an absolute http(s) URL"
)
return
}
}
// Ops metrics collector interval validation (seconds).
if
req
.
OpsMetricsIntervalSeconds
!=
nil
{
v
:=
*
req
.
OpsMetricsIntervalSeconds
...
...
@@ -240,40 +289,45 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
}
settings
:=
&
service
.
SystemSettings
{
RegistrationEnabled
:
req
.
RegistrationEnabled
,
EmailVerifyEnabled
:
req
.
EmailVerifyEnabled
,
PromoCodeEnabled
:
req
.
PromoCodeEnabled
,
SMTPHost
:
req
.
SMTPHost
,
SMTPPort
:
req
.
SMTPPort
,
SMTPUsername
:
req
.
SMTPUsername
,
SMTPPassword
:
req
.
SMTPPassword
,
SMTPFrom
:
req
.
SMTPFrom
,
SMTPFromName
:
req
.
SMTPFromName
,
SMTPUseTLS
:
req
.
SMTPUseTLS
,
TurnstileEnabled
:
req
.
TurnstileEnabled
,
TurnstileSiteKey
:
req
.
TurnstileSiteKey
,
TurnstileSecretKey
:
req
.
TurnstileSecretKey
,
LinuxDoConnectEnabled
:
req
.
LinuxDoConnectEnabled
,
LinuxDoConnectClientID
:
req
.
LinuxDoConnectClientID
,
LinuxDoConnectClientSecret
:
req
.
LinuxDoConnectClientSecret
,
LinuxDoConnectRedirectURL
:
req
.
LinuxDoConnectRedirectURL
,
SiteName
:
req
.
SiteName
,
SiteLogo
:
req
.
SiteLogo
,
SiteSubtitle
:
req
.
SiteSubtitle
,
APIBaseURL
:
req
.
APIBaseURL
,
ContactInfo
:
req
.
ContactInfo
,
DocURL
:
req
.
DocURL
,
HomeContent
:
req
.
HomeContent
,
HideCcsImportButton
:
req
.
HideCcsImportButton
,
DefaultConcurrency
:
req
.
DefaultConcurrency
,
DefaultBalance
:
req
.
DefaultBalance
,
EnableModelFallback
:
req
.
EnableModelFallback
,
FallbackModelAnthropic
:
req
.
FallbackModelAnthropic
,
FallbackModelOpenAI
:
req
.
FallbackModelOpenAI
,
FallbackModelGemini
:
req
.
FallbackModelGemini
,
FallbackModelAntigravity
:
req
.
FallbackModelAntigravity
,
EnableIdentityPatch
:
req
.
EnableIdentityPatch
,
IdentityPatchPrompt
:
req
.
IdentityPatchPrompt
,
RegistrationEnabled
:
req
.
RegistrationEnabled
,
EmailVerifyEnabled
:
req
.
EmailVerifyEnabled
,
PromoCodeEnabled
:
req
.
PromoCodeEnabled
,
PasswordResetEnabled
:
req
.
PasswordResetEnabled
,
InvitationCodeEnabled
:
req
.
InvitationCodeEnabled
,
TotpEnabled
:
req
.
TotpEnabled
,
SMTPHost
:
req
.
SMTPHost
,
SMTPPort
:
req
.
SMTPPort
,
SMTPUsername
:
req
.
SMTPUsername
,
SMTPPassword
:
req
.
SMTPPassword
,
SMTPFrom
:
req
.
SMTPFrom
,
SMTPFromName
:
req
.
SMTPFromName
,
SMTPUseTLS
:
req
.
SMTPUseTLS
,
TurnstileEnabled
:
req
.
TurnstileEnabled
,
TurnstileSiteKey
:
req
.
TurnstileSiteKey
,
TurnstileSecretKey
:
req
.
TurnstileSecretKey
,
LinuxDoConnectEnabled
:
req
.
LinuxDoConnectEnabled
,
LinuxDoConnectClientID
:
req
.
LinuxDoConnectClientID
,
LinuxDoConnectClientSecret
:
req
.
LinuxDoConnectClientSecret
,
LinuxDoConnectRedirectURL
:
req
.
LinuxDoConnectRedirectURL
,
SiteName
:
req
.
SiteName
,
SiteLogo
:
req
.
SiteLogo
,
SiteSubtitle
:
req
.
SiteSubtitle
,
APIBaseURL
:
req
.
APIBaseURL
,
ContactInfo
:
req
.
ContactInfo
,
DocURL
:
req
.
DocURL
,
HomeContent
:
req
.
HomeContent
,
HideCcsImportButton
:
req
.
HideCcsImportButton
,
PurchaseSubscriptionEnabled
:
purchaseEnabled
,
PurchaseSubscriptionURL
:
purchaseURL
,
DefaultConcurrency
:
req
.
DefaultConcurrency
,
DefaultBalance
:
req
.
DefaultBalance
,
EnableModelFallback
:
req
.
EnableModelFallback
,
FallbackModelAnthropic
:
req
.
FallbackModelAnthropic
,
FallbackModelOpenAI
:
req
.
FallbackModelOpenAI
,
FallbackModelGemini
:
req
.
FallbackModelGemini
,
FallbackModelAntigravity
:
req
.
FallbackModelAntigravity
,
EnableIdentityPatch
:
req
.
EnableIdentityPatch
,
IdentityPatchPrompt
:
req
.
IdentityPatchPrompt
,
OpsMonitoringEnabled
:
func
()
bool
{
if
req
.
OpsMonitoringEnabled
!=
nil
{
return
*
req
.
OpsMonitoringEnabled
...
...
@@ -318,6 +372,10 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
RegistrationEnabled
:
updatedSettings
.
RegistrationEnabled
,
EmailVerifyEnabled
:
updatedSettings
.
EmailVerifyEnabled
,
PromoCodeEnabled
:
updatedSettings
.
PromoCodeEnabled
,
PasswordResetEnabled
:
updatedSettings
.
PasswordResetEnabled
,
InvitationCodeEnabled
:
updatedSettings
.
InvitationCodeEnabled
,
TotpEnabled
:
updatedSettings
.
TotpEnabled
,
TotpEncryptionKeyConfigured
:
h
.
settingService
.
IsTotpEncryptionKeyConfigured
(),
SMTPHost
:
updatedSettings
.
SMTPHost
,
SMTPPort
:
updatedSettings
.
SMTPPort
,
SMTPUsername
:
updatedSettings
.
SMTPUsername
,
...
...
@@ -340,6 +398,8 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
DocURL
:
updatedSettings
.
DocURL
,
HomeContent
:
updatedSettings
.
HomeContent
,
HideCcsImportButton
:
updatedSettings
.
HideCcsImportButton
,
PurchaseSubscriptionEnabled
:
updatedSettings
.
PurchaseSubscriptionEnabled
,
PurchaseSubscriptionURL
:
updatedSettings
.
PurchaseSubscriptionURL
,
DefaultConcurrency
:
updatedSettings
.
DefaultConcurrency
,
DefaultBalance
:
updatedSettings
.
DefaultBalance
,
EnableModelFallback
:
updatedSettings
.
EnableModelFallback
,
...
...
@@ -384,6 +444,12 @@ func diffSettings(before *service.SystemSettings, after *service.SystemSettings,
if
before
.
EmailVerifyEnabled
!=
after
.
EmailVerifyEnabled
{
changed
=
append
(
changed
,
"email_verify_enabled"
)
}
if
before
.
PasswordResetEnabled
!=
after
.
PasswordResetEnabled
{
changed
=
append
(
changed
,
"password_reset_enabled"
)
}
if
before
.
TotpEnabled
!=
after
.
TotpEnabled
{
changed
=
append
(
changed
,
"totp_enabled"
)
}
if
before
.
SMTPHost
!=
after
.
SMTPHost
{
changed
=
append
(
changed
,
"smtp_host"
)
}
...
...
backend/internal/handler/admin/subscription_handler.go
View file @
377bffe2
...
...
@@ -77,7 +77,11 @@ func (h *SubscriptionHandler) List(c *gin.Context) {
}
status
:=
c
.
Query
(
"status"
)
subscriptions
,
pagination
,
err
:=
h
.
subscriptionService
.
List
(
c
.
Request
.
Context
(),
page
,
pageSize
,
userID
,
groupID
,
status
)
// Parse sorting parameters
sortBy
:=
c
.
DefaultQuery
(
"sort_by"
,
"created_at"
)
sortOrder
:=
c
.
DefaultQuery
(
"sort_order"
,
"desc"
)
subscriptions
,
pagination
,
err
:=
h
.
subscriptionService
.
List
(
c
.
Request
.
Context
(),
page
,
pageSize
,
userID
,
groupID
,
status
,
sortBy
,
sortOrder
)
if
err
!=
nil
{
response
.
ErrorFrom
(
c
,
err
)
return
...
...
Prev
1
2
3
4
5
6
7
…
12
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment