# All files / middleware usageLimit.ts

0% Statements 0/45
0% Branches 0/1
0% Functions 0/1
0% Lines 0/45

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66

     import { Context, Next } from 'koa';
    import { prisma } from '../models';
    import { QuotaExceededError, ForbiddenError } from './errorHandler';
    import { MEMBER_QUOTA, MemberLevel } from '../types';

    // 检查使用次数限制
    export async function usageLimitMiddleware(ctx: Context, next: Next): Promise<void> {
      const userId = ctx.state.user?.userId;

      // 测试模式：无需登录即可使用
      if (!userId) {
        ctx.state.userQuota = { dailyLimit: -1, wordLimit: -1 };
        await next();
        return;
      }

      const user = await prisma.user.findUnique({ where: { id: parseInt(userId) } });
      if (!user) {
        throw new ForbiddenError('用户不存在');
      }

      const today = new Date().toISOString().slice(0, 10);
      const memberLevel = user.memberLevel;
      const quota = MEMBER_QUOTA[memberLevel as MemberLevel];

      // 重置每日使用次数
      if (user.lastUsageDate !== today) {
        await prisma.user.update({
          where: { id: parseInt(userId) },
          data: {
            dailyUsage: 0,
            lastUsageDate: today,
          },
        });
        user.dailyUsage = 0;
        user.lastUsageDate = today;
      }

      // 检查次数限制 (-1 表示无限制)
      if (quota.dailyLimit !== -1 && user.dailyUsage >= quota.dailyLimit) {
        throw new QuotaExceededError(`今日使用次数已达上限（${quota.dailyLimit}次），请升级会员`);
      }

      // 将用户信息和配额存入 state
      ctx.state.userQuota = quota;
      ctx.state.userInfo = user;

      await next();
    }

    // 检查字数限制
    export function checkWordLimit(wordCount: number): (ctx: Context, next: Next) => Promise<void> {
      return async (ctx: Context, next: Next) => {
        const quota = ctx.state.userQuota;
        if (!quota) {
          throw new ForbiddenError('请先检查使用限制');
        }

        // -1 表示无限制
        if (quota.wordLimit !== -1 && wordCount > quota.wordLimit) {
          throw new QuotaExceededError(`文本字数超出限制（${quota.wordLimit}字），请升级会员或缩短文本`);
        }

        await next();
      };
    }