Merge pull request #2573 from wucm667/feat/redeem-code-expiry

feat(redeem): 兑换码支持设置使用有效期
This commit is contained in:
Wesley Liddick
2026-05-19 16:25:12 +08:00
committed by GitHub
27 changed files with 676 additions and 38 deletions
+10 -4
View File
@@ -1120,6 +1120,7 @@ var (
{Name: "used_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "notes", Type: field.TypeString, Nullable: true, SchemaType: map[string]string{"postgres": "text"}},
{Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "expires_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "validity_days", Type: field.TypeInt, Default: 30},
{Name: "group_id", Type: field.TypeInt64, Nullable: true},
{Name: "used_by", Type: field.TypeInt64, Nullable: true},
@@ -1132,13 +1133,13 @@ var (
ForeignKeys: []*schema.ForeignKey{
{
Symbol: "redeem_codes_groups_redeem_codes",
Columns: []*schema.Column{RedeemCodesColumns[9]},
Columns: []*schema.Column{RedeemCodesColumns[10]},
RefColumns: []*schema.Column{GroupsColumns[0]},
OnDelete: schema.SetNull,
},
{
Symbol: "redeem_codes_users_redeem_codes",
Columns: []*schema.Column{RedeemCodesColumns[10]},
Columns: []*schema.Column{RedeemCodesColumns[11]},
RefColumns: []*schema.Column{UsersColumns[0]},
OnDelete: schema.SetNull,
},
@@ -1152,12 +1153,17 @@ var (
{
Name: "redeemcode_used_by",
Unique: false,
Columns: []*schema.Column{RedeemCodesColumns[10]},
Columns: []*schema.Column{RedeemCodesColumns[11]},
},
{
Name: "redeemcode_group_id",
Unique: false,
Columns: []*schema.Column{RedeemCodesColumns[9]},
Columns: []*schema.Column{RedeemCodesColumns[10]},
},
{
Name: "redeemcode_expires_at",
Unique: false,
Columns: []*schema.Column{RedeemCodesColumns[8]},
},
},
}
+74 -1
View File
@@ -28602,6 +28602,7 @@ type RedeemCodeMutation struct {
used_at *time.Time
notes *string
created_at *time.Time
expires_at *time.Time
validity_days *int
addvalidity_days *int
clearedFields map[string]struct{}
@@ -29059,6 +29060,55 @@ func (m *RedeemCodeMutation) ResetCreatedAt() {
m.created_at = nil
}
// SetExpiresAt sets the "expires_at" field.
func (m *RedeemCodeMutation) SetExpiresAt(t time.Time) {
m.expires_at = &t
}
// ExpiresAt returns the value of the "expires_at" field in the mutation.
func (m *RedeemCodeMutation) ExpiresAt() (r time.Time, exists bool) {
v := m.expires_at
if v == nil {
return
}
return *v, true
}
// OldExpiresAt returns the old "expires_at" field's value of the RedeemCode entity.
// If the RedeemCode 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 *RedeemCodeMutation) OldExpiresAt(ctx context.Context) (v *time.Time, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldExpiresAt is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldExpiresAt requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldExpiresAt: %w", err)
}
return oldValue.ExpiresAt, nil
}
// ClearExpiresAt clears the value of the "expires_at" field.
func (m *RedeemCodeMutation) ClearExpiresAt() {
m.expires_at = nil
m.clearedFields[redeemcode.FieldExpiresAt] = struct{}{}
}
// ExpiresAtCleared returns if the "expires_at" field was cleared in this mutation.
func (m *RedeemCodeMutation) ExpiresAtCleared() bool {
_, ok := m.clearedFields[redeemcode.FieldExpiresAt]
return ok
}
// ResetExpiresAt resets all changes to the "expires_at" field.
func (m *RedeemCodeMutation) ResetExpiresAt() {
m.expires_at = nil
delete(m.clearedFields, redeemcode.FieldExpiresAt)
}
// SetGroupID sets the "group_id" field.
func (m *RedeemCodeMutation) SetGroupID(i int64) {
m.group = &i
@@ -29265,7 +29315,7 @@ func (m *RedeemCodeMutation) Type() string {
// order to get all numeric fields that were incremented/decremented, call
// AddedFields().
func (m *RedeemCodeMutation) Fields() []string {
fields := make([]string, 0, 10)
fields := make([]string, 0, 11)
if m.code != nil {
fields = append(fields, redeemcode.FieldCode)
}
@@ -29290,6 +29340,9 @@ func (m *RedeemCodeMutation) Fields() []string {
if m.created_at != nil {
fields = append(fields, redeemcode.FieldCreatedAt)
}
if m.expires_at != nil {
fields = append(fields, redeemcode.FieldExpiresAt)
}
if m.group != nil {
fields = append(fields, redeemcode.FieldGroupID)
}
@@ -29320,6 +29373,8 @@ func (m *RedeemCodeMutation) Field(name string) (ent.Value, bool) {
return m.Notes()
case redeemcode.FieldCreatedAt:
return m.CreatedAt()
case redeemcode.FieldExpiresAt:
return m.ExpiresAt()
case redeemcode.FieldGroupID:
return m.GroupID()
case redeemcode.FieldValidityDays:
@@ -29349,6 +29404,8 @@ func (m *RedeemCodeMutation) OldField(ctx context.Context, name string) (ent.Val
return m.OldNotes(ctx)
case redeemcode.FieldCreatedAt:
return m.OldCreatedAt(ctx)
case redeemcode.FieldExpiresAt:
return m.OldExpiresAt(ctx)
case redeemcode.FieldGroupID:
return m.OldGroupID(ctx)
case redeemcode.FieldValidityDays:
@@ -29418,6 +29475,13 @@ func (m *RedeemCodeMutation) SetField(name string, value ent.Value) error {
}
m.SetCreatedAt(v)
return nil
case redeemcode.FieldExpiresAt:
v, ok := value.(time.Time)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetExpiresAt(v)
return nil
case redeemcode.FieldGroupID:
v, ok := value.(int64)
if !ok {
@@ -29498,6 +29562,9 @@ func (m *RedeemCodeMutation) ClearedFields() []string {
if m.FieldCleared(redeemcode.FieldNotes) {
fields = append(fields, redeemcode.FieldNotes)
}
if m.FieldCleared(redeemcode.FieldExpiresAt) {
fields = append(fields, redeemcode.FieldExpiresAt)
}
if m.FieldCleared(redeemcode.FieldGroupID) {
fields = append(fields, redeemcode.FieldGroupID)
}
@@ -29524,6 +29591,9 @@ func (m *RedeemCodeMutation) ClearField(name string) error {
case redeemcode.FieldNotes:
m.ClearNotes()
return nil
case redeemcode.FieldExpiresAt:
m.ClearExpiresAt()
return nil
case redeemcode.FieldGroupID:
m.ClearGroupID()
return nil
@@ -29559,6 +29629,9 @@ func (m *RedeemCodeMutation) ResetField(name string) error {
case redeemcode.FieldCreatedAt:
m.ResetCreatedAt()
return nil
case redeemcode.FieldExpiresAt:
m.ResetExpiresAt()
return nil
case redeemcode.FieldGroupID:
m.ResetGroupID()
return nil
+15 -1
View File
@@ -35,6 +35,8 @@ type RedeemCode struct {
Notes *string `json:"notes,omitempty"`
// CreatedAt holds the value of the "created_at" field.
CreatedAt time.Time `json:"created_at,omitempty"`
// ExpiresAt holds the value of the "expires_at" field.
ExpiresAt *time.Time `json:"expires_at,omitempty"`
// GroupID holds the value of the "group_id" field.
GroupID *int64 `json:"group_id,omitempty"`
// ValidityDays holds the value of the "validity_days" field.
@@ -89,7 +91,7 @@ func (*RedeemCode) scanValues(columns []string) ([]any, error) {
values[i] = new(sql.NullInt64)
case redeemcode.FieldCode, redeemcode.FieldType, redeemcode.FieldStatus, redeemcode.FieldNotes:
values[i] = new(sql.NullString)
case redeemcode.FieldUsedAt, redeemcode.FieldCreatedAt:
case redeemcode.FieldUsedAt, redeemcode.FieldCreatedAt, redeemcode.FieldExpiresAt:
values[i] = new(sql.NullTime)
default:
values[i] = new(sql.UnknownType)
@@ -163,6 +165,13 @@ func (_m *RedeemCode) assignValues(columns []string, values []any) error {
} else if value.Valid {
_m.CreatedAt = value.Time
}
case redeemcode.FieldExpiresAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field expires_at", values[i])
} else if value.Valid {
_m.ExpiresAt = new(time.Time)
*_m.ExpiresAt = value.Time
}
case redeemcode.FieldGroupID:
if value, ok := values[i].(*sql.NullInt64); !ok {
return fmt.Errorf("unexpected type %T for field group_id", values[i])
@@ -252,6 +261,11 @@ func (_m *RedeemCode) String() string {
builder.WriteString("created_at=")
builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
builder.WriteString(", ")
if v := _m.ExpiresAt; v != nil {
builder.WriteString("expires_at=")
builder.WriteString(v.Format(time.ANSIC))
}
builder.WriteString(", ")
if v := _m.GroupID; v != nil {
builder.WriteString("group_id=")
builder.WriteString(fmt.Sprintf("%v", *v))
+8
View File
@@ -30,6 +30,8 @@ const (
FieldNotes = "notes"
// FieldCreatedAt holds the string denoting the created_at field in the database.
FieldCreatedAt = "created_at"
// FieldExpiresAt holds the string denoting the expires_at field in the database.
FieldExpiresAt = "expires_at"
// FieldGroupID holds the string denoting the group_id field in the database.
FieldGroupID = "group_id"
// FieldValidityDays holds the string denoting the validity_days field in the database.
@@ -67,6 +69,7 @@ var Columns = []string{
FieldUsedAt,
FieldNotes,
FieldCreatedAt,
FieldExpiresAt,
FieldGroupID,
FieldValidityDays,
}
@@ -148,6 +151,11 @@ func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
}
// ByExpiresAt orders the results by the expires_at field.
func ByExpiresAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldExpiresAt, opts...).ToFunc()
}
// ByGroupID orders the results by the group_id field.
func ByGroupID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldGroupID, opts...).ToFunc()
+55
View File
@@ -95,6 +95,11 @@ func CreatedAt(v time.Time) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldEQ(FieldCreatedAt, v))
}
// ExpiresAt applies equality check predicate on the "expires_at" field. It's identical to ExpiresAtEQ.
func ExpiresAt(v time.Time) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldEQ(FieldExpiresAt, v))
}
// GroupID applies equality check predicate on the "group_id" field. It's identical to GroupIDEQ.
func GroupID(v int64) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldEQ(FieldGroupID, v))
@@ -535,6 +540,56 @@ func CreatedAtLTE(v time.Time) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldLTE(FieldCreatedAt, v))
}
// ExpiresAtEQ applies the EQ predicate on the "expires_at" field.
func ExpiresAtEQ(v time.Time) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldEQ(FieldExpiresAt, v))
}
// ExpiresAtNEQ applies the NEQ predicate on the "expires_at" field.
func ExpiresAtNEQ(v time.Time) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldNEQ(FieldExpiresAt, v))
}
// ExpiresAtIn applies the In predicate on the "expires_at" field.
func ExpiresAtIn(vs ...time.Time) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldIn(FieldExpiresAt, vs...))
}
// ExpiresAtNotIn applies the NotIn predicate on the "expires_at" field.
func ExpiresAtNotIn(vs ...time.Time) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldNotIn(FieldExpiresAt, vs...))
}
// ExpiresAtGT applies the GT predicate on the "expires_at" field.
func ExpiresAtGT(v time.Time) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldGT(FieldExpiresAt, v))
}
// ExpiresAtGTE applies the GTE predicate on the "expires_at" field.
func ExpiresAtGTE(v time.Time) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldGTE(FieldExpiresAt, v))
}
// ExpiresAtLT applies the LT predicate on the "expires_at" field.
func ExpiresAtLT(v time.Time) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldLT(FieldExpiresAt, v))
}
// ExpiresAtLTE applies the LTE predicate on the "expires_at" field.
func ExpiresAtLTE(v time.Time) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldLTE(FieldExpiresAt, v))
}
// ExpiresAtIsNil applies the IsNil predicate on the "expires_at" field.
func ExpiresAtIsNil() predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldIsNull(FieldExpiresAt))
}
// ExpiresAtNotNil applies the NotNil predicate on the "expires_at" field.
func ExpiresAtNotNil() predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldNotNull(FieldExpiresAt))
}
// GroupIDEQ applies the EQ predicate on the "group_id" field.
func GroupIDEQ(v int64) predicate.RedeemCode {
return predicate.RedeemCode(sql.FieldEQ(FieldGroupID, v))
+78
View File
@@ -128,6 +128,20 @@ func (_c *RedeemCodeCreate) SetNillableCreatedAt(v *time.Time) *RedeemCodeCreate
return _c
}
// SetExpiresAt sets the "expires_at" field.
func (_c *RedeemCodeCreate) SetExpiresAt(v time.Time) *RedeemCodeCreate {
_c.mutation.SetExpiresAt(v)
return _c
}
// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil.
func (_c *RedeemCodeCreate) SetNillableExpiresAt(v *time.Time) *RedeemCodeCreate {
if v != nil {
_c.SetExpiresAt(*v)
}
return _c
}
// SetGroupID sets the "group_id" field.
func (_c *RedeemCodeCreate) SetGroupID(v int64) *RedeemCodeCreate {
_c.mutation.SetGroupID(v)
@@ -327,6 +341,10 @@ func (_c *RedeemCodeCreate) createSpec() (*RedeemCode, *sqlgraph.CreateSpec) {
_spec.SetField(redeemcode.FieldCreatedAt, field.TypeTime, value)
_node.CreatedAt = value
}
if value, ok := _c.mutation.ExpiresAt(); ok {
_spec.SetField(redeemcode.FieldExpiresAt, field.TypeTime, value)
_node.ExpiresAt = &value
}
if value, ok := _c.mutation.ValidityDays(); ok {
_spec.SetField(redeemcode.FieldValidityDays, field.TypeInt, value)
_node.ValidityDays = value
@@ -525,6 +543,24 @@ func (u *RedeemCodeUpsert) ClearNotes() *RedeemCodeUpsert {
return u
}
// SetExpiresAt sets the "expires_at" field.
func (u *RedeemCodeUpsert) SetExpiresAt(v time.Time) *RedeemCodeUpsert {
u.Set(redeemcode.FieldExpiresAt, v)
return u
}
// UpdateExpiresAt sets the "expires_at" field to the value that was provided on create.
func (u *RedeemCodeUpsert) UpdateExpiresAt() *RedeemCodeUpsert {
u.SetExcluded(redeemcode.FieldExpiresAt)
return u
}
// ClearExpiresAt clears the value of the "expires_at" field.
func (u *RedeemCodeUpsert) ClearExpiresAt() *RedeemCodeUpsert {
u.SetNull(redeemcode.FieldExpiresAt)
return u
}
// SetGroupID sets the "group_id" field.
func (u *RedeemCodeUpsert) SetGroupID(v int64) *RedeemCodeUpsert {
u.Set(redeemcode.FieldGroupID, v)
@@ -732,6 +768,27 @@ func (u *RedeemCodeUpsertOne) ClearNotes() *RedeemCodeUpsertOne {
})
}
// SetExpiresAt sets the "expires_at" field.
func (u *RedeemCodeUpsertOne) SetExpiresAt(v time.Time) *RedeemCodeUpsertOne {
return u.Update(func(s *RedeemCodeUpsert) {
s.SetExpiresAt(v)
})
}
// UpdateExpiresAt sets the "expires_at" field to the value that was provided on create.
func (u *RedeemCodeUpsertOne) UpdateExpiresAt() *RedeemCodeUpsertOne {
return u.Update(func(s *RedeemCodeUpsert) {
s.UpdateExpiresAt()
})
}
// ClearExpiresAt clears the value of the "expires_at" field.
func (u *RedeemCodeUpsertOne) ClearExpiresAt() *RedeemCodeUpsertOne {
return u.Update(func(s *RedeemCodeUpsert) {
s.ClearExpiresAt()
})
}
// SetGroupID sets the "group_id" field.
func (u *RedeemCodeUpsertOne) SetGroupID(v int64) *RedeemCodeUpsertOne {
return u.Update(func(s *RedeemCodeUpsert) {
@@ -1111,6 +1168,27 @@ func (u *RedeemCodeUpsertBulk) ClearNotes() *RedeemCodeUpsertBulk {
})
}
// SetExpiresAt sets the "expires_at" field.
func (u *RedeemCodeUpsertBulk) SetExpiresAt(v time.Time) *RedeemCodeUpsertBulk {
return u.Update(func(s *RedeemCodeUpsert) {
s.SetExpiresAt(v)
})
}
// UpdateExpiresAt sets the "expires_at" field to the value that was provided on create.
func (u *RedeemCodeUpsertBulk) UpdateExpiresAt() *RedeemCodeUpsertBulk {
return u.Update(func(s *RedeemCodeUpsert) {
s.UpdateExpiresAt()
})
}
// ClearExpiresAt clears the value of the "expires_at" field.
func (u *RedeemCodeUpsertBulk) ClearExpiresAt() *RedeemCodeUpsertBulk {
return u.Update(func(s *RedeemCodeUpsert) {
s.ClearExpiresAt()
})
}
// SetGroupID sets the "group_id" field.
func (u *RedeemCodeUpsertBulk) SetGroupID(v int64) *RedeemCodeUpsertBulk {
return u.Update(func(s *RedeemCodeUpsert) {
+52
View File
@@ -153,6 +153,26 @@ func (_u *RedeemCodeUpdate) ClearNotes() *RedeemCodeUpdate {
return _u
}
// SetExpiresAt sets the "expires_at" field.
func (_u *RedeemCodeUpdate) SetExpiresAt(v time.Time) *RedeemCodeUpdate {
_u.mutation.SetExpiresAt(v)
return _u
}
// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil.
func (_u *RedeemCodeUpdate) SetNillableExpiresAt(v *time.Time) *RedeemCodeUpdate {
if v != nil {
_u.SetExpiresAt(*v)
}
return _u
}
// ClearExpiresAt clears the value of the "expires_at" field.
func (_u *RedeemCodeUpdate) ClearExpiresAt() *RedeemCodeUpdate {
_u.mutation.ClearExpiresAt()
return _u
}
// SetGroupID sets the "group_id" field.
func (_u *RedeemCodeUpdate) SetGroupID(v int64) *RedeemCodeUpdate {
_u.mutation.SetGroupID(v)
@@ -321,6 +341,12 @@ func (_u *RedeemCodeUpdate) sqlSave(ctx context.Context) (_node int, err error)
if _u.mutation.NotesCleared() {
_spec.ClearField(redeemcode.FieldNotes, field.TypeString)
}
if value, ok := _u.mutation.ExpiresAt(); ok {
_spec.SetField(redeemcode.FieldExpiresAt, field.TypeTime, value)
}
if _u.mutation.ExpiresAtCleared() {
_spec.ClearField(redeemcode.FieldExpiresAt, field.TypeTime)
}
if value, ok := _u.mutation.ValidityDays(); ok {
_spec.SetField(redeemcode.FieldValidityDays, field.TypeInt, value)
}
@@ -528,6 +554,26 @@ func (_u *RedeemCodeUpdateOne) ClearNotes() *RedeemCodeUpdateOne {
return _u
}
// SetExpiresAt sets the "expires_at" field.
func (_u *RedeemCodeUpdateOne) SetExpiresAt(v time.Time) *RedeemCodeUpdateOne {
_u.mutation.SetExpiresAt(v)
return _u
}
// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil.
func (_u *RedeemCodeUpdateOne) SetNillableExpiresAt(v *time.Time) *RedeemCodeUpdateOne {
if v != nil {
_u.SetExpiresAt(*v)
}
return _u
}
// ClearExpiresAt clears the value of the "expires_at" field.
func (_u *RedeemCodeUpdateOne) ClearExpiresAt() *RedeemCodeUpdateOne {
_u.mutation.ClearExpiresAt()
return _u
}
// SetGroupID sets the "group_id" field.
func (_u *RedeemCodeUpdateOne) SetGroupID(v int64) *RedeemCodeUpdateOne {
_u.mutation.SetGroupID(v)
@@ -726,6 +772,12 @@ func (_u *RedeemCodeUpdateOne) sqlSave(ctx context.Context) (_node *RedeemCode,
if _u.mutation.NotesCleared() {
_spec.ClearField(redeemcode.FieldNotes, field.TypeString)
}
if value, ok := _u.mutation.ExpiresAt(); ok {
_spec.SetField(redeemcode.FieldExpiresAt, field.TypeTime, value)
}
if _u.mutation.ExpiresAtCleared() {
_spec.ClearField(redeemcode.FieldExpiresAt, field.TypeTime)
}
if value, ok := _u.mutation.ValidityDays(); ok {
_spec.SetField(redeemcode.FieldValidityDays, field.TypeInt, value)
}
+1 -1
View File
@@ -1386,7 +1386,7 @@ func init() {
// redeemcode.DefaultCreatedAt holds the default value on creation for the created_at field.
redeemcode.DefaultCreatedAt = redeemcodeDescCreatedAt.Default.(func() time.Time)
// redeemcodeDescValidityDays is the schema descriptor for validity_days field.
redeemcodeDescValidityDays := redeemcodeFields[9].Descriptor()
redeemcodeDescValidityDays := redeemcodeFields[10].Descriptor()
// redeemcode.DefaultValidityDays holds the default value on creation for the validity_days field.
redeemcode.DefaultValidityDays = redeemcodeDescValidityDays.Default.(int)
securitysecretMixin := schema.SecuritySecret{}.Mixin()
+5
View File
@@ -63,6 +63,10 @@ func (RedeemCode) Fields() []ent.Field {
Immutable().
Default(time.Now).
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
field.Time("expires_at").
Optional().
Nillable().
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
field.Int64("group_id").
Optional().
Nillable(),
@@ -90,5 +94,6 @@ func (RedeemCode) Indexes() []ent.Index {
index.Fields("status"),
index.Fields("used_by"),
index.Fields("group_id"),
index.Fields("expires_at"),
}
}