From d98b4b01a42168bdf0129e255c81ed6497c7399c Mon Sep 17 00:00:00 2001 From: Plumey Simon Date: Tue, 2 Apr 2024 17:07:41 +0200 Subject: [PATCH 01/34] WIP --- frontend/src/components/AnswerForm.vue | 23 +++++++++++++++-------- frontend/src/views/QuizView.vue | 6 ++++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/AnswerForm.vue b/frontend/src/components/AnswerForm.vue index 87873f7..645eb7a 100644 --- a/frontend/src/components/AnswerForm.vue +++ b/frontend/src/components/AnswerForm.vue @@ -41,8 +41,8 @@ const fetchOptions = async () => { } const hasAskedOptions = async () => { - const response = await axios.get(`/api/question/has_asked_options/`); // TODO - return !!response.data.has_asked_options; // TODO + const response = await axios.get(`/api/question/options_asked`); + return !!response.data.options_asked; } const newQuestion = () => { @@ -52,16 +52,23 @@ const newQuestion = () => { emit('newQuestion'); } -onMounted(() => { +const init = async () => { // ask backend if the user has already ask options in this category // if so, show the options form - /* - if (hasAskedOptions()) { + + console.log("request Has asked options") + const response = await hasAskedOptions(); + console.log("response Has asked options") + console.log(response); + if (response) { fetchOptions(); show_text_form.value = false; - }*/ + } // if not, show the text form (default value is true) +} +onMounted(() => { + init(); }); @@ -77,7 +84,7 @@ onMounted(() => {

- Good job! {{ response_to_answer.right_answer }} was the right answer! + Good job! "{{ response_to_answer.right_answer }}" was the right answer!

Unfortunately, your answer "{{ response_to_answer.answer_sent }}" was wrong. The correct answer was "{{ @@ -94,7 +101,7 @@ onMounted(() => {

Unfortunately, your answer "{{ response_to_answer.answer_sent }}" was wrong. The correct answer was "{{ response_to_answer.right_answer }}"

- +
diff --git a/frontend/src/views/QuizView.vue b/frontend/src/views/QuizView.vue index 17d4761..461ac9d 100644 --- a/frontend/src/views/QuizView.vue +++ b/frontend/src/views/QuizView.vue @@ -9,11 +9,13 @@ const route = useRoute(); const id_category = route.params.id_category; // variables specific to this component -const question = ref(""); +const question = ref(null); const fetchNewQuestion = async () => { + console.log("fetch new question"); const response = await axios.get(`/api/question/${id_category}/new`, { }); + console.log("response to new question"); question.value = response.data.text; } @@ -29,7 +31,7 @@ onMounted(() => {

Question

{{ question }}

- + From 63b88a008abcc965a3d2ce837b591616afb7ee09 Mon Sep 17 00:00:00 2001 From: Strogator <102219695+Strogator@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:19:53 +0200 Subject: [PATCH 02/34] my bad (#77) --- frontend/src/views/Authentication/LogoutView.vue | 3 +++ frontend/src/views/Authentication/SignUpView.vue | 3 +++ 2 files changed, 6 insertions(+) diff --git a/frontend/src/views/Authentication/LogoutView.vue b/frontend/src/views/Authentication/LogoutView.vue index e69de29..956dc09 100644 --- a/frontend/src/views/Authentication/LogoutView.vue +++ b/frontend/src/views/Authentication/LogoutView.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/frontend/src/views/Authentication/SignUpView.vue b/frontend/src/views/Authentication/SignUpView.vue index e69de29..08d003c 100644 --- a/frontend/src/views/Authentication/SignUpView.vue +++ b/frontend/src/views/Authentication/SignUpView.vue @@ -0,0 +1,3 @@ + \ No newline at end of file From c8c56cad58a44ee49673d5e3d8e2f64271e9d965 Mon Sep 17 00:00:00 2001 From: Plumey Simon Date: Tue, 9 Apr 2024 13:40:52 +0200 Subject: [PATCH 03/34] Creating apiclient for fetching data --- frontend/src/api_client.js | 20 ++++++++++++++++++++ frontend/src/main.js | 5 ----- frontend/src/views/HomeView.vue | 14 +++----------- 3 files changed, 23 insertions(+), 16 deletions(-) create mode 100644 frontend/src/api_client.js diff --git a/frontend/src/api_client.js b/frontend/src/api_client.js new file mode 100644 index 0000000..0a775d6 --- /dev/null +++ b/frontend/src/api_client.js @@ -0,0 +1,20 @@ +import axios from 'axios'; + +// set the default base url for axios requests +const API_SERVER = import.meta.env.VITE_API_SERVER; +axios.defaults.baseURL = API_SERVER; +axios.defaults.withCredentials = true; + +export default +class APIClient { + /** + * Get all the categories with current IQ in each category + * (keys are category id) + * @returns + */ + static async getCategories() + { + const response = await axios.get(`/api/category/iq/`); + return response.data; + } +} \ No newline at end of file diff --git a/frontend/src/main.js b/frontend/src/main.js index 422f8f5..5a5dbdb 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -3,11 +3,6 @@ import './assets/main.css' import { createApp } from 'vue' import App from './App.vue' import router from './router' -import axios from 'axios' - -const API_SERVER = import.meta.env.VITE_API_SERVER; -axios.defaults.baseURL = API_SERVER; -axios.defaults.withCredentials = true; const app = createApp(App) diff --git a/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue index 3b6268b..2101ad6 100644 --- a/frontend/src/views/HomeView.vue +++ b/frontend/src/views/HomeView.vue @@ -1,21 +1,13 @@ From 8ff03b28c7881a0e3712440afd4c1d74ca6c6066 Mon Sep 17 00:00:00 2001 From: Alessio Comi Date: Fri, 5 Apr 2024 14:54:58 +0200 Subject: [PATCH 04/34] add backend login, logout and signup --- .github/workflows/django_test.yml | 36 ------------------- api/masteriq/urls.py | 4 ++- api/masteriqapp/views/AuthenticationView.py | 35 ++++++++++++++++++ api/masteriqapp/views/IQView.py | 7 ++-- api/masteriqapp/views/__init__.py | 1 + .../views/{ => Authentication}/LoginView.vue | 0 .../src/views/Authentication/LogoutView.vue | 0 .../src/views/Authentication/RegisterView.vue | 36 +++++++++++++++++++ frontend/src/views/RegisterView.vue | 5 --- 9 files changed, 79 insertions(+), 45 deletions(-) delete mode 100644 .github/workflows/django_test.yml create mode 100644 api/masteriqapp/views/AuthenticationView.py rename frontend/src/views/{ => Authentication}/LoginView.vue (100%) create mode 100644 frontend/src/views/Authentication/LogoutView.vue create mode 100644 frontend/src/views/Authentication/RegisterView.vue delete mode 100644 frontend/src/views/RegisterView.vue diff --git a/.github/workflows/django_test.yml b/.github/workflows/django_test.yml deleted file mode 100644 index f4af184..0000000 --- a/.github/workflows/django_test.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Django CI - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -jobs: - build: - - runs-on: ubuntu-latest - strategy: - max-parallel: 4 - matrix: - python-version: [3.11] - - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install Dependencies - run: | - python -m pip install --upgrade pip - cd api - pip install -r requirements.txt - - name: Copy .env - run: | - cd api - cp .env.cicd .env - - name: Run Tests - run: | - cd api - python manage.py test diff --git a/api/masteriq/urls.py b/api/masteriq/urls.py index 2a968fa..b6bb9b9 100644 --- a/api/masteriq/urls.py +++ b/api/masteriq/urls.py @@ -26,8 +26,10 @@ router.register("category", views.IQView, basename="category") router.register("question", views.QuestionView, basename="question") router.register("rank", views.RankView, basename="rank") +router.register("user", views.AuthenticationView, basename="user") + urlpatterns = [ path('admin/', admin.site.urls), - path("api/", include(router.urls)) + path("api/", include(router.urls)), ] diff --git a/api/masteriqapp/views/AuthenticationView.py b/api/masteriqapp/views/AuthenticationView.py new file mode 100644 index 0000000..420df27 --- /dev/null +++ b/api/masteriqapp/views/AuthenticationView.py @@ -0,0 +1,35 @@ +from rest_framework import viewsets, status +from rest_framework.response import Response +from django.contrib.auth import authenticate, login, logout +from django.contrib.auth.models import User +from rest_framework.decorators import action +from rest_framework.permissions import AllowAny + + +class AuthenticationView(viewsets.ViewSet): + @action(detail=False, methods=['POST'], permission_classes=[AllowAny]) + def login(self, request): + username = request.data.get('username') + password = request.data.get('password') + user = authenticate(username=username, password=password) + if user: + login(request, user) + return Response({'message': 'Login successful'}, status=status.HTTP_200_OK) + else: + return Response({'message': 'Invalid credentials'}, status=status.HTTP_401_UNAUTHORIZED) + + @action(detail=False, methods=['POST']) + def logout(self, request): + logout(request) + return Response({'message': 'Logout successful'}, status=status.HTTP_200_OK) + + @action(detail=False, methods=['POST'], permission_classes=[AllowAny]) + def signup(self, request): + username = request.data.get('username') + password = request.data.get('password') + if not User.objects.filter(username=username).exists(): + user = User.objects.create_user(username=username, password=password) + login(request, user) + return Response({'message': 'Signup successful'}, status=status.HTTP_201_CREATED) + else: + return Response({'message': 'Username already exists'}, status=status.HTTP_400_BAD_REQUEST) diff --git a/api/masteriqapp/views/IQView.py b/api/masteriqapp/views/IQView.py index f72b87c..a01bf00 100644 --- a/api/masteriqapp/views/IQView.py +++ b/api/masteriqapp/views/IQView.py @@ -8,6 +8,7 @@ from django.apps import apps from rest_framework import status from rest_framework.response import Response +from django.contrib.auth.decorators import login_required masteriq = apps.get_app_config("masteriqapp") @@ -27,16 +28,16 @@ def category_image(self, request, pk): @action(detail=False, methods=["GET"], url_path="iq") def category_with_iq(self, request): - #TODO: RESTRICT TO CONNECTED USER + # TODO: RESTRICT TO CONNECTED USER answer_dict = {} for category in self.queryset: cat_dict = { "category_name": category.name, - "user_iq": 100 #TODO: REPLACE WITH USER IQ + "user_iq": 100 # TODO: REPLACE WITH USER IQ } answer_dict[category.id] = cat_dict return Response(status=status.HTTP_200_OK, data=answer_dict) @action(detail=True, methods=["GET"]) def user_iq(self, request, pk): - return Response(status=status.HTTP_200_OK, data={"user_iq":random.randint(1,200)}) \ No newline at end of file + return Response(status=status.HTTP_200_OK, data={"user_iq": random.randint(1, 200)}) diff --git a/api/masteriqapp/views/__init__.py b/api/masteriqapp/views/__init__.py index 69ea03e..953cce9 100644 --- a/api/masteriqapp/views/__init__.py +++ b/api/masteriqapp/views/__init__.py @@ -1,3 +1,4 @@ from .IQView import IQView from .QuestionView import QuestionView from .RankView import RankView +from .AuthenticationView import AuthenticationView diff --git a/frontend/src/views/LoginView.vue b/frontend/src/views/Authentication/LoginView.vue similarity index 100% rename from frontend/src/views/LoginView.vue rename to frontend/src/views/Authentication/LoginView.vue diff --git a/frontend/src/views/Authentication/LogoutView.vue b/frontend/src/views/Authentication/LogoutView.vue new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/views/Authentication/RegisterView.vue b/frontend/src/views/Authentication/RegisterView.vue new file mode 100644 index 0000000..7aaa817 --- /dev/null +++ b/frontend/src/views/Authentication/RegisterView.vue @@ -0,0 +1,36 @@ + + + diff --git a/frontend/src/views/RegisterView.vue b/frontend/src/views/RegisterView.vue deleted file mode 100644 index 951d01e..0000000 --- a/frontend/src/views/RegisterView.vue +++ /dev/null @@ -1,5 +0,0 @@ - \ No newline at end of file From 20b51687ea42892dad74087c748b3ced2db9d9d7 Mon Sep 17 00:00:00 2001 From: Alessio Comi Date: Fri, 5 Apr 2024 15:08:35 +0200 Subject: [PATCH 05/34] preparing folder authentication for authentication views and adapting router index.js --- frontend/src/router/index.js | 15 +++++--- .../src/views/Authentication/RegisterView.vue | 36 ------------------- .../src/views/Authentication/SignUpView.vue | 0 3 files changed, 10 insertions(+), 41 deletions(-) delete mode 100644 frontend/src/views/Authentication/RegisterView.vue create mode 100644 frontend/src/views/Authentication/SignUpView.vue diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index e4de527..c51e197 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -20,14 +20,19 @@ const router = createRouter({ component: () => import('../views/AddQuestionView.vue') }, { - path: '/login', + path: 'Authentication/login', name: 'Login', - component: () => import('../views/LoginView.vue') + component: () => import('../views/Authentication/LoginView.vue') }, { - path: '/register', - name: 'Register', - component: () => import('../views/RegisterView.vue') + path: 'Authentication/logout', + name: 'Logout', + component: () => import('../views/Authentication/LogoutView.vue') + }, + { + path: 'Authentication/Signup', + name: 'Signup', + component: () => import('../views/Authentication/SignUpView.vue') } ] }) diff --git a/frontend/src/views/Authentication/RegisterView.vue b/frontend/src/views/Authentication/RegisterView.vue deleted file mode 100644 index 7aaa817..0000000 --- a/frontend/src/views/Authentication/RegisterView.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/frontend/src/views/Authentication/SignUpView.vue b/frontend/src/views/Authentication/SignUpView.vue new file mode 100644 index 0000000..e69de29 From 15866cd97492d097263d229941fe12eb6bca38c7 Mon Sep 17 00:00:00 2001 From: Strogator <102219695+Strogator@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:19:53 +0200 Subject: [PATCH 06/34] my bad (#77) --- frontend/src/views/Authentication/LogoutView.vue | 3 +++ frontend/src/views/Authentication/SignUpView.vue | 3 +++ 2 files changed, 6 insertions(+) diff --git a/frontend/src/views/Authentication/LogoutView.vue b/frontend/src/views/Authentication/LogoutView.vue index e69de29..956dc09 100644 --- a/frontend/src/views/Authentication/LogoutView.vue +++ b/frontend/src/views/Authentication/LogoutView.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/frontend/src/views/Authentication/SignUpView.vue b/frontend/src/views/Authentication/SignUpView.vue index e69de29..08d003c 100644 --- a/frontend/src/views/Authentication/SignUpView.vue +++ b/frontend/src/views/Authentication/SignUpView.vue @@ -0,0 +1,3 @@ + \ No newline at end of file From be448620f8e07450c316adb42407195f91566b08 Mon Sep 17 00:00:00 2001 From: Plumey Simon Date: Tue, 9 Apr 2024 13:40:52 +0200 Subject: [PATCH 07/34] Creating apiclient for fetching data --- frontend/src/api_client.js | 20 ++++++++++++++++++++ frontend/src/main.js | 5 ----- frontend/src/views/HomeView.vue | 14 +++----------- 3 files changed, 23 insertions(+), 16 deletions(-) create mode 100644 frontend/src/api_client.js diff --git a/frontend/src/api_client.js b/frontend/src/api_client.js new file mode 100644 index 0000000..0a775d6 --- /dev/null +++ b/frontend/src/api_client.js @@ -0,0 +1,20 @@ +import axios from 'axios'; + +// set the default base url for axios requests +const API_SERVER = import.meta.env.VITE_API_SERVER; +axios.defaults.baseURL = API_SERVER; +axios.defaults.withCredentials = true; + +export default +class APIClient { + /** + * Get all the categories with current IQ in each category + * (keys are category id) + * @returns + */ + static async getCategories() + { + const response = await axios.get(`/api/category/iq/`); + return response.data; + } +} \ No newline at end of file diff --git a/frontend/src/main.js b/frontend/src/main.js index 422f8f5..5a5dbdb 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -3,11 +3,6 @@ import './assets/main.css' import { createApp } from 'vue' import App from './App.vue' import router from './router' -import axios from 'axios' - -const API_SERVER = import.meta.env.VITE_API_SERVER; -axios.defaults.baseURL = API_SERVER; -axios.defaults.withCredentials = true; const app = createApp(App) diff --git a/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue index 3b6268b..2101ad6 100644 --- a/frontend/src/views/HomeView.vue +++ b/frontend/src/views/HomeView.vue @@ -1,21 +1,13 @@ From c6c2345b4f2b47afe2c3b60663e9790c6e133d1b Mon Sep 17 00:00:00 2001 From: Plumey Simon Date: Tue, 9 Apr 2024 14:07:04 +0200 Subject: [PATCH 08/34] Fixing routes --- frontend/src/router/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index c51e197..ee9531b 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -20,17 +20,17 @@ const router = createRouter({ component: () => import('../views/AddQuestionView.vue') }, { - path: 'Authentication/login', + path: '/login', name: 'Login', component: () => import('../views/Authentication/LoginView.vue') }, { - path: 'Authentication/logout', + path: '/logout', name: 'Logout', component: () => import('../views/Authentication/LogoutView.vue') }, { - path: 'Authentication/Signup', + path: '/signup', name: 'Signup', component: () => import('../views/Authentication/SignUpView.vue') } From a867d67a3dd1c9a22035e0a45304931112a7c42c Mon Sep 17 00:00:00 2001 From: Plumey Simon Date: Tue, 9 Apr 2024 14:07:04 +0200 Subject: [PATCH 09/34] Fixing routes --- frontend/src/router/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index c51e197..ee9531b 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -20,17 +20,17 @@ const router = createRouter({ component: () => import('../views/AddQuestionView.vue') }, { - path: 'Authentication/login', + path: '/login', name: 'Login', component: () => import('../views/Authentication/LoginView.vue') }, { - path: 'Authentication/logout', + path: '/logout', name: 'Logout', component: () => import('../views/Authentication/LogoutView.vue') }, { - path: 'Authentication/Signup', + path: '/signup', name: 'Signup', component: () => import('../views/Authentication/SignUpView.vue') } From 848575d9ecc3b3b8c6a18bbc8a727eee30ef7192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=BChler=20Ma=C3=ABlys?= Date: Tue, 9 Apr 2024 14:40:13 +0200 Subject: [PATCH 10/34] return false if no question --- api/masteriqapp/views/QuestionView.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/masteriqapp/views/QuestionView.py b/api/masteriqapp/views/QuestionView.py index d922395..b8aaa15 100644 --- a/api/masteriqapp/views/QuestionView.py +++ b/api/masteriqapp/views/QuestionView.py @@ -132,6 +132,7 @@ def answer_options(self, request): @action(detail=False, methods=["GET"]) def options_asked(self, request): if not 'question' in request.session or not 'options_asked' in request.session: - return Response(status=449, data={"error": "No question being answered at the moment"}) - data_to_send = {"options_asked": request.session['options_asked']} + data_to_send = {"options_asked": False} + else: + data_to_send = {"options_asked": request.session['options_asked']} return Response(status=status.HTTP_200_OK, data=data_to_send) From cf13415eb5df181067022eaec2a95ef68c57d01b Mon Sep 17 00:00:00 2001 From: Plumey Simon Date: Tue, 9 Apr 2024 16:05:52 +0200 Subject: [PATCH 11/34] Fixing bug after refresh --- frontend/src/components/AnswerForm.vue | 38 ++++++++++---------------- frontend/src/views/QuizView.vue | 13 +++++---- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/frontend/src/components/AnswerForm.vue b/frontend/src/components/AnswerForm.vue index 645eb7a..7e0fd9c 100644 --- a/frontend/src/components/AnswerForm.vue +++ b/frontend/src/components/AnswerForm.vue @@ -1,11 +1,6 @@ diff --git a/frontend/src/views/QuizView.vue b/frontend/src/views/QuizView.vue index 461ac9d..a6c81ac 100644 --- a/frontend/src/views/QuizView.vue +++ b/frontend/src/views/QuizView.vue @@ -10,13 +10,16 @@ const id_category = route.params.id_category; // variables specific to this component const question = ref(null); +const hasAskedOptions = ref(false); const fetchNewQuestion = async () => { - console.log("fetch new question"); - const response = await axios.get(`/api/question/${id_category}/new`, { + const responseQuestion = await axios.get(`/api/question/${id_category}/new`, { }); - console.log("response to new question"); - question.value = response.data.text; + question.value = responseQuestion.data.text; + + // wait for the question before checking if the user has asked for options + const responseOptionAsked = await axios.get(`/api/question/options_asked`); + hasAskedOptions.value = !!responseOptionAsked.data.options_asked; } onMounted(() => { @@ -30,7 +33,7 @@ onMounted(() => {

Answer correctly to the question and earn as many IQs as possible!

Question

{{ question }}

- + From f743582fa7ab67e7339b5ae9f2508ce7dc845410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=BChler=20Ma=C3=ABlys?= Date: Tue, 9 Apr 2024 16:36:39 +0200 Subject: [PATCH 12/34] use if to check for yes/right/true and no/wrong/false --- api/masteriqapp/views/QuestionView.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/api/masteriqapp/views/QuestionView.py b/api/masteriqapp/views/QuestionView.py index b8aaa15..046c0bd 100644 --- a/api/masteriqapp/views/QuestionView.py +++ b/api/masteriqapp/views/QuestionView.py @@ -15,6 +15,16 @@ masteriq = apps.get_app_config("masteriqapp") +def check_if_text_answer_is_correct(given_answer, right_answer): + if (right_answer.lower() == "yes" or right_answer.lower() == "true" or right_answer.lower() == "right") and (given_answer.lower() == "yes" or given_answer.lower() == "true" or given_answer.lower() == "right") : + return True + if (right_answer.lower() == "no" or right_answer.lower() == "wrong" or right_answer.lower() == "false") and (given_answer.lower() == "no" or given_answer.lower() == "wrong" or given_answer.lower() == "false") : + return True + if given_answer.lower() == right_answer.lower(): + return True + return False + + class QuestionView(viewsets.ViewSet): category_model = masteriq.get_model("Category") question_model = masteriq.get_model("Question") @@ -96,9 +106,7 @@ def answer_text(self, request): "answer with options"}) question = self.question_model.objects.get(pk=request.session['question']) right_answer = question.options.get(is_correct=True) - user_is_correct = False - if request.data['answer'].lower() == right_answer.text.lower(): - user_is_correct = True + user_is_correct = check_if_text_answer_is_correct(request.data['answer'], right_answer.text) data_to_send = {"user_is_correct": user_is_correct, "right_answer": right_answer.text, "answer_sent": request.data['answer']} del request.session['question'] @@ -136,3 +144,5 @@ def options_asked(self, request): else: data_to_send = {"options_asked": request.session['options_asked']} return Response(status=status.HTTP_200_OK, data=data_to_send) + + From 60420d65054d0de3b44673e7e7485d4388284ba0 Mon Sep 17 00:00:00 2001 From: Plumey Simon Date: Tue, 9 Apr 2024 16:51:49 +0200 Subject: [PATCH 13/34] Removing unsed component --- frontend/src/components/HelloWorld.vue | 44 ------------- frontend/src/components/TheWelcome.vue | 88 ------------------------- frontend/src/components/WelcomeItem.vue | 86 ------------------------ 3 files changed, 218 deletions(-) delete mode 100644 frontend/src/components/HelloWorld.vue delete mode 100644 frontend/src/components/TheWelcome.vue delete mode 100644 frontend/src/components/WelcomeItem.vue diff --git a/frontend/src/components/HelloWorld.vue b/frontend/src/components/HelloWorld.vue deleted file mode 100644 index 5fb372c..0000000 --- a/frontend/src/components/HelloWorld.vue +++ /dev/null @@ -1,44 +0,0 @@ - - - - - diff --git a/frontend/src/components/TheWelcome.vue b/frontend/src/components/TheWelcome.vue deleted file mode 100644 index dab9536..0000000 --- a/frontend/src/components/TheWelcome.vue +++ /dev/null @@ -1,88 +0,0 @@ - - - diff --git a/frontend/src/components/WelcomeItem.vue b/frontend/src/components/WelcomeItem.vue deleted file mode 100644 index ac366d0..0000000 --- a/frontend/src/components/WelcomeItem.vue +++ /dev/null @@ -1,86 +0,0 @@ - - - From d35be412ee68c4960eedaa4c534494251cf5b334 Mon Sep 17 00:00:00 2001 From: Plumey Simon Date: Tue, 9 Apr 2024 16:58:31 +0200 Subject: [PATCH 14/34] Using APIClient to fetch data from backend --- frontend/src/api_client.js | 121 ++++++++++++++++++++++- frontend/src/components/AnswerForm.vue | 19 ++-- frontend/src/components/CategoryItem.vue | 26 +---- frontend/src/components/CustomInput.vue | 2 +- frontend/src/components/LeaderBoard.vue | 28 ++---- frontend/src/views/QuizView.vue | 10 +- 6 files changed, 143 insertions(+), 63 deletions(-) diff --git a/frontend/src/api_client.js b/frontend/src/api_client.js index 0a775d6..03ed6c7 100644 --- a/frontend/src/api_client.js +++ b/frontend/src/api_client.js @@ -6,15 +6,128 @@ axios.defaults.baseURL = API_SERVER; axios.defaults.withCredentials = true; export default -class APIClient { + class APIClient { /** * Get all the categories with current IQ in each category * (keys are category id) - * @returns + * @returns {Array} {category_id: {category_name: String, user_iq: Number}} */ - static async getCategories() - { + static async getCategories() { const response = await axios.get(`/api/category/iq/`); return response.data; } + + /** + * Get a new question for a given category + * @param {Number} category_id + * @returns {String} question text + */ + static async getNewQuestion(category_id) { + const response = await axios.get(`/api/question/${category_id}/new`); + return response.data.text; + } + + /** + * Get if the user has already asked for options + * @returns {Boolean} true if options have been asked, false otherwise + */ + static async getIfOptionsAsked() { + const response = await axios.get(`/api/question/options_asked`); + return !!response.data.options_asked; + } + + /** + * Get the options for the current question + * @returns {Object} {"id_option": "text_option"} + */ + static async getOptions() { + const response = await axios.get(`/api/question/options`); + return response.data.options; + } + + /** + * Return the image for a given category id + * @param {Number} category_id + * @returns {String} base64 image {data:image/jpeg;base64, ...} + */ + static async getImageCategory(category_id) { + const arrayBufferToBase64 = (buffer) => { + let binary = ''; + const bytes = new Uint8Array(buffer); + const len = bytes.byteLength; + for (let i = 0; i < len; i++) { + binary += String.fromCharCode(bytes[i]); + } + return btoa(binary); + } + + const response = await axios.get(`/api/category/${category_id}/image/`, + { + responseType: 'arraybuffer' + }); + return 'data:image/jpeg;base64,' + arrayBufferToBase64(response.data); + } + + /** + * Get the global leaderboard. It's the best players average IQ in all categories + * @returns {Array} [{user_id: Number, user_name: String, user_score: Number}] + */ + static async getGlobalLeaderboard() + { + const response = await axios.get(`/api/rank/global_leaderboard/`); + return response.data; + } + /** + * Get the global leaderboard specific to a category. It's the players with the best IQ in this category id + * @returns {Array} [{user_id: Number, user_name: String, user_score: Number}] + */ + static async getCategoryLeaderboard(category_id) + { + const response = await axios.get(`/api/rank/${category_id}/leaderboard/`); + return response.data; + } + + /** + * Get the global user rank based on average IQ in all categories of the connected player + * @returns {Object} {user_rank: Number, user_score: Number} + */ + static async getGlobalUserRank() + { + const response = await axios.get(`/api/rank/global_user/`); + return response.data; + } + + /** + * Get the user rank specific to a category. + * @returns {Object} {user_rank: Number, user_score: Number} + */ + static async getCategoryUserRank(category_id) + { + const response = await axios.get(`/api/rank/${category_id}/user/`); + return response.data; + } + + /** + * Post the answer to the question as a text + * @param {String} answer_text + * @returns {Object} {user_is_correct: Boolean, right_answer: String, answer_sent: String} + */ + static async postAnswerText(answer_text) { + const response = await axios.post(`/api/question/answer_text/`, { + answer: answer_text, + }); + return response.data; + } + + /** + * Post the answer to the question as an options + * @param {String} option_id + * @returns {Object} {user_is_correct: Boolean, right_answer: String, answer_sent: String} + */ + static async postAnswerOption(option_id) { + const response = await axios.post(`/api/question/answer_option/`, { + answer: option_id, + }); + return response.data; + } } \ No newline at end of file diff --git a/frontend/src/components/AnswerForm.vue b/frontend/src/components/AnswerForm.vue index 7e0fd9c..4758489 100644 --- a/frontend/src/components/AnswerForm.vue +++ b/frontend/src/components/AnswerForm.vue @@ -1,5 +1,5 @@