feat(api-key): add independent quota and expiration support
This feature allows API Keys to have their own quota limits and expiration times, independent of the user's balance. Backend: - Add quota, quota_used, expires_at fields to api_key schema - Implement IsExpired() and IsQuotaExhausted() checks in middleware - Add ResetQuota and ClearExpiration API endpoints - Integrate quota billing in gateway handlers (OpenAI, Anthropic, Gemini) - Include quota/expiration fields in auth cache for performance - Expiration check returns 403, quota exhausted returns 429 Frontend: - Add quota and expiration inputs to key create/edit dialog - Add quick-select buttons for expiration (+7, +30, +90 days) - Add reset quota confirmation dialog - Add expires_at column to keys list - Add i18n translations for new features (en/zh) Migration: - Add 045_add_api_key_quota.sql for new columns
This commit is contained in:
@@ -95,6 +95,21 @@ func Status(v string) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldEQ(FieldStatus, v))
|
||||
}
|
||||
|
||||
// Quota applies equality check predicate on the "quota" field. It's identical to QuotaEQ.
|
||||
func Quota(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldEQ(FieldQuota, v))
|
||||
}
|
||||
|
||||
// QuotaUsed applies equality check predicate on the "quota_used" field. It's identical to QuotaUsedEQ.
|
||||
func QuotaUsed(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldEQ(FieldQuotaUsed, v))
|
||||
}
|
||||
|
||||
// ExpiresAt applies equality check predicate on the "expires_at" field. It's identical to ExpiresAtEQ.
|
||||
func ExpiresAt(v time.Time) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldEQ(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||
func CreatedAtEQ(v time.Time) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldEQ(FieldCreatedAt, v))
|
||||
@@ -490,6 +505,136 @@ func IPBlacklistNotNil() predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldNotNull(FieldIPBlacklist))
|
||||
}
|
||||
|
||||
// QuotaEQ applies the EQ predicate on the "quota" field.
|
||||
func QuotaEQ(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldEQ(FieldQuota, v))
|
||||
}
|
||||
|
||||
// QuotaNEQ applies the NEQ predicate on the "quota" field.
|
||||
func QuotaNEQ(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldNEQ(FieldQuota, v))
|
||||
}
|
||||
|
||||
// QuotaIn applies the In predicate on the "quota" field.
|
||||
func QuotaIn(vs ...float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldIn(FieldQuota, vs...))
|
||||
}
|
||||
|
||||
// QuotaNotIn applies the NotIn predicate on the "quota" field.
|
||||
func QuotaNotIn(vs ...float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldNotIn(FieldQuota, vs...))
|
||||
}
|
||||
|
||||
// QuotaGT applies the GT predicate on the "quota" field.
|
||||
func QuotaGT(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldGT(FieldQuota, v))
|
||||
}
|
||||
|
||||
// QuotaGTE applies the GTE predicate on the "quota" field.
|
||||
func QuotaGTE(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldGTE(FieldQuota, v))
|
||||
}
|
||||
|
||||
// QuotaLT applies the LT predicate on the "quota" field.
|
||||
func QuotaLT(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldLT(FieldQuota, v))
|
||||
}
|
||||
|
||||
// QuotaLTE applies the LTE predicate on the "quota" field.
|
||||
func QuotaLTE(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldLTE(FieldQuota, v))
|
||||
}
|
||||
|
||||
// QuotaUsedEQ applies the EQ predicate on the "quota_used" field.
|
||||
func QuotaUsedEQ(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldEQ(FieldQuotaUsed, v))
|
||||
}
|
||||
|
||||
// QuotaUsedNEQ applies the NEQ predicate on the "quota_used" field.
|
||||
func QuotaUsedNEQ(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldNEQ(FieldQuotaUsed, v))
|
||||
}
|
||||
|
||||
// QuotaUsedIn applies the In predicate on the "quota_used" field.
|
||||
func QuotaUsedIn(vs ...float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldIn(FieldQuotaUsed, vs...))
|
||||
}
|
||||
|
||||
// QuotaUsedNotIn applies the NotIn predicate on the "quota_used" field.
|
||||
func QuotaUsedNotIn(vs ...float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldNotIn(FieldQuotaUsed, vs...))
|
||||
}
|
||||
|
||||
// QuotaUsedGT applies the GT predicate on the "quota_used" field.
|
||||
func QuotaUsedGT(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldGT(FieldQuotaUsed, v))
|
||||
}
|
||||
|
||||
// QuotaUsedGTE applies the GTE predicate on the "quota_used" field.
|
||||
func QuotaUsedGTE(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldGTE(FieldQuotaUsed, v))
|
||||
}
|
||||
|
||||
// QuotaUsedLT applies the LT predicate on the "quota_used" field.
|
||||
func QuotaUsedLT(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldLT(FieldQuotaUsed, v))
|
||||
}
|
||||
|
||||
// QuotaUsedLTE applies the LTE predicate on the "quota_used" field.
|
||||
func QuotaUsedLTE(v float64) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldLTE(FieldQuotaUsed, v))
|
||||
}
|
||||
|
||||
// ExpiresAtEQ applies the EQ predicate on the "expires_at" field.
|
||||
func ExpiresAtEQ(v time.Time) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldEQ(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// ExpiresAtNEQ applies the NEQ predicate on the "expires_at" field.
|
||||
func ExpiresAtNEQ(v time.Time) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldNEQ(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// ExpiresAtIn applies the In predicate on the "expires_at" field.
|
||||
func ExpiresAtIn(vs ...time.Time) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldIn(FieldExpiresAt, vs...))
|
||||
}
|
||||
|
||||
// ExpiresAtNotIn applies the NotIn predicate on the "expires_at" field.
|
||||
func ExpiresAtNotIn(vs ...time.Time) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldNotIn(FieldExpiresAt, vs...))
|
||||
}
|
||||
|
||||
// ExpiresAtGT applies the GT predicate on the "expires_at" field.
|
||||
func ExpiresAtGT(v time.Time) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldGT(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// ExpiresAtGTE applies the GTE predicate on the "expires_at" field.
|
||||
func ExpiresAtGTE(v time.Time) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldGTE(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// ExpiresAtLT applies the LT predicate on the "expires_at" field.
|
||||
func ExpiresAtLT(v time.Time) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldLT(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// ExpiresAtLTE applies the LTE predicate on the "expires_at" field.
|
||||
func ExpiresAtLTE(v time.Time) predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldLTE(FieldExpiresAt, v))
|
||||
}
|
||||
|
||||
// ExpiresAtIsNil applies the IsNil predicate on the "expires_at" field.
|
||||
func ExpiresAtIsNil() predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldIsNull(FieldExpiresAt))
|
||||
}
|
||||
|
||||
// ExpiresAtNotNil applies the NotNil predicate on the "expires_at" field.
|
||||
func ExpiresAtNotNil() predicate.APIKey {
|
||||
return predicate.APIKey(sql.FieldNotNull(FieldExpiresAt))
|
||||
}
|
||||
|
||||
// HasUser applies the HasEdge predicate on the "user" edge.
|
||||
func HasUser() predicate.APIKey {
|
||||
return predicate.APIKey(func(s *sql.Selector) {
|
||||
|
||||
Reference in New Issue
Block a user