mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-03-30 02:27:11 +00:00
Merge pull request #967 from StarryKira/fix/admin-reset-quota-monthly
fix: 管理员重置配额补全 monthly 字段并修复 ristretto 缓存异步问题 fix issue #964
This commit is contained in:
@@ -218,11 +218,12 @@ func (h *SubscriptionHandler) Extend(c *gin.Context) {
|
|||||||
|
|
||||||
// ResetSubscriptionQuotaRequest represents the reset quota request
|
// ResetSubscriptionQuotaRequest represents the reset quota request
|
||||||
type ResetSubscriptionQuotaRequest struct {
|
type ResetSubscriptionQuotaRequest struct {
|
||||||
Daily bool `json:"daily"`
|
Daily bool `json:"daily"`
|
||||||
Weekly bool `json:"weekly"`
|
Weekly bool `json:"weekly"`
|
||||||
|
Monthly bool `json:"monthly"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetQuota resets daily and/or weekly usage for a subscription.
|
// ResetQuota resets daily, weekly, and/or monthly usage for a subscription.
|
||||||
// POST /api/v1/admin/subscriptions/:id/reset-quota
|
// POST /api/v1/admin/subscriptions/:id/reset-quota
|
||||||
func (h *SubscriptionHandler) ResetQuota(c *gin.Context) {
|
func (h *SubscriptionHandler) ResetQuota(c *gin.Context) {
|
||||||
subscriptionID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
subscriptionID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||||
@@ -235,11 +236,11 @@ func (h *SubscriptionHandler) ResetQuota(c *gin.Context) {
|
|||||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !req.Daily && !req.Weekly {
|
if !req.Daily && !req.Weekly && !req.Monthly {
|
||||||
response.BadRequest(c, "At least one of 'daily' or 'weekly' must be true")
|
response.BadRequest(c, "At least one of 'daily', 'weekly', or 'monthly' must be true")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sub, err := h.subscriptionService.AdminResetQuota(c.Request.Context(), subscriptionID, req.Daily, req.Weekly)
|
sub, err := h.subscriptionService.AdminResetQuota(c.Request.Context(), subscriptionID, req.Daily, req.Weekly, req.Monthly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.ErrorFrom(c, err)
|
response.ErrorFrom(c, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -11,17 +11,19 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// resetQuotaUserSubRepoStub 支持 GetByID、ResetDailyUsage、ResetWeeklyUsage,
|
// resetQuotaUserSubRepoStub 支持 GetByID、ResetDailyUsage、ResetWeeklyUsage、ResetMonthlyUsage,
|
||||||
// 其余方法继承 userSubRepoNoop(panic)。
|
// 其余方法继承 userSubRepoNoop(panic)。
|
||||||
type resetQuotaUserSubRepoStub struct {
|
type resetQuotaUserSubRepoStub struct {
|
||||||
userSubRepoNoop
|
userSubRepoNoop
|
||||||
|
|
||||||
sub *UserSubscription
|
sub *UserSubscription
|
||||||
|
|
||||||
resetDailyCalled bool
|
resetDailyCalled bool
|
||||||
resetWeeklyCalled bool
|
resetWeeklyCalled bool
|
||||||
resetDailyErr error
|
resetMonthlyCalled bool
|
||||||
resetWeeklyErr error
|
resetDailyErr error
|
||||||
|
resetWeeklyErr error
|
||||||
|
resetMonthlyErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resetQuotaUserSubRepoStub) GetByID(_ context.Context, id int64) (*UserSubscription, error) {
|
func (r *resetQuotaUserSubRepoStub) GetByID(_ context.Context, id int64) (*UserSubscription, error) {
|
||||||
@@ -46,6 +48,11 @@ func (r *resetQuotaUserSubRepoStub) ResetWeeklyUsage(_ context.Context, _ int64,
|
|||||||
return r.resetWeeklyErr
|
return r.resetWeeklyErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *resetQuotaUserSubRepoStub) ResetMonthlyUsage(_ context.Context, _ int64, _ time.Time) error {
|
||||||
|
r.resetMonthlyCalled = true
|
||||||
|
return r.resetMonthlyErr
|
||||||
|
}
|
||||||
|
|
||||||
func newResetQuotaSvc(stub *resetQuotaUserSubRepoStub) *SubscriptionService {
|
func newResetQuotaSvc(stub *resetQuotaUserSubRepoStub) *SubscriptionService {
|
||||||
return NewSubscriptionService(groupRepoNoop{}, stub, nil, nil, nil)
|
return NewSubscriptionService(groupRepoNoop{}, stub, nil, nil, nil)
|
||||||
}
|
}
|
||||||
@@ -56,12 +63,13 @@ func TestAdminResetQuota_ResetBoth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
svc := newResetQuotaSvc(stub)
|
svc := newResetQuotaSvc(stub)
|
||||||
|
|
||||||
result, err := svc.AdminResetQuota(context.Background(), 1, true, true)
|
result, err := svc.AdminResetQuota(context.Background(), 1, true, true, false)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, result)
|
require.NotNil(t, result)
|
||||||
require.True(t, stub.resetDailyCalled, "应调用 ResetDailyUsage")
|
require.True(t, stub.resetDailyCalled, "应调用 ResetDailyUsage")
|
||||||
require.True(t, stub.resetWeeklyCalled, "应调用 ResetWeeklyUsage")
|
require.True(t, stub.resetWeeklyCalled, "应调用 ResetWeeklyUsage")
|
||||||
|
require.False(t, stub.resetMonthlyCalled, "不应调用 ResetMonthlyUsage")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAdminResetQuota_ResetDailyOnly(t *testing.T) {
|
func TestAdminResetQuota_ResetDailyOnly(t *testing.T) {
|
||||||
@@ -70,12 +78,13 @@ func TestAdminResetQuota_ResetDailyOnly(t *testing.T) {
|
|||||||
}
|
}
|
||||||
svc := newResetQuotaSvc(stub)
|
svc := newResetQuotaSvc(stub)
|
||||||
|
|
||||||
result, err := svc.AdminResetQuota(context.Background(), 2, true, false)
|
result, err := svc.AdminResetQuota(context.Background(), 2, true, false, false)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, result)
|
require.NotNil(t, result)
|
||||||
require.True(t, stub.resetDailyCalled, "应调用 ResetDailyUsage")
|
require.True(t, stub.resetDailyCalled, "应调用 ResetDailyUsage")
|
||||||
require.False(t, stub.resetWeeklyCalled, "不应调用 ResetWeeklyUsage")
|
require.False(t, stub.resetWeeklyCalled, "不应调用 ResetWeeklyUsage")
|
||||||
|
require.False(t, stub.resetMonthlyCalled, "不应调用 ResetMonthlyUsage")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAdminResetQuota_ResetWeeklyOnly(t *testing.T) {
|
func TestAdminResetQuota_ResetWeeklyOnly(t *testing.T) {
|
||||||
@@ -84,12 +93,13 @@ func TestAdminResetQuota_ResetWeeklyOnly(t *testing.T) {
|
|||||||
}
|
}
|
||||||
svc := newResetQuotaSvc(stub)
|
svc := newResetQuotaSvc(stub)
|
||||||
|
|
||||||
result, err := svc.AdminResetQuota(context.Background(), 3, false, true)
|
result, err := svc.AdminResetQuota(context.Background(), 3, false, true, false)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, result)
|
require.NotNil(t, result)
|
||||||
require.False(t, stub.resetDailyCalled, "不应调用 ResetDailyUsage")
|
require.False(t, stub.resetDailyCalled, "不应调用 ResetDailyUsage")
|
||||||
require.True(t, stub.resetWeeklyCalled, "应调用 ResetWeeklyUsage")
|
require.True(t, stub.resetWeeklyCalled, "应调用 ResetWeeklyUsage")
|
||||||
|
require.False(t, stub.resetMonthlyCalled, "不应调用 ResetMonthlyUsage")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAdminResetQuota_BothFalseReturnsError(t *testing.T) {
|
func TestAdminResetQuota_BothFalseReturnsError(t *testing.T) {
|
||||||
@@ -98,22 +108,24 @@ func TestAdminResetQuota_BothFalseReturnsError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
svc := newResetQuotaSvc(stub)
|
svc := newResetQuotaSvc(stub)
|
||||||
|
|
||||||
_, err := svc.AdminResetQuota(context.Background(), 7, false, false)
|
_, err := svc.AdminResetQuota(context.Background(), 7, false, false, false)
|
||||||
|
|
||||||
require.ErrorIs(t, err, ErrInvalidInput)
|
require.ErrorIs(t, err, ErrInvalidInput)
|
||||||
require.False(t, stub.resetDailyCalled)
|
require.False(t, stub.resetDailyCalled)
|
||||||
require.False(t, stub.resetWeeklyCalled)
|
require.False(t, stub.resetWeeklyCalled)
|
||||||
|
require.False(t, stub.resetMonthlyCalled)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAdminResetQuota_SubscriptionNotFound(t *testing.T) {
|
func TestAdminResetQuota_SubscriptionNotFound(t *testing.T) {
|
||||||
stub := &resetQuotaUserSubRepoStub{sub: nil}
|
stub := &resetQuotaUserSubRepoStub{sub: nil}
|
||||||
svc := newResetQuotaSvc(stub)
|
svc := newResetQuotaSvc(stub)
|
||||||
|
|
||||||
_, err := svc.AdminResetQuota(context.Background(), 999, true, true)
|
_, err := svc.AdminResetQuota(context.Background(), 999, true, true, true)
|
||||||
|
|
||||||
require.ErrorIs(t, err, ErrSubscriptionNotFound)
|
require.ErrorIs(t, err, ErrSubscriptionNotFound)
|
||||||
require.False(t, stub.resetDailyCalled)
|
require.False(t, stub.resetDailyCalled)
|
||||||
require.False(t, stub.resetWeeklyCalled)
|
require.False(t, stub.resetWeeklyCalled)
|
||||||
|
require.False(t, stub.resetMonthlyCalled)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAdminResetQuota_ResetDailyUsageError(t *testing.T) {
|
func TestAdminResetQuota_ResetDailyUsageError(t *testing.T) {
|
||||||
@@ -124,7 +136,7 @@ func TestAdminResetQuota_ResetDailyUsageError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
svc := newResetQuotaSvc(stub)
|
svc := newResetQuotaSvc(stub)
|
||||||
|
|
||||||
_, err := svc.AdminResetQuota(context.Background(), 4, true, true)
|
_, err := svc.AdminResetQuota(context.Background(), 4, true, true, false)
|
||||||
|
|
||||||
require.ErrorIs(t, err, dbErr)
|
require.ErrorIs(t, err, dbErr)
|
||||||
require.True(t, stub.resetDailyCalled)
|
require.True(t, stub.resetDailyCalled)
|
||||||
@@ -139,12 +151,41 @@ func TestAdminResetQuota_ResetWeeklyUsageError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
svc := newResetQuotaSvc(stub)
|
svc := newResetQuotaSvc(stub)
|
||||||
|
|
||||||
_, err := svc.AdminResetQuota(context.Background(), 5, false, true)
|
_, err := svc.AdminResetQuota(context.Background(), 5, false, true, false)
|
||||||
|
|
||||||
require.ErrorIs(t, err, dbErr)
|
require.ErrorIs(t, err, dbErr)
|
||||||
require.True(t, stub.resetWeeklyCalled)
|
require.True(t, stub.resetWeeklyCalled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAdminResetQuota_ResetMonthlyOnly(t *testing.T) {
|
||||||
|
stub := &resetQuotaUserSubRepoStub{
|
||||||
|
sub: &UserSubscription{ID: 8, UserID: 10, GroupID: 20},
|
||||||
|
}
|
||||||
|
svc := newResetQuotaSvc(stub)
|
||||||
|
|
||||||
|
result, err := svc.AdminResetQuota(context.Background(), 8, false, false, true)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, result)
|
||||||
|
require.False(t, stub.resetDailyCalled, "不应调用 ResetDailyUsage")
|
||||||
|
require.False(t, stub.resetWeeklyCalled, "不应调用 ResetWeeklyUsage")
|
||||||
|
require.True(t, stub.resetMonthlyCalled, "应调用 ResetMonthlyUsage")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAdminResetQuota_ResetMonthlyUsageError(t *testing.T) {
|
||||||
|
dbErr := errors.New("db error")
|
||||||
|
stub := &resetQuotaUserSubRepoStub{
|
||||||
|
sub: &UserSubscription{ID: 9, UserID: 10, GroupID: 20},
|
||||||
|
resetMonthlyErr: dbErr,
|
||||||
|
}
|
||||||
|
svc := newResetQuotaSvc(stub)
|
||||||
|
|
||||||
|
_, err := svc.AdminResetQuota(context.Background(), 9, false, false, true)
|
||||||
|
|
||||||
|
require.ErrorIs(t, err, dbErr)
|
||||||
|
require.True(t, stub.resetMonthlyCalled)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAdminResetQuota_ReturnsRefreshedSub(t *testing.T) {
|
func TestAdminResetQuota_ReturnsRefreshedSub(t *testing.T) {
|
||||||
stub := &resetQuotaUserSubRepoStub{
|
stub := &resetQuotaUserSubRepoStub{
|
||||||
sub: &UserSubscription{
|
sub: &UserSubscription{
|
||||||
@@ -156,7 +197,7 @@ func TestAdminResetQuota_ReturnsRefreshedSub(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
svc := newResetQuotaSvc(stub)
|
svc := newResetQuotaSvc(stub)
|
||||||
result, err := svc.AdminResetQuota(context.Background(), 6, true, false)
|
result, err := svc.AdminResetQuota(context.Background(), 6, true, false, false)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// ResetDailyUsage stub 会将 sub.DailyUsageUSD 归零,
|
// ResetDailyUsage stub 会将 sub.DailyUsageUSD 归零,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ var (
|
|||||||
ErrSubscriptionAlreadyExists = infraerrors.Conflict("SUBSCRIPTION_ALREADY_EXISTS", "subscription already exists for this user and group")
|
ErrSubscriptionAlreadyExists = infraerrors.Conflict("SUBSCRIPTION_ALREADY_EXISTS", "subscription already exists for this user and group")
|
||||||
ErrSubscriptionAssignConflict = infraerrors.Conflict("SUBSCRIPTION_ASSIGN_CONFLICT", "subscription exists but request conflicts with existing assignment semantics")
|
ErrSubscriptionAssignConflict = infraerrors.Conflict("SUBSCRIPTION_ASSIGN_CONFLICT", "subscription exists but request conflicts with existing assignment semantics")
|
||||||
ErrGroupNotSubscriptionType = infraerrors.BadRequest("GROUP_NOT_SUBSCRIPTION_TYPE", "group is not a subscription type")
|
ErrGroupNotSubscriptionType = infraerrors.BadRequest("GROUP_NOT_SUBSCRIPTION_TYPE", "group is not a subscription type")
|
||||||
ErrInvalidInput = infraerrors.BadRequest("INVALID_INPUT", "at least one of resetDaily or resetWeekly must be true")
|
ErrInvalidInput = infraerrors.BadRequest("INVALID_INPUT", "at least one of resetDaily, resetWeekly, or resetMonthly must be true")
|
||||||
ErrDailyLimitExceeded = infraerrors.TooManyRequests("DAILY_LIMIT_EXCEEDED", "daily usage limit exceeded")
|
ErrDailyLimitExceeded = infraerrors.TooManyRequests("DAILY_LIMIT_EXCEEDED", "daily usage limit exceeded")
|
||||||
ErrWeeklyLimitExceeded = infraerrors.TooManyRequests("WEEKLY_LIMIT_EXCEEDED", "weekly usage limit exceeded")
|
ErrWeeklyLimitExceeded = infraerrors.TooManyRequests("WEEKLY_LIMIT_EXCEEDED", "weekly usage limit exceeded")
|
||||||
ErrMonthlyLimitExceeded = infraerrors.TooManyRequests("MONTHLY_LIMIT_EXCEEDED", "monthly usage limit exceeded")
|
ErrMonthlyLimitExceeded = infraerrors.TooManyRequests("MONTHLY_LIMIT_EXCEEDED", "monthly usage limit exceeded")
|
||||||
@@ -696,10 +696,10 @@ func (s *SubscriptionService) CheckAndActivateWindow(ctx context.Context, sub *U
|
|||||||
return s.userSubRepo.ActivateWindows(ctx, sub.ID, windowStart)
|
return s.userSubRepo.ActivateWindows(ctx, sub.ID, windowStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdminResetQuota manually resets the daily and/or weekly usage windows.
|
// AdminResetQuota manually resets the daily, weekly, and/or monthly usage windows.
|
||||||
// Uses startOfDay(now) as the new window start, matching automatic resets.
|
// Uses startOfDay(now) as the new window start, matching automatic resets.
|
||||||
func (s *SubscriptionService) AdminResetQuota(ctx context.Context, subscriptionID int64, resetDaily, resetWeekly bool) (*UserSubscription, error) {
|
func (s *SubscriptionService) AdminResetQuota(ctx context.Context, subscriptionID int64, resetDaily, resetWeekly, resetMonthly bool) (*UserSubscription, error) {
|
||||||
if !resetDaily && !resetWeekly {
|
if !resetDaily && !resetWeekly && !resetMonthly {
|
||||||
return nil, ErrInvalidInput
|
return nil, ErrInvalidInput
|
||||||
}
|
}
|
||||||
sub, err := s.userSubRepo.GetByID(ctx, subscriptionID)
|
sub, err := s.userSubRepo.GetByID(ctx, subscriptionID)
|
||||||
@@ -717,8 +717,18 @@ func (s *SubscriptionService) AdminResetQuota(ctx context.Context, subscriptionI
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Invalidate caches, same as CheckAndResetWindows
|
if resetMonthly {
|
||||||
|
if err := s.userSubRepo.ResetMonthlyUsage(ctx, sub.ID, windowStart); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Invalidate L1 ristretto cache. Ristretto's Del() is asynchronous by design,
|
||||||
|
// so call Wait() immediately after to flush pending operations and guarantee
|
||||||
|
// the deleted key is not returned on the very next Get() call.
|
||||||
s.InvalidateSubCache(sub.UserID, sub.GroupID)
|
s.InvalidateSubCache(sub.UserID, sub.GroupID)
|
||||||
|
if s.subCacheL1 != nil {
|
||||||
|
s.subCacheL1.Wait()
|
||||||
|
}
|
||||||
if s.billingCacheService != nil {
|
if s.billingCacheService != nil {
|
||||||
_ = s.billingCacheService.InvalidateSubscription(ctx, sub.UserID, sub.GroupID)
|
_ = s.billingCacheService.InvalidateSubscription(ctx, sub.UserID, sub.GroupID)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,14 +121,14 @@ export async function revoke(id: number): Promise<{ message: string }> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset daily and/or weekly usage quota for a subscription
|
* Reset daily, weekly, and/or monthly usage quota for a subscription
|
||||||
* @param id - Subscription ID
|
* @param id - Subscription ID
|
||||||
* @param options - Which windows to reset
|
* @param options - Which windows to reset
|
||||||
* @returns Updated subscription
|
* @returns Updated subscription
|
||||||
*/
|
*/
|
||||||
export async function resetQuota(
|
export async function resetQuota(
|
||||||
id: number,
|
id: number,
|
||||||
options: { daily: boolean; weekly: boolean }
|
options: { daily: boolean; weekly: boolean; monthly: boolean }
|
||||||
): Promise<UserSubscription> {
|
): Promise<UserSubscription> {
|
||||||
const { data } = await apiClient.post<UserSubscription>(
|
const { data } = await apiClient.post<UserSubscription>(
|
||||||
`/admin/subscriptions/${id}/reset-quota`,
|
`/admin/subscriptions/${id}/reset-quota`,
|
||||||
|
|||||||
@@ -1574,7 +1574,7 @@ export default {
|
|||||||
revoke: 'Revoke',
|
revoke: 'Revoke',
|
||||||
resetQuota: 'Reset Quota',
|
resetQuota: 'Reset Quota',
|
||||||
resetQuotaTitle: 'Reset Usage Quota',
|
resetQuotaTitle: 'Reset Usage Quota',
|
||||||
resetQuotaConfirm: "Reset the daily and weekly usage quota for '{user}'? Usage will be zeroed and windows restarted from today.",
|
resetQuotaConfirm: "Reset the daily, weekly, and monthly usage quota for '{user}'? Usage will be zeroed and windows restarted from today.",
|
||||||
quotaResetSuccess: 'Quota reset successfully',
|
quotaResetSuccess: 'Quota reset successfully',
|
||||||
failedToResetQuota: 'Failed to reset quota',
|
failedToResetQuota: 'Failed to reset quota',
|
||||||
noSubscriptionsYet: 'No subscriptions yet',
|
noSubscriptionsYet: 'No subscriptions yet',
|
||||||
|
|||||||
@@ -1662,7 +1662,7 @@ export default {
|
|||||||
revoke: '撤销',
|
revoke: '撤销',
|
||||||
resetQuota: '重置配额',
|
resetQuota: '重置配额',
|
||||||
resetQuotaTitle: '重置用量配额',
|
resetQuotaTitle: '重置用量配额',
|
||||||
resetQuotaConfirm: "确定要重置 '{user}' 的每日和每周用量配额吗?用量将归零并从今天开始重新计算。",
|
resetQuotaConfirm: "确定要重置 '{user}' 的每日、每周和每月用量配额吗?用量将归零并从今天开始重新计算。",
|
||||||
quotaResetSuccess: '配额重置成功',
|
quotaResetSuccess: '配额重置成功',
|
||||||
failedToResetQuota: '重置配额失败',
|
failedToResetQuota: '重置配额失败',
|
||||||
noSubscriptionsYet: '暂无订阅',
|
noSubscriptionsYet: '暂无订阅',
|
||||||
|
|||||||
@@ -1154,7 +1154,7 @@ const confirmResetQuota = async () => {
|
|||||||
if (resettingQuota.value) return
|
if (resettingQuota.value) return
|
||||||
resettingQuota.value = true
|
resettingQuota.value = true
|
||||||
try {
|
try {
|
||||||
await adminAPI.subscriptions.resetQuota(resettingSubscription.value.id, { daily: true, weekly: true })
|
await adminAPI.subscriptions.resetQuota(resettingSubscription.value.id, { daily: true, weekly: true, monthly: true })
|
||||||
appStore.showSuccess(t('admin.subscriptions.quotaResetSuccess'))
|
appStore.showSuccess(t('admin.subscriptions.quotaResetSuccess'))
|
||||||
showResetQuotaConfirm.value = false
|
showResetQuotaConfirm.value = false
|
||||||
resettingSubscription.value = null
|
resettingSubscription.value = null
|
||||||
|
|||||||
Reference in New Issue
Block a user