50 lines
1.4 KiB
TypeScript
50 lines
1.4 KiB
TypeScript
/**
|
|
* The invite routes.
|
|
*
|
|
* @module
|
|
*/
|
|
|
|
import { Router } from "@oak/oak";
|
|
import { APIErrorCode, type APIResponse } from "../../shared/api.ts";
|
|
import { APIException } from "../lib/api-exception.ts";
|
|
import type { InviteResponse } from "../../shared/user.ts";
|
|
import { type AuthContext, authMiddleware } from "../middleware/auth.ts";
|
|
import { createInvite, validateInvite } from "../services/invite-service.ts";
|
|
|
|
/**
|
|
* The invite routes:
|
|
*
|
|
* - `POST /api/invites` — signed in. Makes an invite and answers its token.
|
|
* - `GET /api/invites/:token` — public. Checks an invite is valid, before the
|
|
* register page shows its form; 404 when it isn't.
|
|
*/
|
|
const router: Router = new Router({ prefix: "/api/invites" });
|
|
|
|
router.post("/", authMiddleware, (ctx: AuthContext) => {
|
|
if (!ctx.state.user) {
|
|
throw new APIException(APIErrorCode.UNAUTHORIZED, 401, "Not authenticated");
|
|
}
|
|
const responseBody: APIResponse<InviteResponse> = {
|
|
success: true,
|
|
data: { token: createInvite(ctx.state.user.userId) },
|
|
};
|
|
ctx.response.status = 201;
|
|
ctx.response.body = responseBody;
|
|
});
|
|
|
|
router.get("/:token", (ctx) => {
|
|
try {
|
|
validateInvite(ctx.params.token);
|
|
const responseBody: APIResponse<null> = { success: true, data: null };
|
|
ctx.response.body = responseBody;
|
|
} catch {
|
|
throw new APIException(
|
|
APIErrorCode.NOT_FOUND,
|
|
404,
|
|
"Invalid or expired invite",
|
|
);
|
|
}
|
|
});
|
|
|
|
export default router;
|