diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 997894c322fef088a7ff37136b44d788d0aab02e..f4cf0363869ac87d4678fca98195eadb53dbc62f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,29 +1,24 @@ +image: maven:eclipse-temurin + +before_script: + - cd FullstackProsjekt + stages: -- ".pre" -- build -- test -- deploy -- ".post" -build-job: + - build + - test + - package + +build: stage: build script: - - echo "Compiling the code..." - - echo "Compile complete." -unit-test-job: + - mvn compile + +test: stage: test script: - - echo "Running unit tests... This will take about 60 seconds." - - sleep 60 - - echo "Code coverage is 90%" -lint-test-job: - stage: test - script: - - echo "Linting code... This will take about 10 seconds." - - sleep 10 - - echo "No lint issues found." -deploy-job: - stage: deploy - environment: production + - mvn clean test + +package: + stage: package script: - - echo "Deploying application..." - - echo "Application successfully deployed." + - mvn clean package diff --git a/FullstackProsjekt/pom.xml b/FullstackProsjekt/pom.xml index 58e2066d59c09afdc60f8b039fbca4727cf89da0..f0793596aef3af99423917ffc02ed70eb820acc5 100644 --- a/FullstackProsjekt/pom.xml +++ b/FullstackProsjekt/pom.xml @@ -71,6 +71,9 @@ <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> + <configuration> + <mainClass>edu.ntnu.idatt2105.FullstackProsjektApplication</mainClass> + </configuration> </plugin> </plugins> </build> diff --git a/FullstackProsjekt/src/frontend/src/api.js b/FullstackProsjekt/src/frontend/src/api.js new file mode 100644 index 0000000000000000000000000000000000000000..79898c49cd747a39059aace068dcf4a80c862d6d --- /dev/null +++ b/FullstackProsjekt/src/frontend/src/api.js @@ -0,0 +1,6 @@ +import axios from 'axios'; + +export const apiClient = axios.create({ + baseURL: '/api', + //TODO: set api URL +}); \ No newline at end of file diff --git a/FullstackProsjekt/src/frontend/src/tokenController.js b/FullstackProsjekt/src/frontend/src/tokenController.js new file mode 100644 index 0000000000000000000000000000000000000000..6d1b4b7a7fa311f3dbc6032ce5f11c282f71dc09 --- /dev/null +++ b/FullstackProsjekt/src/frontend/src/tokenController.js @@ -0,0 +1,11 @@ +export const getToken = () => { + return localStorage.getItem('token'); +} + +export const setToken = (token) => { + localStorage.setItem('token', token); +} + +export const removeToken = () => { + localStorage.removeItem('token'); +} \ No newline at end of file diff --git a/FullstackProsjekt/src/frontend/src/views/EditQuizView.vue b/FullstackProsjekt/src/frontend/src/views/EditQuizView.vue index 064b4fd76a05ff7d631d9d043493b0eb710831f6..1878a53587c38d383e5b6a3733edd57a1f12bfae 100644 --- a/FullstackProsjekt/src/frontend/src/views/EditQuizView.vue +++ b/FullstackProsjekt/src/frontend/src/views/EditQuizView.vue @@ -2,12 +2,17 @@ import NewQuestionModel from "@/components/shared/NewQuestionModel.vue"; import {ref} from "vue"; import router from "@/router/index.js"; +import {apiClient} from "@/api.js"; +const quizId = ref(null); //TODO: set quiz id when routing here const createdQuestion = ref(null); const newAnswers = ref([]); const showNewQuestionModal = ref(false); const selectedAnswer = ref(null); +const existingQuestions = ref([]); let answerId = 1; +const errorMsg = ''; //TODO: display error to user + function createQuestion() { @@ -51,20 +56,39 @@ function answerCount() { } } -function submitQuestion() { +async function getExistingQuestions() { + try { + const response = await apiClient.get(`/quizzes/${quizId.value}/questions`); // Fetch questions for a specific quiz + existingQuestions.value = response.data; // Update existingQuestions with the fetched questions + } catch (error) { + console.error('Error fetching existing questions:', error); + // Optionally, you can handle error response here + alert('An error occurred while fetching existing questions'); + } +} + +async function submitQuestion() { + //TODO: proper error handling if(!createdQuestion.value){ alert('Question cannot be empty'); return false } - if(!validateAnswers() && !answerCount()){ + if(!validateAnswers() && !answerCount()){ alert('Fill all inputs before submitting') return false } - //Supposed to send request to backend with a finnished Question with id and such - router.post('/questions',{ - question:createdQuestion.value, - answers:newAnswers.value - }) + + try { + await apiClient.post('questions', { + //TODO: find quizID, send this too + question: createdQuestion.value, + correctAnswer: selectedAnswer.value, + answers: newAnswers.value + }); + } catch (error) { + //TODO: proper error handling + this.errorMsg = 'Error logging in'; + } } </script> diff --git a/FullstackProsjekt/src/frontend/src/views/LoginView.vue b/FullstackProsjekt/src/frontend/src/views/LoginView.vue index 3d9894d15b5d79e7c0d3e5af9dcab8edc0dc2420..84d35a53695a97c64cd793a34cea2458fd64a7cf 100644 --- a/FullstackProsjekt/src/frontend/src/views/LoginView.vue +++ b/FullstackProsjekt/src/frontend/src/views/LoginView.vue @@ -1,24 +1,32 @@ <script> -import axios from "axios"; -import Svg from "@/assets/Svg.vue"; +//import Svg from "@/assets/Svg.vue"; +import {setToken} from "@/tokenController.js"; +import {apiClient} from "@/api.js"; export default { - name: 'Login', - components: {Svg}, + //name: 'Login', + //components: {Svg}, data() { return { email: '', password: '', - showPassword: false // Add showPassword property + showPassword: false, // Add showPassword property + errorMsg: '', //TODO: display error to user } }, methods: { async handleSubmit() { - const response = await axios.post('login', { - email: this.email, - password: this.password - }); - localStorage.setItem('token', response.data.token) + try { + await apiClient.post('/login', { + email: this.email, + password: this.password + }).then(response => { + setToken(response.data.token); //TODO: check token name + }); + } catch (error) { + //TODO: proper error handling + this.errorMsg = 'Error logging in'; + } }, togglePasswordVisibility() { this.showPassword = !this.showPassword; diff --git a/FullstackProsjekt/src/frontend/src/views/OverviewQuizView.vue b/FullstackProsjekt/src/frontend/src/views/OverviewQuizView.vue index 3a402f3911526094e24f3b7633180779deba528d..b78c5f8d992fdd6dca60c3a317c0daace8fab03a 100644 --- a/FullstackProsjekt/src/frontend/src/views/OverviewQuizView.vue +++ b/FullstackProsjekt/src/frontend/src/views/OverviewQuizView.vue @@ -52,6 +52,17 @@ <script> import { defineComponent } from "vue"; import Svg from "@/assets/Svg.vue"; +import {apiClient} from "@/api.js"; +import {ref} from "vue"; +getQuizzes(); + +const quizzes = ref([]); + +async function getQuizzes() { + //TODO: try/catch + const response = await apiClient.get('/quizzes/${quizId.value}'); + quizzes.value = response.data; //TODO: create parsing method +} export default defineComponent({ components: { Svg }, @@ -84,7 +95,6 @@ export default defineComponent({ }); </script> - <style> .overViewQuestion-page{ padding: 50px; diff --git a/FullstackProsjekt/src/frontend/src/views/SignupView.vue b/FullstackProsjekt/src/frontend/src/views/SignupView.vue index 2cea418225aab581fe7fd48766b5e1a9b6d105d7..ebb9787b19be92187eaa512b236c486e742804ea 100644 --- a/FullstackProsjekt/src/frontend/src/views/SignupView.vue +++ b/FullstackProsjekt/src/frontend/src/views/SignupView.vue @@ -1,7 +1,7 @@ <script> - import Svg from '../assets/Svg.vue' - import axios from "axios"; + //import Svg from '../assets/Svg.vue' + import {apiClient} from "@/api.js"; export default { name: 'Register', data(){ @@ -10,20 +10,28 @@ last_name:'', email:'', password:'', - password_confirm:'' + password_confirm:'', + errorMsg: '', //TODO: display error to user } }, methods:{ - async handleSubmit(e) { - const response = await axios.post('signup', { - first_name: this.first_name, - last_name: this.last_name, - email: this.email, - password: this.password, - password_confirm: this.password_confirm - }); - - this.$router.push('/login') + async handleSubmit() { + //TODO: use interceptor to check matching password, send one password + try { + await apiClient.post('/api/auth/register', { + first_name: this.first_name, + last_name: this.last_name, + email: this.email, + password: this.password + //password_confirm: this.password_confirm + }).then(response => { + //TODO: display successful registration to user + this.$router.push('/login') + }); + } catch (error) { + //TODO: proper error handling + this.errorMsg = 'Error signing up'; + } } } } diff --git a/FullstackProsjekt/src/frontend/userController.js b/FullstackProsjekt/src/frontend/userController.js new file mode 100644 index 0000000000000000000000000000000000000000..0f298254e38767ec8180c7e8b1c79d2361d7e7ab --- /dev/null +++ b/FullstackProsjekt/src/frontend/userController.js @@ -0,0 +1,20 @@ +import { ref } from 'vue'; + +export const user = ref({ + userId: null, + email: null, +}); + +// Function to set user data +export function setUser(userId, userEmail) { + user.value = { + userId: userId, + email: userEmail + }; +} +export function clearUser() { + user.value = { + userId: null, + email: null, + }; +} \ No newline at end of file