From 2b22a8dcf40ebd1bcce3236a7df78d49c96c829e Mon Sep 17 00:00:00 2001 From: abdu <abdukiran@gmail.com> Date: Tue, 5 Nov 2024 21:57:35 +0100 Subject: [PATCH] add comments, minor adjustments --- frontend/src/components/CustomListElement.vue | 2 +- frontend/src/components/LoginPage.vue | 10 +++++++++- frontend/src/components/MainPage.vue | 19 +++++++++++++++++++ frontend/src/router/index.js | 2 ++ .../com/cloudcomputing/todo/entity/Todo.java | 2 ++ .../com/cloudcomputing/todo/entity/User.java | 2 ++ .../todo/mapper/TodoMapper.java | 2 ++ .../todo/mapper/UserMapper.java | 3 +++ .../todo/repository/UserRepository.java | 1 + .../todo/service/UserService.java | 7 +++++++ .../todo/util/CustomAuthenticator.java | 1 + 11 files changed, 49 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/CustomListElement.vue b/frontend/src/components/CustomListElement.vue index ab1f42e..32cb3ab 100644 --- a/frontend/src/components/CustomListElement.vue +++ b/frontend/src/components/CustomListElement.vue @@ -29,7 +29,7 @@ export default { <!-- Bottom-left description --> <div class="list-item-description mb-0"> - {{ description.length > 50 ? description.slice(0, 30) + '...' : description }} + {{ description.length > 50 ? description.slice(0, 50) + '...' : description }} </div> </div> </template> diff --git a/frontend/src/components/LoginPage.vue b/frontend/src/components/LoginPage.vue index 7736071..9a4c4d7 100644 --- a/frontend/src/components/LoginPage.vue +++ b/frontend/src/components/LoginPage.vue @@ -17,12 +17,15 @@ export default { } }, computed: { + // checks if sign up input fields are empty checkEmptyFieldsSignup(){ return this.user.userName === '' || this.user.password === '' || this.repeatedPassword === '' || this.user.password !== this.repeatedPassword; }, + // checks if login input fields are empty checkEmptyFieldsSignin(){ return this.user.userName === '' || this.user.password === '' }, + // checks if passwords have the same length at sign up checkPasswordSame(){ let pw = this.user.password let pw_repeated = this.repeatedPassword @@ -51,6 +54,7 @@ export default { }) }); + // showing a toast message depending on the response code if(response.status === 201){ this.$bvToast.show('account-created-toast') } else if(response.status === 409){ @@ -74,11 +78,12 @@ export default { let responseData = '' - //muss hier rein, bei status 401 wird nämlich kein json zurückgesendet und response.json() ist sonst nicht möglich + // muss hier rein, bei status 401 wird nämlich kein json zurückgesendet und response.json() ist sonst nicht möglich if(response.status === 200) { responseData = await response.json(); } + // if login was successful, neccessary attributes are set in frontends/browsers webstorage and toast is displayed if(response.status === 200){ localStorage.setItem('userId', responseData.userId) localStorage.setItem('isLoggedIn', 'true') @@ -139,6 +144,9 @@ export default { <b-toast invalid-user-password auto-hide-delay="10000" variant="danger" id="invalid-user-password" title="error"> username or password invalid </b-toast> + <b-toast auto-hide-delay="2000" variant="success" id="todo-set-complete" title="todo completed"> + + </b-toast> </b-container> </template> diff --git a/frontend/src/components/MainPage.vue b/frontend/src/components/MainPage.vue index d419a60..1da6f86 100644 --- a/frontend/src/components/MainPage.vue +++ b/frontend/src/components/MainPage.vue @@ -4,16 +4,22 @@ import CustomListElement from "@/components/CustomListElement.vue"; export default { name: "MainPage", components: {CustomListElement}, + // this method will be called once the dom has been rendered + // we use this to check for login status when the mainpage is opened created(){ + // redirect user to login page when hes not logged in if(localStorage.getItem('isLoggedIn') === false || localStorage.getItem('userId') === null){ this.$router.push({ name: 'login' }) } + // setting userId for further use and fetching all todos this.userId = localStorage.getItem('userId') this.getAllTodos() + // validating session every 60 seconds setInterval(this.validateSession, 60000) }, + // all the variables we will be using in our view data() { return { items: [], @@ -37,10 +43,13 @@ export default { todoIdForDeleteModal: '' } }, + // our methods (obviously) methods: { + // sets the id of the todoObject to be displayed in the delete modal setToDoIdForDeleteModal(todoId){ this.todoIdForDeleteModal = todoId }, + // sends fetch-request to check for session validity async validateSession(){ if(this.$route.name === 'main') { let url = "http://localhost:9876/user/validateSession" @@ -50,6 +59,7 @@ export default { credentials: 'include' }) + // if session is invalid, user will be logged out if (response.status === 401) { localStorage.removeItem("userId") localStorage.removeItem("isLoggedIn") @@ -57,10 +67,12 @@ export default { } } }, + // shows dtails of the given item showDetails(item) { this.selectedItem = item; this.showDetailsModal = true; }, + // fetches all todos for the current user async getAllTodos(){ let url = `http://localhost:9876/user/getAllTodos?userId=${localStorage.getItem('userId')}` @@ -69,12 +81,14 @@ export default { credentials: 'include', }) + // fills list with the todos if request was successful if(response.status === 200) { const items = await response.json() this.items = items.filter(item => item.completed === false) this.completedItems = items.filter(item => item.completed === true) } }, + // creates a todoJsonObject and sends it to backend for persistence async addTodo(){ let url = "http://localhost:9876/user/addTodo" @@ -92,12 +106,14 @@ export default { }) }); + // iff request was successful backend resends complete list of todos so frontend can refill the list if(response.status === 201) { const items = await response.json() this.items = items.filter(item => item.completed === false) this.completedItems = items.filter(item => item.completed === true) } }, + // deletes given todo async deleteTodo(todoId){ let url = `http://localhost:9876/user/deleteTodo?userId=${localStorage.getItem('userId')}&todoId=${todoId}` @@ -109,10 +125,12 @@ export default { credentials: 'include', }) + // if deleted successfully, we fetch all todos again if(response.status === 204) { await this.getAllTodos() } }, + // sets the given todo as complete async setTodoComplete(todoId){ let url = `http://localhost:9876/user/setTodoComplete?userId=${localStorage.getItem('userId')}&todoId=${todoId}` @@ -128,6 +146,7 @@ export default { await this.getAllTodos() } }, + // logs out the current user and resets attributes in storage async signout(){ let url = "http://localhost:9876/user/signout" diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index 42d215f..ab9f693 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -5,11 +5,13 @@ import MainPage from '../components/MainPage.vue'; Vue.use(Router); +// the routes we use in our app const routes = [ { path: '/', name: 'login', component: LoginPage }, { path: '/main', name: 'main', component: MainPage }, ] +// using history mode instead of hash mode (/#/ in url looks ugly af) const router = new Router({ mode: 'history', routes, diff --git a/src/main/java/com/cloudcomputing/todo/entity/Todo.java b/src/main/java/com/cloudcomputing/todo/entity/Todo.java index 11bf3ba..fb9cb0a 100644 --- a/src/main/java/com/cloudcomputing/todo/entity/Todo.java +++ b/src/main/java/com/cloudcomputing/todo/entity/Todo.java @@ -5,6 +5,8 @@ import lombok.Setter; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; +// todoEntity, used for object relational mapping with spring data + @Getter @Setter @Document diff --git a/src/main/java/com/cloudcomputing/todo/entity/User.java b/src/main/java/com/cloudcomputing/todo/entity/User.java index 66026dd..4935ab8 100644 --- a/src/main/java/com/cloudcomputing/todo/entity/User.java +++ b/src/main/java/com/cloudcomputing/todo/entity/User.java @@ -5,6 +5,8 @@ import lombok.Setter; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; +// user entity, used for object relational mapping with spring data + @Getter @Setter @Document(collection = "users") diff --git a/src/main/java/com/cloudcomputing/todo/mapper/TodoMapper.java b/src/main/java/com/cloudcomputing/todo/mapper/TodoMapper.java index 647f263..818e984 100644 --- a/src/main/java/com/cloudcomputing/todo/mapper/TodoMapper.java +++ b/src/main/java/com/cloudcomputing/todo/mapper/TodoMapper.java @@ -7,6 +7,7 @@ import org.springframework.stereotype.Component; @Component public class TodoMapper { + // maps entity attributes on dto public TodoDTO entityToDto(Todo todo) { TodoDTO todoDTO = new TodoDTO(); todoDTO.setTodoId(todo.getTodoId()); @@ -18,6 +19,7 @@ public class TodoMapper { return todoDTO; } + // maps dto attributes on entity public Todo dtoToEntity(TodoDTO dto){ Todo todo = new Todo(); todo.setTodoId(dto.getTodoId()); diff --git a/src/main/java/com/cloudcomputing/todo/mapper/UserMapper.java b/src/main/java/com/cloudcomputing/todo/mapper/UserMapper.java index de8e958..8f0a916 100644 --- a/src/main/java/com/cloudcomputing/todo/mapper/UserMapper.java +++ b/src/main/java/com/cloudcomputing/todo/mapper/UserMapper.java @@ -8,6 +8,7 @@ import org.springframework.stereotype.Component; @Component public class UserMapper { + // maps entity attributes to dto public UserDTO entityToDto(User user) { UserDTO userDTO = new UserDTO(); userDTO.setUserId(user.getUserId()); @@ -16,6 +17,7 @@ public class UserMapper { return userDTO; } + // maps dto attributes to entity public User dtoToEntity(UserDTO userDTO) { User user = new User(); user.setUserId(userDTO.getUserId()); @@ -30,6 +32,7 @@ public class UserMapper { * */ + //salts and hashes password by byte values public String saltAndHashPassword(String userName, String pw) { //turn username into byte-array to use as unique salt byte[] salt = userName.getBytes(); diff --git a/src/main/java/com/cloudcomputing/todo/repository/UserRepository.java b/src/main/java/com/cloudcomputing/todo/repository/UserRepository.java index c3c6cf2..612b025 100644 --- a/src/main/java/com/cloudcomputing/todo/repository/UserRepository.java +++ b/src/main/java/com/cloudcomputing/todo/repository/UserRepository.java @@ -3,6 +3,7 @@ package com.cloudcomputing.todo.repository; import com.cloudcomputing.todo.entity.User; import org.springframework.data.mongodb.repository.MongoRepository; +// spring data parses the method names and creates the according queries public interface UserRepository extends MongoRepository<User, String> { boolean existsByUserName(String userName); boolean existsByUserId(String userId); diff --git a/src/main/java/com/cloudcomputing/todo/service/UserService.java b/src/main/java/com/cloudcomputing/todo/service/UserService.java index b25dbcf..740e60c 100644 --- a/src/main/java/com/cloudcomputing/todo/service/UserService.java +++ b/src/main/java/com/cloudcomputing/todo/service/UserService.java @@ -43,6 +43,7 @@ public class UserService { public UserDTO createUser(UserDTO userDTO) { User newUser; + // creates user from userDTO if user doesnt exist yet (checked by userid + username) if (!(userRepository.existsByUserId(userDTO.getUserId()) || userRepository.existsByUserName(userDTO.getUserName()))) { newUser = userMapper.dtoToEntity(userDTO); return userMapper.entityToDto(userRepository.save(newUser)); @@ -56,6 +57,7 @@ public class UserService { * @return the userDTO with the given username */ public UserDTO getUser(UserDTO userDTO) { + // looks for user entity in db and converts it to dto return userMapper.entityToDto(userRepository.findByUserName(userDTO.getUserName())); } @@ -65,6 +67,7 @@ public class UserService { * @return boolean value which indicates if the login was successful or not */ public boolean login(HttpServletRequest request, UserDTO userDTO) { + // authenticates user (pw-hash-check) and sets the attribute "userId" of the given session if (customAuthenticator.authenticate(userDTO)) { String userId = userRepository.findByUserName(userDTO.getUserName()).getUserId(); HttpSession session = request.getSession(); @@ -81,6 +84,7 @@ public class UserService { * @return true to indicate successful logout */ public boolean logout(HttpServletRequest request, String userId) { + // checks if session exists and invalidates it HttpSession session = request.getSession(); if (session != null) { @@ -95,9 +99,12 @@ public class UserService { * @return list of todoDTOs */ public List<TodoDTO> getAllTodos(String userId) { + // finds all todos for the given userId in the db List<Todo> todoList = todoRepository.findAllByUserId(userId); List<TodoDTO> todoDTOList = new ArrayList<>(); + // iterates through the list of todos, converts them to dtos + // and adds them to a list of dtos which is returned after todoList.forEach((todoItem) -> { todoDTOList.add(todoMapper.entityToDto(todoItem)); }); diff --git a/src/main/java/com/cloudcomputing/todo/util/CustomAuthenticator.java b/src/main/java/com/cloudcomputing/todo/util/CustomAuthenticator.java index 647329d..2ec9d4d 100644 --- a/src/main/java/com/cloudcomputing/todo/util/CustomAuthenticator.java +++ b/src/main/java/com/cloudcomputing/todo/util/CustomAuthenticator.java @@ -17,6 +17,7 @@ public class CustomAuthenticator { @Autowired private UserMapper userMapper; + // checks if the given password of the user dto ( received from frontend ) has same hash as stored password-hash public boolean authenticate(UserDTO userDTO) { User user = userRepository.findByUserName(userDTO.getUserName()); String expectedHash = ""; -- GitLab