Implement exercise 1.1 (open help page)

This commit is contained in:
2024-11-14 08:09:06 +01:00
parent 20b9a59257
commit c2fe6ee3d2
8 changed files with 126 additions and 79 deletions

View File

@@ -10,16 +10,14 @@
"nameEn": "Register", "nameEn": "Register",
"exerciseNr": 1, "exerciseNr": 1,
"descriptionDe": "Erstelle einen neuen Account im Online Shop", "descriptionDe": "Erstelle einen neuen Account im Online Shop",
"descriptionEn": "Create a new account in the online shop", "descriptionEn": "Create a new account in the online shop"
"solved": false
}, },
{ {
"nameDe": "Ein Ticket kaufen", "nameDe": "Ein Ticket kaufen",
"nameEn": "Buy a ticket", "nameEn": "Buy a ticket",
"exerciseNr": 2, "exerciseNr": 2,
"descriptionDe": "Suche dir ein Event deiner Wahl und kaufe dafür ein Ticket", "descriptionDe": "Suche dir ein Event deiner Wahl und kaufe dafür ein Ticket",
"descriptionEn": "Search for an event of choice and buy a ticket for", "descriptionEn": "Search for an event of choice and buy a ticket for"
"solved": false
} }
] ]
}, },
@@ -33,16 +31,14 @@
"nameEn": "Access Help Page", "nameEn": "Access Help Page",
"exerciseNr": 1, "exerciseNr": 1,
"descriptionDe": "Manipuliere die URL so, dass du die Hilfe-Seite erreichen kannst", "descriptionDe": "Manipuliere die URL so, dass du die Hilfe-Seite erreichen kannst",
"descriptionEn": "Manipulate the URL and access the help page", "descriptionEn": "Manipulate the URL and access the help page"
"solved": false
}, },
{ {
"nameDe": "Das ausgebuchte Konzert buchen", "nameDe": "Das ausgebuchte Konzert buchen",
"nameEn": "Book the unavailable concert", "nameEn": "Book the unavailable concert",
"exerciseNr": 2, "exerciseNr": 2,
"descriptionDe": "Manipuliere die URL so, dass du das ausgebuchte Konzert aufrufen kannst und buche ein Ticket dafür", "descriptionDe": "Manipuliere die URL so, dass du das ausgebuchte Konzert aufrufen kannst und buche ein Ticket dafür",
"descriptionEn": "Manipulate the URL and access the sold out concert and buy a ticket", "descriptionEn": "Manipulate the URL and access the sold out concert and buy a ticket"
"solved": false
} }
] ]
}, },
@@ -56,24 +52,21 @@
"nameEn": "Readout account names", "nameEn": "Readout account names",
"exerciseNr": 1, "exerciseNr": 1,
"descriptionDe": "Lasse dir alle Accountnamen über das Suchfeld ausgeben", "descriptionDe": "Lasse dir alle Accountnamen über das Suchfeld ausgeben",
"descriptionEn": "Readout all account names via the search field", "descriptionEn": "Readout all account names via the search field"
"solved": false
}, },
{ {
"nameDe": "Passwort auslesen", "nameDe": "Passwort auslesen",
"nameEn": "Readout password", "nameEn": "Readout password",
"exerciseNr": 2, "exerciseNr": 2,
"descriptionDe": "Versuche ein Passwort aus der Datenbank eines Accounts auszulesen", "descriptionDe": "Versuche ein Passwort aus der Datenbank eines Accounts auszulesen",
"descriptionEn": "Get the password of an account from the database", "descriptionEn": "Get the password of an account from the database"
"solved": false
}, },
{ {
"nameDe": "Verändere deine Account Berechtigungen", "nameDe": "Verändere deine Account Berechtigungen",
"nameEn": "Change your account role", "nameEn": "Change your account role",
"exerciseNr": 3, "exerciseNr": 3,
"descriptionDe": "Ändere die Berechtigungen deines Accounts", "descriptionDe": "Ändere die Berechtigungen deines Accounts",
"descriptionEn": "Change the privileges of your account", "descriptionEn": "Change the privileges of your account"
"solved": false
} }
] ]
}, },
@@ -87,24 +80,21 @@
"nameEn": "Hello World!", "nameEn": "Hello World!",
"exerciseNr": 1, "exerciseNr": 1,
"descriptionDe": "Nimm dir eine URL des Shops und erweitere sie mit JavaScript Code so, dass beim Öffnen des Links eine 'Hallo Welt' Nachricht erscheint", "descriptionDe": "Nimm dir eine URL des Shops und erweitere sie mit JavaScript Code so, dass beim Öffnen des Links eine 'Hallo Welt' Nachricht erscheint",
"descriptionEn": "Take an URL of the shop and extend it with JavaScript code so that a 'Hello World' message appears whent the link is opened", "descriptionEn": "Take an URL of the shop and extend it with JavaScript code so that a 'Hello World' message appears whent the link is opened"
"solved": false
}, },
{ {
"nameDe": "Ein externes Script aufrufen", "nameDe": "Ein externes Script aufrufen",
"nameEn": "Run an external script", "nameEn": "Run an external script",
"exerciseNr": 2, "exerciseNr": 2,
"descriptionDe": "Bearbeite die URL des Shops so, dass du das Script ausführen kannst", "descriptionDe": "Bearbeite die URL des Shops so, dass du das Script ausführen kannst",
"descriptionEn": "Create an URL of the shop, which calls the script", "descriptionEn": "Create an URL of the shop, which calls the script"
"solved": false
}, },
{ {
"nameDe": "Hacken mit eigenem Script", "nameDe": "Hacken mit eigenem Script",
"nameEn": "Hack with your script", "nameEn": "Hack with your script",
"exerciseNr": 3, "exerciseNr": 3,
"descriptionDe": "Schreibe eine JavaScript Datei, lade sie über das Admin Panel hoch und kreiere eine URL, welche es ausführt", "descriptionDe": "Schreibe eine JavaScript Datei, lade sie über das Admin Panel hoch und kreiere eine URL, welche es ausführt",
"descriptionEn": "Write our own JavaScript file, upload it via Admin Panel and create an URL to execute it", "descriptionEn": "Write our own JavaScript file, upload it via Admin Panel and create an URL to execute it"
"solved": false
} }
] ]
} }

View File

@@ -21,11 +21,9 @@ account.get("/", (req: Request, res: Response) => {
// Login user // Login user
account.post("/login", async (req: Request, res: Response) => { account.post("/login", async (req: Request, res: Response) => {
// Using raw SQL code for SQL injections! // Using raw SQL code for SQL injections!
// todo: Inner join
const [results, metadata] = const [results, metadata] =
await sequelize.query( await sequelize.query(
"SELECT * FROM Accounts " + "SELECT * FROM Accounts " +
"INNER JOIN Addresses ON Accounts.id=Addresses.accountId " +
"WHERE (username='" + req.body.username + "WHERE (username='" + req.body.username +
"' AND password='" + req.body.password + "')") "' AND password='" + req.body.password + "')")
@@ -42,6 +40,7 @@ account.post("/login", async (req: Request, res: Response) => {
} }
if (results.length != 0) { if (results.length != 0) {
// Status: 200 OK // Status: 200 OK
res.status(200).json(results[0]) res.status(200).json(results[0])
} else { } else {

View File

@@ -1,3 +1,4 @@
import { Op } from "sequelize";
import { Exercise } from "../models/exercises/exercise.model"; import { Exercise } from "../models/exercises/exercise.model";
import { ExerciseGroup } from "../models/exercises/exerciseGroup.model"; import { ExerciseGroup } from "../models/exercises/exerciseGroup.model";
import { Request, Response, Router } from "express"; import { Request, Response, Router } from "express";
@@ -27,19 +28,47 @@ exercises.get("/", (req: Request, res: Response) => {
* @param state New state boolean * @param state New state boolean
*/ */
exercises.post("/:groupNr/:exerciseNr/:state", (req: Request, res: Response) => { exercises.post("/:groupNr/:exerciseNr/:state", (req: Request, res: Response) => {
ExerciseGroup.findOne({ Exercise.findOne({
where: { groupNr: req.params.groupNr } where: {
}) [Op.and] : [
.then(group => { {
Exercise.findOne({ exerciseNr: req.params.exerciseNr
where: { },
exerciseNr: req.params.exerciseNr, {
exerciseGroupId: group.id "$exerciseGroup.groupNr$": req.params.groupNr
} }
}) ]
.then(exercise => { },
exercise.update({ solved: req.params.state == "1"}) include: [ ExerciseGroup ]
res.status(200).send() })
.then(async exercise => {
let changed = false
if (exercise.dataValues.solved != (req.params.state == "1")) {
await exercise.update({ solved: req.params.state == "1" })
changed = true
}
res.status(200).json({
exercise: exercise,
changed: changed
}) })
}) })
// ExerciseGroup.findOne({
// where: { groupNr: req.params.groupNr }
// })
// .then(group => {
// Exercise.findOne({
// where: {
// exerciseNr: req.params.exerciseNr,
// exerciseGroupId: group.id
// }
// })
// .then(exercise => {
// exercise.update({ solved: req.params.state == "1"})
// res.status(200).send()
// })
// })
}) })

View File

@@ -131,7 +131,6 @@ location.get("/search", (req: Request, res: Response) => {
include: [ City, Concert ] include: [ City, Concert ]
}) })
.then(locations => { .then(locations => {
console.log(locations)
res.status(200).json(locations) res.status(200).json(locations)
}) })
}) })

View File

@@ -64,6 +64,7 @@ export async function prepopulateExerciseDatabase() {
.then(async dataset => { .then(async dataset => {
for (let exercise of exerciseGroup.exercises) { for (let exercise of exerciseGroup.exercises) {
exercise["exerciseGroupId"] = dataset.id exercise["exerciseGroupId"] = dataset.id
exercise["solved"] = false
await Exercise.create(exercise) await Exercise.create(exercise)
} }

View File

@@ -1,9 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { useAccountStore } from '@/stores/account.store'; import { useAccountStore } from '@/stores/account.store';
import { useBasketStore } from '@/stores/basket.store'; import { useBasketStore } from '@/stores/basket.store';
import { useExerciseStore } from '@/stores/exercise.store';
const accountStore = useAccountStore() const accountStore = useAccountStore()
const basketStore = useBasketStore() const basketStore = useBasketStore()
const exerciseStore = useExerciseStore()
exerciseStore.getAllExercises()
</script> </script>
<template> <template>
@@ -30,6 +34,12 @@ const basketStore = useBasketStore()
to="/admin" to="/admin"
/> />
<v-btn variant="plain" icon="mdi-help" to="/help" /> <v-btn
v-if="exerciseStore.helpPageVisible"
variant="plain"
icon="mdi-help"
to="/help"
/>
<v-btn variant="plain" icon="mdi-cog" to="/preferences"/> <v-btn variant="plain" icon="mdi-cog" to="/preferences"/>
</template> </template>

View File

@@ -9,7 +9,7 @@ import { LanguageEnum } from '@/data/enums/languageEnum';
const exerciseStore = useExerciseStore() const exerciseStore = useExerciseStore()
const preferencesStore = usePreferencesStore() const preferencesStore = usePreferencesStore()
exerciseStore.getAllExercises() exerciseStore.solveExercise(1, 1)
function getDotColor(exerciseGroupNr: number) { function getDotColor(exerciseGroupNr: number) {
switch(exerciseGroupNr) { switch(exerciseGroupNr) {

View File

@@ -11,7 +11,9 @@ export const useExerciseStore = defineStore("exerciseStore", {
exercises: ref<Array<ExerciseModel>>([]), exercises: ref<Array<ExerciseModel>>([]),
/** Request to server sent, waiting for data response */ /** Request to server sent, waiting for data response */
fetchInProgress: ref(false) fetchInProgress: ref(false),
helpPageVisible: ref(false)
}), }),
actions: { actions: {
@@ -24,10 +26,26 @@ export const useExerciseStore = defineStore("exerciseStore", {
await fetchAllExerciseGroups() await fetchAllExerciseGroups()
.then(result => { .then(result => {
this.exercises = result.data this.exercises = result.data
this.helpPageVisible = this.getExercise(1, 1).solved
this.fetchInProgress = false this.fetchInProgress = false
}) })
}, },
/**
* Get a exercise by group and exercise number
*
* @param exerciseGroupNr Number of group of exercise
* @param exerciseNr Number of exercise in group
*
* @returns ExerciseModel
*/
getExercise(exerciseGroupNr: number, exerciseNr: number): ExerciseModel {
return this.exercises.find((exercise: ExerciseModel) => {
return exercise.exerciseNr == exerciseNr && exercise.exerciseGroup.groupNr == exerciseGroupNr
})
},
/** /**
* Mark an exercise as solved * Mark an exercise as solved
* *
@@ -42,56 +60,57 @@ export const useExerciseStore = defineStore("exerciseStore", {
this.fetchInProgress = true this.fetchInProgress = true
// Change only if the exercise is not solved // Change only if the exercise is not solved
if(!this.exerciseGroups[exerciseGroupNr].exercises[exerciseNr - 1].solved) { updateExercise(exerciseGroupNr, exerciseNr, true)
updateExercise(exerciseGroupNr, exerciseNr, true) .then(result => {
.then(result => { if (result.data.changed) {
let bannerState = BannerStateEnum.ERROR let bannerState = BannerStateEnum.ERROR
switch(exerciseGroupNr) { switch(exerciseGroupNr) {
case 0: { case 0: {
switch(exerciseNr) { switch(exerciseNr) {
case 1: bannerState = BannerStateEnum.EXERCISESOLVED01; break; case 1: bannerState = BannerStateEnum.EXERCISESOLVED01; break;
case 2: bannerState = BannerStateEnum.EXERCISESOLVED02; break; case 2: bannerState = BannerStateEnum.EXERCISESOLVED02; break;
}
break;
} }
case 1: { break;
switch(exerciseNr) {
case 1: bannerState = BannerStateEnum.EXERCISESOLVED11; break;
case 2: bannerState = BannerStateEnum.EXERCISESOLVED12; break;
case 3: bannerState = BannerStateEnum.EXERCISESOLVED13; break;
}
break;
}
case 2: {
switch(exerciseNr) {
case 1: bannerState = BannerStateEnum.EXERCISESOLVED21; break;
case 2: bannerState = BannerStateEnum.EXERCISESOLVED22; break;
case 3: bannerState = BannerStateEnum.EXERCISESOLVED23; break;
}
break;
}
case 3: {
switch(exerciseNr) {
case 1: bannerState = BannerStateEnum.EXERCISESOLVED31; break;
case 2: bannerState = BannerStateEnum.EXERCISESOLVED32; break;
case 3: bannerState = BannerStateEnum.EXERCISESOLVED33; break;
}
break;
}
} }
case 1: {
switch(exerciseNr) {
case 1: bannerState = BannerStateEnum.EXERCISESOLVED11; break;
case 2: bannerState = BannerStateEnum.EXERCISESOLVED12; break;
case 3: bannerState = BannerStateEnum.EXERCISESOLVED13; break;
}
break;
}
case 2: {
switch(exerciseNr) {
case 1: bannerState = BannerStateEnum.EXERCISESOLVED21; break;
case 2: bannerState = BannerStateEnum.EXERCISESOLVED22; break;
case 3: bannerState = BannerStateEnum.EXERCISESOLVED23; break;
}
break;
}
case 3: {
switch(exerciseNr) {
case 1: bannerState = BannerStateEnum.EXERCISESOLVED31; break;
case 2: bannerState = BannerStateEnum.EXERCISESOLVED32; break;
case 3: bannerState = BannerStateEnum.EXERCISESOLVED33; break;
}
break;
}
}
feedbackStore.changeBanner(bannerState) feedbackStore.changeBanner(bannerState)
this.getAllExercises() this.getAllExercises()
}) }
} })
} }
} }
}) })