From c366e70e95156d2637f82116312770e12a9aad32 Mon Sep 17 00:00:00 2001 From: realtradam Date: Sat, 27 Jul 2024 20:20:29 -0400 Subject: implement delete functionality --- .../blog/web/controllers/ArticleController.java | 41 +++++------------ .../com/blog/web/controllers/AuthController.java | 2 +- .../main/java/com/blog/web/models/UserEntity.java | 19 ++++++-- .../com/blog/web/repository/ArticleRepository.java | 3 +- .../java/com/blog/web/security/CorsConfig.java | 1 - .../java/com/blog/web/services/ArticleService.java | 7 ++- .../blog/web/services/impl/ArticleServiceImpl.java | 52 +++++++++++----------- .../blog/web/services/impl/UserServiceImpl.java | 22 +++------ frontend/src/pages/Home.tsx | 13 ++++-- 9 files changed, 74 insertions(+), 86 deletions(-) diff --git a/backend/src/main/java/com/blog/web/controllers/ArticleController.java b/backend/src/main/java/com/blog/web/controllers/ArticleController.java index 0429084..b321cd2 100644 --- a/backend/src/main/java/com/blog/web/controllers/ArticleController.java +++ b/backend/src/main/java/com/blog/web/controllers/ArticleController.java @@ -12,7 +12,8 @@ import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; -import java.util.HashSet; +import java.util.List; +import java.util.Optional; @CrossOrigin(origins = "http://localhost:5173", allowCredentials = "true", allowedHeaders = "*") @RestController @@ -40,12 +41,12 @@ public class ArticleController { } @GetMapping("/articles") - public HashSet listArticles(@RequestParam(value = "search", required = false) String search) { - HashSet articles; - if (search != null) { - articles = articleService.searchPublicArticles(search); + public List listArticles(@RequestParam(value = "search", required = false) Optional search) { + final List articles; + if (search.isPresent()) { + articles = articleService.searchPublicArticles(search.get()); } else { - articles = new HashSet(articleService.findAllArticles()); + articles = articleService.findAllArticles(); } return articles; } @@ -53,26 +54,15 @@ public class ArticleController { @GetMapping("/article/{articleId}") public ArticlePublicDto showArticle(@PathVariable("articleId") long articleId, Model model) { ArticlePublicDto articlePublicDto = articleService.findArticlePublicById(articleId); - //model.addAttribute("article", articlePublicDto); - //UserEntity user = userService.getLoggedInUser().orElse(new UserEntity()); - //model.addAttribute("user", user); - //return "articles/show"; return articlePublicDto; } - /*@GetMapping("/articles/new") - public String createArticleForm(Model model) { - model.addAttribute("user", userService.getLoggedInUser().orElse(new UserEntity())); - model.addAttribute("article", new Article()); - return "articles/new"; - }*/ - @PostMapping("/article/new") public String saveArticle(@Valid @ModelAttribute("article") ArticleDto articleDto, BindingResult result) { // if non-authenticated in user tries to create an article // redirect them to login page - UserEntity user = userService.getLoggedInUser().orElse(null); - if (user == null) { + Optional user = userService.getLoggedInUser(); + if (user.isEmpty()) { return "redirect:/login"; } else if (!result.hasErrors()) { articleService.saveArticle(articleDto); @@ -84,18 +74,7 @@ public class ArticleController { @GetMapping("/articles/delete/{articleId}") public String deleteArticle(@PathVariable("articleId") Long articleId) { articleService.delete(articleId); - return "redirect:/articles"; - } - - @GetMapping("/articles/edit/{articleId}") - public String editArticleForm(@PathVariable("articleId") long articleId, Model model) { - UserEntity user = userService.getLoggedInUser().orElse(null); - if (user != null) { - model.addAttribute("user", user); - ArticleDto articleDto = articleService.findArticleById(articleId); - model.addAttribute("article", articleDto); - } - return "articles/edit"; + return ""; } @PostMapping("/articles/edit/{articleId}") diff --git a/backend/src/main/java/com/blog/web/controllers/AuthController.java b/backend/src/main/java/com/blog/web/controllers/AuthController.java index 4da346b..039393c 100644 --- a/backend/src/main/java/com/blog/web/controllers/AuthController.java +++ b/backend/src/main/java/com/blog/web/controllers/AuthController.java @@ -40,7 +40,7 @@ public class AuthController { @GetMapping("/profile") public UserPublicDto profile() { - final UserEntity user = userService.getLoggedInUser().orElse(null); + final UserEntity user = userService.getLoggedInUser().orElse(new UserEntity()); return new UserPublicDto(user); } } diff --git a/backend/src/main/java/com/blog/web/models/UserEntity.java b/backend/src/main/java/com/blog/web/models/UserEntity.java index bf45b21..089b8bc 100644 --- a/backend/src/main/java/com/blog/web/models/UserEntity.java +++ b/backend/src/main/java/com/blog/web/models/UserEntity.java @@ -5,7 +5,9 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; @Entity(name = "users") @@ -19,7 +21,18 @@ public class UserEntity { private String password; @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinTable(name = "user_roles", joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")}, inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")}) - private final List roles = new ArrayList<>(); + private Set roles = new HashSet<>(); + + public UserEntity(String username, String email, String password, HashSet roles) { + this.username = username; + this.email = email; + this.password = password; + setRoles(roles); + } + + public UserEntity() { + + } public boolean equals(UserEntity user) { return this.id == user.getId(); @@ -61,11 +74,11 @@ public class UserEntity { this.password = password; } - public List getRoles() { + public Set getRoles() { return roles; } - public void setRoles(List roles) { + public void setRoles(Set roles) { this.roles.clear(); this.roles.addAll(roles); } diff --git a/backend/src/main/java/com/blog/web/repository/ArticleRepository.java b/backend/src/main/java/com/blog/web/repository/ArticleRepository.java index f40eada..e48f156 100644 --- a/backend/src/main/java/com/blog/web/repository/ArticleRepository.java +++ b/backend/src/main/java/com/blog/web/repository/ArticleRepository.java @@ -5,8 +5,9 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import java.util.HashSet; +import java.util.List; public interface ArticleRepository extends JpaRepository { @Query("SELECT a from Article a WHERE a.title LIKE CONCAT('%', :search, '%')") - HashSet
searchArticles(String search); + List
searchArticles(String search); } diff --git a/backend/src/main/java/com/blog/web/security/CorsConfig.java b/backend/src/main/java/com/blog/web/security/CorsConfig.java index 55db15a..19b20f5 100644 --- a/backend/src/main/java/com/blog/web/security/CorsConfig.java +++ b/backend/src/main/java/com/blog/web/security/CorsConfig.java @@ -8,7 +8,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CorsConfig { - // Configures CORS for the application @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { diff --git a/backend/src/main/java/com/blog/web/services/ArticleService.java b/backend/src/main/java/com/blog/web/services/ArticleService.java index 1e50df0..4bf3028 100644 --- a/backend/src/main/java/com/blog/web/services/ArticleService.java +++ b/backend/src/main/java/com/blog/web/services/ArticleService.java @@ -4,7 +4,6 @@ import com.blog.web.dto.ArticleDto; import com.blog.web.dto.ArticlePublicDto; import com.blog.web.models.Article; -import java.util.HashSet; import java.util.List; import java.util.Optional; @@ -13,15 +12,15 @@ public interface ArticleService { Optional
saveArticle(ArticleDto article); - ArticleDto findArticleById(long articleId); + Optional findArticleById(long articleId); void updateArticle(ArticleDto articleDto); - boolean delete(Long articleId); + boolean delete(long articleId); //List searchArticles(String search); ArticlePublicDto findArticlePublicById(long articleId); - HashSet searchPublicArticles(String search); + List searchPublicArticles(String search); } diff --git a/backend/src/main/java/com/blog/web/services/impl/ArticleServiceImpl.java b/backend/src/main/java/com/blog/web/services/impl/ArticleServiceImpl.java index aaf1044..2f9de6c 100644 --- a/backend/src/main/java/com/blog/web/services/impl/ArticleServiceImpl.java +++ b/backend/src/main/java/com/blog/web/services/impl/ArticleServiceImpl.java @@ -12,7 +12,6 @@ import com.blog.web.services.ArticleService; import com.blog.web.services.UserService; import org.springframework.stereotype.Service; -import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -51,54 +50,55 @@ public class ArticleServiceImpl implements ArticleService { } @Override - public ArticleDto findArticleById(long articleId) { - Article article = articleRepository.findById(articleId).get(); - return mapToArticleDto(article); + public Optional findArticleById(long articleId) { + final Optional
otpArticle = articleRepository.findById(articleId); + if(otpArticle.isEmpty()) { + return Optional.empty(); + } + else { + return Optional.of(mapToArticleDto(otpArticle.get())); + } } @Override public void updateArticle(ArticleDto articleDto) { - String username = SecurityUtil.getSessionUser(); - UserEntity user = userRepository.findByUsername(username).orElse(null); + final String username = SecurityUtil.getSessionUser(); + final UserEntity user = userRepository.findByUsername(username).orElse(null); if (user == null) { return; } - Article article = mapToArticle(articleDto); + final Article article = mapToArticle(articleDto); article.setCreatedBy(user); articleRepository.save(article); } @Override - public boolean delete(Long articleId) { - final UserEntity user = userService.getLoggedInUser().orElse(null); - if (user == null) { - return false; - } - String userId = user.getUsername(); - ArticleDto article = this.findArticleById(articleId); + public boolean delete(long articleId) { + final Optional optArticle = this.findArticleById(articleId); + if(optArticle.isEmpty()) { return false; } // cant find article, give up + final ArticleDto article = optArticle.get(); String ownerId = article.getUsername(); - if (ownerId.equals(userId)) { + + final Optional optUser = userService.getLoggedInUser(); + if (optUser.isEmpty()) { return false; } // not logged in, not allowed to delete + final UserEntity user = optUser.get(); + String userId = user.getUsername(); + + if (!ownerId.equals(userId)) { return false; } // logged in a different user, not allowed to delete + else { articleRepository.deleteById(articleId); return true; - } else { - return false; } } - //@Override - //public List searchArticles(String search) { - // List
articles = articleRepository.searchArticles(search); - // return articles.stream().map(article -> mapToArticleDto(article)).collect(Collectors.toList()); - //} - @Override public ArticlePublicDto findArticlePublicById(long articleId) { return new ArticlePublicDto(articleRepository.findById(articleId).get()); } @Override - public HashSet searchPublicArticles(String search) { - HashSet
articles = articleRepository.searchArticles(search); - return articles.stream().map(article -> mapToArticlePublicDto(article)).collect(Collectors.toCollection(HashSet::new)); + public List searchPublicArticles(String search) { + List
articles = articleRepository.searchArticles(search); + return articles.stream().map(article -> mapToArticlePublicDto(article)).collect(Collectors.toList()); } } diff --git a/backend/src/main/java/com/blog/web/services/impl/UserServiceImpl.java b/backend/src/main/java/com/blog/web/services/impl/UserServiceImpl.java index 9c3eaa8..b39d15e 100644 --- a/backend/src/main/java/com/blog/web/services/impl/UserServiceImpl.java +++ b/backend/src/main/java/com/blog/web/services/impl/UserServiceImpl.java @@ -10,9 +10,7 @@ import com.blog.web.services.UserService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; +import java.util.*; @Service public class UserServiceImpl implements UserService { @@ -28,14 +26,8 @@ public class UserServiceImpl implements UserService { @Override public void saveUser(RegistrationDto registrationDto) { - UserEntity user = new UserEntity(); - user.setUsername(registrationDto.getUsername()); - user.setEmail(registrationDto.getEmail()); - user.setPassword(passwordEncoder.encode(registrationDto.getPassword())); - - final Role role = roleRepository.findByName("User").orElse(new Role()); - user.setRoles(List.of(role)); - userRepository.save(user); + final HashSet roles = (HashSet) Set.of(roleRepository.findByName("User").orElse(new Role())); + userRepository.save(new UserEntity(registrationDto.getUsername(), registrationDto.getEmail(), passwordEncoder.encode(registrationDto.getPassword()), roles)); } @Override @@ -50,11 +42,11 @@ public class UserServiceImpl implements UserService { public Optional getLoggedInUser() { final Optional user; - String username = SecurityUtil.getSessionUser(); - if (username != null) { - user = this.findByUsername(username); + Optional optUsername = Optional.ofNullable(SecurityUtil.getSessionUser()); + if(optUsername.isPresent()) { + user = this.findByUsername(optUsername.get()); } else { - user = Optional.of(new UserEntity()); + user = Optional.empty(); } return user; } diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index bada22d..71683e7 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, FormEvent } from "react"; +import { useState, useEffect, useCallback, FormEvent } from "react"; type article = { id: number; @@ -31,7 +31,7 @@ export default function Home({ }; const response = await fetch( - `${import.meta.env.VITE_API_TITLE}/api/v1/article/delete/${target.id.value}`, + `${import.meta.env.VITE_API_TITLE}/api/v1/articles/delete/${target.id.value}`, { credentials: "include", method: "get", @@ -41,10 +41,12 @@ export default function Home({ console.log(response); alert("check console for error"); } + else { + fetchArticles(); + } }; - // pull data when new search is given - useEffect(() => { + const fetchArticles = useCallback(() => { let url; if (articleSearch.value === null) { //alert("not searched"); @@ -65,6 +67,9 @@ export default function Home({ .then((response) => setArticles(response)); }, [articleSearch.value]); + // pull data when new search is given + useEffect(() => { fetchArticles(); } , [articleSearch.value, fetchArticles]); + // when new data is pulled update the articles shown useEffect(() => { setAllArticles( -- cgit v1.2.3