diff --git a/public/index.html b/public/index.html index 9644ff7..23f118a 100644 --- a/public/index.html +++ b/public/index.html @@ -12,17 +12,44 @@ -
+ \ No newline at end of file diff --git a/public/login.html b/public/login.html new file mode 100644 index 0000000..6df5d74 --- /dev/null +++ b/public/login.html @@ -0,0 +1,49 @@ + + + + + + + JS Reading App + + + + + +
+
+
+ +
+
+ +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/src/server.tsx b/src/server.tsx index fff5fab..531ed4b 100644 --- a/src/server.tsx +++ b/src/server.tsx @@ -8,10 +8,16 @@ import {QuestionSource, QuestionMeta} from './shared.ts'; type Question = [QuestionSource, QuestionMeta]; +type QuestionURLS = { + nextQuestionUrl: string, + validationUrl: string, + answerQuestionUrl: string +}; const questions: Question = Object.values(rawQuestions).flatMap(s => s.questions.map( q => [s, q])); -const router = new Router(); +const apiRouter = new Router(); +const loginRouter = new Router(); const app = new Application(); function hashString(str: string): number { @@ -45,7 +51,7 @@ function getRandomQuestion(seed: string, index: number, questions: Question[ } -function getQuestionPage(question: Question, nextQuestionUrl: string, validationUrl: string, answerQuestionUrl: string){ +function getQuestionPage(question: Question, urls: QuestionURLS){ return (
 { question[0].toString() }
@@ -64,15 +70,15 @@ function getQuestionPage(question: Question, nextQuestionUrl: string, validation
Next Question @@ -83,7 +89,7 @@ function getQuestionPage(question: Question, nextQuestionUrl: string, validation Show Answer @@ -120,43 +126,72 @@ function processValidAnswer(ctx, answer: string): void { } -router.all("/api/v1/random-questions/:seed/:idx/validate", async (ctx)=> { +function getQuestion(ctx): Question{ + const seed = ctx.params.seed; + const index = Number.parseInt(ctx.params.idx??"0"); + return getRandomQuestion(seed, index, questions); +} + +function getUrls(ctx): QuestionURLS{ const seed = ctx.params.seed; const index = Number.parseInt(ctx.params.idx??"0"); - const answer = (await ctx.request.body().value).get("answer"); const nextQuestionUrl = `/api/v1/random-questions/${seed}/${index + 1}`; - const q = getRandomQuestion(seed, index, questions); + const validationUrl = `/api/v1/random-questions/${seed}/${index}/validate`; + const answerQuestionUrl = `/api/v1/random-questions/${seed}/${index}/answer` + return {nextQuestionUrl, validationUrl, answerQuestionUrl}; +} + +apiRouter.post("/api/v1/random-questions/:seed/:idx/validate", async (ctx)=> { + const answer = (await ctx.request.body().value).get("answer"); + const q = getQuestion(ctx); if(isValidAnswer(q, answer)){ - processValidAnswer(ctx, nextQuestionUrl) + processValidAnswer(ctx, getUrls(ctx).nextQuestionUrl) }else{ - processInvalidAnswer(ctx, nextQuestionUrl) + processInvalidAnswer(ctx, getUrls(ctx).nextQuestionUrl) } }) -router.get("/api/v1/random-questions/:seed/:idx/answer", (ctx)=> { - const seed = ctx.params.seed; - const index = Number.parseInt(ctx.params.idx??"0"); - const q = getRandomQuestion(seed, index, questions); +apiRouter.get("/api/v1/random-questions/:seed/:idx/answer", (ctx)=> { + const q = getQuestion(ctx); ctx.response.body = renderToString(
The answer is {q[1].answer}
); }) -router.get("/api/v1/random-questions/:seed/:idx", (ctx)=> { - const seed = ctx.params.seed; - const index = Number.parseInt(ctx.params.idx??"0"); - const q = getRandomQuestion(seed, index, questions); - const nextQuestionUrl = `/api/v1/random-questions/${seed}/${index + 1}`; - const validationUrl = `/api/v1/random-questions/${seed}/${index}/validate`; - const answerQuestionUrl = `/api/v1/random-questions/${seed}/${index}/answer` +apiRouter.get("/api/v1/random-questions/:seed/:idx", (ctx)=> { + const q = getQuestion(ctx); + const urls = getUrls(ctx); - ctx.response.body = renderToString(getQuestionPage(q, nextQuestionUrl, validationUrl, answerQuestionUrl)); + ctx.response.body = renderToString(getQuestionPage(q, urls)); + ctx.response.headers.append("HX-Trigger", JSON.stringify({'set-question-id': ctx.params.idx})); }); -app.use(router.routes()); +loginRouter.post("/api/v1/login", async (ctx)=> { + const username = (await ctx.request.body().value).get("username"); + ctx.response.headers.append("HX-Trigger", JSON.stringify({'set-seed': username})); + ctx.response.body = username; +}); + +loginRouter.post("/api/v1/logout", (ctx)=> { + ctx.response.headers.append("HX-Trigger", "logout"); + ctx.response.body = ""; +}); + + +app.use(loginRouter.routes()); app.use(staticFiles("public", {brotli: true, fetch: true})); +app.use(async (ctx, next) => { + if(!ctx.request.headers.get('session')){ + console.log("user not logged in.") + ctx.response.headers.append("HX-Redirect", "/login.html"); + return + } + await next(); +}) +app.use(apiRouter.routes()); + await app.listen({ port: 8000 });