mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-11-14 08:17:26 +01:00
* feat(admin): add a Billing tab for subscriptions and sales
The admin can now follow subscriptions and sales without opening Stripe:
- Summary tiles: active subscriptions (monthly/annual), MRR with annual
plans counted as 1/12, sales and revenue for 7d/30d/90d/12m/all time,
all-time sales, subscriptions cancelling at period end, and refunds
and disputes.
- A stacked chart of sales per day, week or month by plan family.
- A by-plan table: active grants, period and all-time sales and revenue.
- A paginated list of grants with plan, Stripe status, active/expired/
revoked and user filters, linked to the admin user, repository or
conference.
- One row of webhook health: pending, failed, oldest pending event, last
error and unreviewed payment reversals.
A sale is one checkout or subscription, so a paper pack's three grants
count once. Revenue is each sale's Stripe list price, resolved once per
price and cached in memory. Currencies are never added together. Without
Stripe the page shows counts and marks revenue as unavailable.
GET /api/admin/billing/summary and /grants sit behind the admin check.
Grants get a { purchasedAt, _id } index for the list.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: preserve payment history in admin billing totals
* fix: scope billing history and preserve original sale prices
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
38 lines
7.4 KiB
JavaScript
38 lines
7.4 KiB
JavaScript
import { reviewConsentController } from "./review-consent.js";
|
||
import * as pages from "./app.js";
|
||
import * as admin from "./admin.js";
|
||
|
||
export const pageRoutes = [
|
||
{path: "/review-link", template: "partials/reviewConsent.htm", title: "Artifact consent – Anonymous GitHub", setup: (state, services) => reviewConsentController(state, services)},
|
||
{path: "/connections", template: "partials/connections.htm", title: "GitHub connections – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.connectionsController(state, services.http)},
|
||
{path: "/signin", template: "partials/signin.htm", title: "Sign in – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.signinController(state, services.http)},
|
||
{path: "/", template: "partials/home.htm", title: "Anonymous GitHub – Share the code, not the author", preserveExplorer: false, setup: (state, services) => pages.homeController(state, services.http, services.location, services.window, services.timeout)},
|
||
{path: "/dashboard", template: "partials/dashboard.htm", title: "Your anonymizations – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.unifiedDashboardController(state, services.http, services.location, services.promises, services.window, services.quotaService)},
|
||
{"path":"/pr-dashboard","redirect":"/dashboard"},
|
||
{path: "/anonymize/:repoId?", template: "partials/anonymize.htm", title: "New anonymization – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.anonymizeController(state, services.http, services.html, services.params, services.location, services.translate, services.timeout)},
|
||
{path: "/pull-request-anonymize/:pullRequestId?", template: "partials/anonymize.htm", title: "Anonymize a pull request – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.anonymizeController(state, services.http, services.html, services.params, services.location, services.translate, services.timeout)},
|
||
{path: "/gist-anonymize/:gistId?", template: "partials/anonymize.htm", title: "Anonymize a gist – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.anonymizeController(state, services.http, services.html, services.params, services.location, services.translate, services.timeout)},
|
||
{path: "/status/:repoId", template: "partials/status.htm", title: "Repository status – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.statusController(state, services.http, services.params)},
|
||
{path: "/conferences", template: "partials/conferences.htm", title: "Your conferences – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.conferencesController(state, services.http, services.location)},
|
||
{path: "/conference/new", template: "partials/newConference.htm", title: "New conference – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.newConferenceController(state, services.http, services.location, services.params)},
|
||
{path: "/conference/:conferenceId/edit", template: "partials/newConference.htm", title: "Edit conference – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.newConferenceController(state, services.http, services.location, services.params)},
|
||
{path: "/conference/:conferenceId", template: "partials/conference.htm", title: "Conference – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.conferenceController(state, services.http, services.location, services.params)},
|
||
{path: "/faq", template: "partials/faq.htm", title: "FAQ – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.faqController(state, services.http)},
|
||
{path: "/profile", template: "partials/profile.htm", title: "Your settings – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.profileController(state, services.http, services.translate, services.timeout, services.quotaService)},
|
||
{path: "/claim", template: "partials/claim.htm", title: "Claim an anonymization – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.claimController(state, services.http, services.location)},
|
||
{path: "/pr/:pullRequestId/:path(.*)*", template: "partials/pullRequest.htm", title: "Anonymous pull request – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.pullRequestController(state, services.http, services.location, services.params, services.html)},
|
||
{path: "/gist/:gistId/:path(.*)*", template: "partials/gist.htm", title: "Anonymous gist – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => pages.gistController(state, services.http, services.location, services.params, services.html)},
|
||
{path: "/r/:repoId/:path(.*)*", template: "partials/explorer.htm", title: "Anonymous repository – Anonymous GitHub", preserveExplorer: true, setup: (state, services) => pages.exploreController(state, services.http, services.location, services.params, services.html, services.promises)},
|
||
{path: "/repository/:repoId/:path(.*)*", template: "partials/explorer.htm", title: "Anonymous repository – Anonymous GitHub", preserveExplorer: true, setup: (state, services) => pages.exploreController(state, services.http, services.location, services.params, services.html, services.promises)},
|
||
{path: "/admin/", template: "partials/admin/overview.htm", title: "Admin · Overview – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => admin.overviewAdminController(state, services.http, services.location, services.interval)},
|
||
{path: "/admin/repositories", template: "partials/admin/repositories.htm", title: "Admin · Repositories – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => admin.repositoriesAdminController(state, services.http, services.location)},
|
||
{path: "/admin/users", template: "partials/admin/users.htm", title: "Admin · Users – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => admin.usersAdminController(state, services.http, services.location)},
|
||
{path: "/admin/users/:username", template: "partials/admin/user.htm", title: "Admin · User details – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => admin.userAdminController(state, services.http, services.location, services.params)},
|
||
{path: "/admin/conferences", template: "partials/admin/conferences.htm", title: "Admin · Conferences – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => admin.conferencesAdminController(state, services.http, services.location)},
|
||
{path: "/admin/billing", template: "partials/admin/billing.htm", title: "Admin · Billing – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => admin.billingAdminController(state, services.http, services.location)},
|
||
{path: "/admin/queues", template: "partials/admin/queues.htm", title: "Admin · Queues – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => admin.queuesAdminController(state, services.http, services.location, services.interval, services.timeout)},
|
||
{path: "/admin/errors", template: "partials/admin/errors.htm", title: "Admin · Errors – Anonymous GitHub", preserveExplorer: false, setup: (state, services) => admin.errorsAdminController(state, services.http, services.location, services.interval)},
|
||
{path: "/404", template: "partials/404.htm", title: "Page not found – Anonymous GitHub", preserveExplorer: false, setup: () => {}},
|
||
{path: "/:pathMatch(.*)*", template: "partials/404.htm", title: "Page not found – Anonymous GitHub", setup: () => {}},
|
||
];
|