diff --git a/README.md b/README.md index 1656734..2d94044 100644 --- a/README.md +++ b/README.md @@ -35,19 +35,18 @@ The newest at the moment of me writing this (December 16th 2025) are the (visual - [x] en - [ ] de - [ ] ua - - [ ] db: examstore add language field, api handle languages -- [ ] db: (revise) script for processing, (revise and) share appropriate files + - [x] db: examstore add language field, api handle languages (questions lang) - [ ] clean up js code in exam.vue and result.vue (currently a little bit of a mess) ## Some information about the project My intention is, to share access to test exams free of charge, you don't have to pay me - although you can, I greatly appreciate if you donate! -In the future I will host this project publicly `aaS`, and will probably put non-invasive, privacy friendly ads if it gains enough traction +I'm planning to host this project publicly and to put non-invasive ads if it gains enough traction -All data used by this software is public information by definition provided in the Polish Constitution - (article 61.)[https://www.sejm.gov.pl/prawo/konst/polski/kon1.htm], and can be acquired by either checking above links on the gov website, or by writing to the Ministry ((if something happened to be missing))[placeholder_for_post_about_missing_points_column] +All data used by this software is public information by definition provided in the Polish Constitution - [article 61.](https://www.sejm.gov.pl/prawo/konst/polski/kon1.htm), and can be acquired by either checking above links on the gov website, or by writing to the Ministry [(if something happened to be missing)](placeholder_for_post_about_missing_points_column) ==> (blog post to write in the future) -This project is a website mimicking an official driver's license theoritical exam (for different license categories) with a seperate media server, connected using drizzle ORM to a SQLite database +This project is a website mimicking an official driver's license theoritical exam (for all license categories provided by the Ministry: A, A1, A2, AM, B, B1, C, C1, D, D1, T, PT) with a seperate media http server (not included here), connected using drizzle ORM to a SQLite database ## Setup @@ -57,7 +56,11 @@ This project utilizes `pnpm`, thus it is recommended pnpm install ``` -## Development Server +Check out `.env.example`, mainly CDN_URL for media http url + +As of Dec. 16 2025 a test database is included at `./db/database.db` + +### Development Server Start the development server on `http://localhost:3000`: @@ -65,7 +68,7 @@ Start the development server on `http://localhost:3000`: pnpm run dev ``` -## Production +### Production Build the application for production: diff --git a/pages/exam.vue b/pages/exam.vue index 3c73cc1..0f4c44c 100644 --- a/pages/exam.vue +++ b/pages/exam.vue @@ -116,6 +116,7 @@ const { } = await useLazyFetch(`/api/basic`, { query: { category: examStore.category, + lang: examStore.lang, }, }); @@ -126,6 +127,7 @@ const { } = await useLazyFetch(`/api/advanced`, { query: { category: examStore.category, + lang: examStore.lang, }, }); diff --git a/server/api/advanced.get.ts b/server/api/advanced.get.ts index 7046123..d3d60c1 100644 --- a/server/api/advanced.get.ts +++ b/server/api/advanced.get.ts @@ -9,22 +9,34 @@ import categories from '~/categories'; export default defineEventHandler(async (event) => { const query = getQuery(event); const category = query.category; + const lang = query.lang; - if (category === '' || typeof category !== 'string') { - throw createError({ - statusCode: 400, - statusMessage: - 'category argument has to be string (or not to be defined at all)', - }); - } - if (!categories.includes(`${category.toUpperCase()}`)) { + if ( + typeof category !== 'string' || + !categories.includes(`${category.toUpperCase()}`) + ) { throw createError({ statusCode: 400, statusMessage: `category argument has to be equal to either: ${categories}`, }); } - async function getFromDb(points: number, limit: number, category: string) { + if ( + typeof lang !== 'string' || + !['PL', 'EN', 'DE', 'UA'].includes(`${lang.toUpperCase()}`) + ) { + throw createError({ + statusCode: 400, + statusMessage: `lang argument has to be equal to either: pl, en, de, ua`, + }); + } + + async function getFromDb( + points: number, + limit: number, + category: string, + lang: string, + ) { return await db .select({ id: tasks_advanced.id, @@ -45,7 +57,7 @@ export default defineEventHandler(async (event) => { .where( and( eq(categories_db.name, category.toUpperCase()), - eq(questions_advanced.lang, 'PL'), + eq(questions_advanced.lang, lang.toUpperCase()), eq(tasks_advanced.weight, points), ), ) @@ -57,7 +69,7 @@ export default defineEventHandler(async (event) => { const randomizedQuestions: AdvancedQuestion[] = []; for (const [key, value] of Object.entries({ 1: 2, 2: 4, 3: 6 })) { - randomizedQuestions.push(...(await getFromDb(+key, value, category))); + randomizedQuestions.push(...(await getFromDb(+key, value, category, lang))); } return arrayShuffle(randomizedQuestions); }); diff --git a/server/api/basic.get.ts b/server/api/basic.get.ts index 1f2e564..88fc16b 100644 --- a/server/api/basic.get.ts +++ b/server/api/basic.get.ts @@ -9,22 +9,34 @@ import categories from '~/categories'; export default defineEventHandler(async (event) => { const query = getQuery(event); const category = query.category; + const lang = query.lang; - if (category === '' || typeof category !== 'string') { - throw createError({ - statusCode: 400, - statusMessage: - 'category argument has to be string (or not to be defined at all)', - }); - } - if (!categories.includes(`${category.toUpperCase()}`)) { + if ( + typeof category !== 'string' || + !categories.includes(`${category.toUpperCase()}`) + ) { throw createError({ statusCode: 400, statusMessage: `category argument has to be equal to either: ${categories}`, }); } - async function getFromDb(points: number, limit: number, category: string) { + if ( + typeof lang !== 'string' || + !['PL', 'EN', 'DE', 'UA'].includes(`${lang.toUpperCase()}`) + ) { + throw createError({ + statusCode: 400, + statusMessage: `lang argument has to be equal to either: pl, en, de, ua`, + }); + } + + async function getFromDb( + points: number, + limit: number, + category: string, + lang: string, + ) { return await db .select({ id: tasks.id, @@ -39,7 +51,7 @@ export default defineEventHandler(async (event) => { .where( and( eq(categories_db.name, category.toUpperCase()), - eq(questions.lang, 'PL'), + eq(questions.lang, lang.toUpperCase()), eq(tasks.weight, points), ), ) @@ -51,7 +63,7 @@ export default defineEventHandler(async (event) => { const randomizedQuestions: BasicQuestion[] = []; for (const [key, value] of Object.entries({ 1: 4, 2: 6, 3: 10 })) { - randomizedQuestions.push(...(await getFromDb(+key, value, category))); + randomizedQuestions.push(...(await getFromDb(+key, value, category, lang))); } return arrayShuffle(randomizedQuestions); });