added login
This commit is contained in:
1 parent
171657d616
commit
0cb2d25a62
3 files changed
+137
-26
No files matched your search
+29
-2
@@ -12,17 +12,44 @@
|
||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||
<div class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
<a class="navbar-item" href="https://bulma.io">
|
||||
<a class="navbar-item" href="#" hx-post="/api/v1/logout">
|
||||
<img src="images/js_logo.svg" alt="js logo" style="height: 100%">
|
||||
<h2 class="title is-3 ml-1">Reading Exercices</h2>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div hx-get="/api/v1/random-questions/dsdsddsf/4"
|
||||
<div hx-get="/api/v1/random-questions/:seed/:defaultIndex"
|
||||
hx-trigger="load"
|
||||
id="question-body">
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function getDefaultIndex(){
|
||||
if(document.location.hash.length > 1){
|
||||
return document.location.hash.substr(1)
|
||||
}
|
||||
return localStorage.getItem("defaultIndex") || '0';
|
||||
}
|
||||
document.body.addEventListener('htmx:configRequest', function(evt) {
|
||||
evt.detail.headers.session = localStorage.getItem("seed");
|
||||
evt.detail.path = evt.detail.path.replace(":seed", localStorage.getItem("seed"));
|
||||
|
||||
evt.detail.path = evt.detail.path.replace(":defaultIndex", getDefaultIndex());
|
||||
});
|
||||
document.body.addEventListener('logout', function (evt) {
|
||||
window.localStorage.clear();
|
||||
document.location.href = "/login.html";
|
||||
});
|
||||
|
||||
document.body.addEventListener('set-question-id', function (evt) {
|
||||
if(isNaN(evt.detail.value)){
|
||||
return;
|
||||
}
|
||||
document.location.hash = evt.detail.value
|
||||
localStorage.setItem("defaultIndex", evt.detail.value);
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>JS Reading App</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
|
||||
<script src="https://unpkg.com/htmx.org@1.9.9"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||
<div class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
<a class="navbar-item" href="#">
|
||||
<img src="images/js_logo.svg" alt="js logo" style="height: 100%">
|
||||
<h2 class="title is-3 ml-1">Reading Exercices</h2>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-half">
|
||||
<form hx-post="/api/v1/login" hx-swap="none">
|
||||
|
||||
<div class="field has-addons">
|
||||
<div class="control">
|
||||
<input class="input" id="username" type="text" placeholder="bob.l.eponge@ocean.com" name="username" required>
|
||||
</div>
|
||||
<div class="control">
|
||||
<input type="submit" class="button" value="Login">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.body.addEventListener('set-seed', function (evt) {
|
||||
const seed = document.getElementById("username").value;
|
||||
window.localStorage.setItem("seed", seed);
|
||||
document.location.href = "/";
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
+59
-24
@@ -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<T>(seed: string, index: number, questions: Question[
|
||||
|
||||
}
|
||||
|
||||
function getQuestionPage(question: Question, nextQuestionUrl: string, validationUrl: string, answerQuestionUrl: string){
|
||||
function getQuestionPage(question: Question, urls: QuestionURLS){
|
||||
return (<div>
|
||||
<pre> { question[0].toString() }</pre>
|
||||
<div class="content mt-2 mb-2">
|
||||
@@ -64,15 +70,15 @@ function getQuestionPage(question: Question, nextQuestionUrl: string, validation
|
||||
<button class="button is-info"
|
||||
hx-trigger="click"
|
||||
hx-target="#message"
|
||||
hx-post={validationUrl} >
|
||||
hx-post={urls.validationUrl} >
|
||||
Verify Answer
|
||||
</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a class="button is-info"
|
||||
href="#"
|
||||
hx-trigger="next-question from:body delay:1500ms, click"
|
||||
hx-get={nextQuestionUrl}
|
||||
hx-trigger="next-question from:body delay:500ms, click"
|
||||
hx-get={urls.nextQuestionUrl}
|
||||
hx-params="none"
|
||||
hx-target="#question-body" >
|
||||
Next Question
|
||||
@@ -83,7 +89,7 @@ function getQuestionPage(question: Question, nextQuestionUrl: string, validation
|
||||
<a class="button is-info"
|
||||
href="#"
|
||||
hx-trigger="click"
|
||||
hx-get={answerQuestionUrl}
|
||||
hx-get={urls.answerQuestionUrl}
|
||||
hx-params="none"
|
||||
hx-target="#message" >
|
||||
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(
|
||||
<div class="notification is-warning">
|
||||
The answer is {q[1].answer}
|
||||
</div>);
|
||||
})
|
||||
|
||||
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 });
|
||||
Reference in new issue
Block a user