Accounts with limits: a Newznab key and a tier per user, daily API and NZB counts, invites
Test and deploy / test (push) Successful in 47s
Test and deploy / edge (push) Successful in 1m44s
Test and deploy / deploy (push) Skipped

ACCESS=accounts (config/access.ts; open stays the default and behaves as
before): Newznab and the catalog's releases routes name a user (apikey or
the web interface's token), whose tier sets searches and NZBs per UTC day
(Newznab 500/501, the catalog 429) and how far back they see (102/403).
Counted in one upsert per use, so the last one can't be taken twice;
caps, stats and refused requests aren't counted. Signup takes an invite
(SIGNUP), which may give a tier; ace access:invite, access:tier (extends a
running tier), access:suspend. The web interface signs in and shows the
day's usage and the Newznab key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daan MeijerandClaude Opus 5.5 committed 2026-10-17 00:16:45 +02:00
1 parent c55918350e
commit 1322e42fb7
23 files changed
+1023 -39

No files matched your search

+28
View File
@@ -0,0 +1,28 @@
import { BaseCommand, args, flags } from '@adonisjs/core/ace'
import type { CommandOptions } from '@adonisjs/core/types/ace'
import User from '#models/user'
/** Suspends a user (Newznab error 101, the catalog 403), e.g. for a shared key; --undo lifts it. */
export default class AccessSuspend extends BaseCommand {
static commandName = 'access:suspend'
static description = 'Suspends a user (or lifts it with --undo)'
static options: CommandOptions = { startApp: true }
@args.string({ description: 'The user’s email' })
declare email: string
@flags.boolean({ description: 'Lift the suspension' })
declare undo: boolean
async run() {
const user = await User.findBy('email', this.email)
if (!user) {
this.logger.error(`No user ${this.email}`)
this.exitCode = 1
return
}
user.suspended = !this.undo
await user.save()
this.logger.info(`${user.email}: ${user.suspended ? 'suspended' : 'active'}`)
}
}