diff --git a/src/main/java/com/alterdekim/game/controller/APIController.java b/src/main/java/com/alterdekim/game/controller/APIController.java index 7cd4892..16a05a1 100644 --- a/src/main/java/com/alterdekim/game/controller/APIController.java +++ b/src/main/java/com/alterdekim/game/controller/APIController.java @@ -147,6 +147,15 @@ public class APIController { return ResponseEntity.badRequest().build(); } + @PostMapping("/api/v1/friends/remove/") + public ResponseEntity removeFriend( @RequestParam("friend_id") Long friend_id ) { + if( userService.findById(friend_id) == null ) return ResponseEntity.badRequest().build(); + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + Long userId = userService.findByUsername(((org.springframework.security.core.userdetails.User) auth.getPrincipal()).getUsername()).getId(); + friendService.removeFriend(userId, friend_id); + return ResponseEntity.ok().build(); + } + @PostMapping("/async/notify/get/") @ResponseBody public DeferredResult getNotify(@RequestParam("last_chat_id") Long last_chat_id, diff --git a/src/main/java/com/alterdekim/game/controller/AuthController.java b/src/main/java/com/alterdekim/game/controller/AuthController.java index 9f8fc39..0a39f39 100644 --- a/src/main/java/com/alterdekim/game/controller/AuthController.java +++ b/src/main/java/com/alterdekim/game/controller/AuthController.java @@ -1,14 +1,21 @@ package com.alterdekim.game.controller; +import com.alterdekim.game.dto.FriendPageResult; import com.alterdekim.game.dto.UserDTO; import com.alterdekim.game.entities.Invite; import com.alterdekim.game.entities.User; import com.alterdekim.game.service.InviteService; +import com.alterdekim.game.service.InviteServiceImpl; import com.alterdekim.game.service.UserService; +import com.alterdekim.game.service.UserServiceImpl; +import com.alterdekim.game.util.AuthenticationUtil; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -23,27 +30,22 @@ public class AuthController { private final String base_title = " | Nosedive"; - private final UserService userService; - private final InviteService inviteService; + @Autowired + private UserServiceImpl userService; - public AuthController(UserService userService, InviteService inviteService) { - this.inviteService = inviteService; - this.userService = userService; - } - - @GetMapping("/game") - public String gamePage(Model model) { - return "game"; - } + @Autowired + private InviteServiceImpl inviteService; @GetMapping("/login") public String loginPage(Model model) { + AuthenticationUtil.authProfile(model, userService); model.addAttribute("title", "Login" + base_title); return "login"; } @GetMapping("/signup") public String showRegistrationForm(Model model) { + AuthenticationUtil.authProfile(model, userService); UserDTO userDto = new UserDTO(); model.addAttribute("user", userDto); return "signup"; diff --git a/src/main/java/com/alterdekim/game/controller/StaticController.java b/src/main/java/com/alterdekim/game/controller/StaticController.java index 041244d..42de855 100644 --- a/src/main/java/com/alterdekim/game/controller/StaticController.java +++ b/src/main/java/com/alterdekim/game/controller/StaticController.java @@ -1,8 +1,11 @@ package com.alterdekim.game.controller; import com.alterdekim.game.dto.AuthApiObject; +import com.alterdekim.game.dto.FriendPageResult; import com.alterdekim.game.entities.User; +import com.alterdekim.game.service.FriendServiceImpl; import com.alterdekim.game.service.UserServiceImpl; +import com.alterdekim.game.util.AuthenticationUtil; import com.alterdekim.game.util.Hash; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -19,32 +22,56 @@ public class StaticController { @Autowired private UserServiceImpl userService; + @Autowired + private FriendServiceImpl friendService; + @GetMapping("/rules") public String rulesPage(Model model) { + AuthenticationUtil.authProfile(model, userService); return "rules"; } + @GetMapping("/game") + public String gamePage(Model model) { + return "game"; + } + @GetMapping("/games") public String gamesPage(Model model) { try { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - User u = userService.findByUsername(((org.springframework.security.core.userdetails.User) authentication.getPrincipal()).getUsername()); - Long userId = u.getId(); + User u = AuthenticationUtil.authProfile(model, userService); String apiKey = Hash.sha256((u.getId() + u.getUsername() + u.getPassword()).getBytes()); - model.addAttribute("auth_obj", new AuthApiObject(apiKey, userId, Hash.rnd())); + model.addAttribute("auth_obj", new AuthApiObject(apiKey, u.getId(), Hash.rnd())); } catch ( Exception e ) { log.error(e.getMessage(), e); } return "games"; } + @GetMapping("/friends") + public String friendsPage(Model model) { + Long userId = AuthenticationUtil.authProfile(model, userService).getId(); + model.addAttribute("friends", friendService.getFriendsOfUserId(userId).stream() + .map(l -> userService.findById(l)) + .map(u -> new FriendPageResult("/profile/"+u.getId(), "background-image: url("https://i.dogecdn.wtf/wxEpEiovduvcXadQ");", u.getUsername(), u.getId()))); + return "friends"; + } + + @GetMapping("/settings") + public String settingsPage(Model model) { + Long userId = AuthenticationUtil.authProfile(model, userService).getId(); + return "settings"; + } + @GetMapping("/") public String homePage(Model model) { + AuthenticationUtil.authProfile(model, userService); return "index"; } @GetMapping("/access-denied") public String accessDenied(Model model) { + AuthenticationUtil.authProfile(model, userService); model.addAttribute("title", "Access denied"); return "access-denied"; } diff --git a/src/main/java/com/alterdekim/game/dto/FriendPageResult.java b/src/main/java/com/alterdekim/game/dto/FriendPageResult.java new file mode 100644 index 0000000..8899c52 --- /dev/null +++ b/src/main/java/com/alterdekim/game/dto/FriendPageResult.java @@ -0,0 +1,15 @@ +package com.alterdekim.game.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class FriendPageResult { + private String href; + private String avatar; + private String username; + private Long id; +} diff --git a/src/main/java/com/alterdekim/game/repository/FriendRepository.java b/src/main/java/com/alterdekim/game/repository/FriendRepository.java index bbd381c..7ce8c99 100644 --- a/src/main/java/com/alterdekim/game/repository/FriendRepository.java +++ b/src/main/java/com/alterdekim/game/repository/FriendRepository.java @@ -3,9 +3,11 @@ package com.alterdekim.game.repository; import com.alterdekim.game.entities.FriendStatus; import com.alterdekim.game.entities.Room; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -13,4 +15,9 @@ import java.util.List; public interface FriendRepository extends JpaRepository { @Query(value = "SELECT IF(f.firstUserId = :userId, f.secondUserId, f.firstUserId) FROM FriendStatus f WHERE (f.firstUserId = :userId OR f.secondUserId = :userId) AND f.status = 2") List getFriendsOfUserId(@Param("userId") Long userId); + + @Transactional + @Modifying + @Query(value = "DELETE FROM FriendStatus f WHERE ((f.firstUserId = :userId AND f.secondUserId = :friendId) OR (f.firstUserId = :friendId AND f.secondUserId = :userId)) AND f.status = 2") + void removeFriend(@Param("userId") Long userId, @Param("friendId") Long friendId); } \ No newline at end of file diff --git a/src/main/java/com/alterdekim/game/security/SpringSecurity.java b/src/main/java/com/alterdekim/game/security/SpringSecurity.java index 629fc4a..09f490a 100644 --- a/src/main/java/com/alterdekim/game/security/SpringSecurity.java +++ b/src/main/java/com/alterdekim/game/security/SpringSecurity.java @@ -39,6 +39,8 @@ public class SpringSecurity { .requestMatchers("/games").hasAnyAuthority("ROLE_ADMIN") .requestMatchers("/profile/**").hasAnyAuthority("ROLE_ADMIN") .requestMatchers("/api/**").hasAnyAuthority("ROLE_ADMIN") + .requestMatchers("/friends").hasAnyAuthority("ROLE_ADMIN") + .requestMatchers("/settings").hasAnyAuthority("ROLE_ADMIN") .requestMatchers("/static/**").permitAll() .requestMatchers("/access-denied").permitAll() .requestMatchers("/signup").permitAll() diff --git a/src/main/java/com/alterdekim/game/service/FriendServiceImpl.java b/src/main/java/com/alterdekim/game/service/FriendServiceImpl.java index d1a0cd5..ba56172 100644 --- a/src/main/java/com/alterdekim/game/service/FriendServiceImpl.java +++ b/src/main/java/com/alterdekim/game/service/FriendServiceImpl.java @@ -14,4 +14,8 @@ public class FriendServiceImpl { public List getFriendsOfUserId(Long userId) { return repository.getFriendsOfUserId(userId); } + + public void removeFriend(Long userId, Long friendId) { + repository.removeFriend(userId, friendId); + } } diff --git a/src/main/java/com/alterdekim/game/util/AuthenticationUtil.java b/src/main/java/com/alterdekim/game/util/AuthenticationUtil.java new file mode 100644 index 0000000..f6eb2b7 --- /dev/null +++ b/src/main/java/com/alterdekim/game/util/AuthenticationUtil.java @@ -0,0 +1,26 @@ +package com.alterdekim.game.util; + +import com.alterdekim.game.dto.FriendPageResult; +import com.alterdekim.game.entities.User; +import com.alterdekim.game.service.UserServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.ui.Model; + +@Slf4j +public class AuthenticationUtil { + public static User authProfile(Model model, UserServiceImpl userService) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if( authentication.isAuthenticated() ) { + try { + User u = userService.findByUsername(((org.springframework.security.core.userdetails.User) authentication.getPrincipal()).getUsername()); + model.addAttribute("profile", new FriendPageResult("/profile/" + u.getId(), "", u.getUsername(), u.getId())); + return u; + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + return null; + } +} diff --git a/src/main/resources/static/css/friends.css b/src/main/resources/static/css/friends.css new file mode 100644 index 0000000..874a6ff --- /dev/null +++ b/src/main/resources/static/css/friends.css @@ -0,0 +1,60 @@ +.block { + display: block; + border-bottom: 2px solid var(--dive-shadow-second); + border-radius: 5px; + padding-top: .1px; + padding-bottom: .1px; + width: 100%; + background-color: var(--dive-white); + max-width: 1000px; + min-height: 30vh; +} + +.block-content { + justify-content: center; + display: flex; + margin-bottom: 15px; +} + +h2 { + margin-top: 0.5rem; + margin-left: 0.5rem; +} + +.friends-list-one-info-actions > button { + margin-top: 5px; +} + +.friends-list { + display: inline-block; +} + +.friends-list-one { + float: left; + width: 320px; + height: 95px; + padding-top: 10px; + padding-bottom: 10px; +} + +.friends-list-one-avatar { + float: left; + width: 75px; + height: 75px; + border-radius: 3px; + background-size: cover; + background-position: center; +} + +.friends-list-one-info { + float: left; + padding-left: 15px; + width: 240px; +} + +.friends-list-one-info-nick { + height: 25px; + font-weight: 300; + font-size: 21px; + line-height: 25px; +} \ No newline at end of file diff --git a/src/main/resources/static/css/settings.css b/src/main/resources/static/css/settings.css new file mode 100644 index 0000000..dd13c14 --- /dev/null +++ b/src/main/resources/static/css/settings.css @@ -0,0 +1,69 @@ +.container { + width: 1000px; +} + +.grid { + display: grid !important; + grid-template-columns: repeat(12,1fr); + grid-column-gap: 25px; +} + +.g-col-8 { + grid-column-end: span 8; + min-width: 0; +} + +.g-col-4 { + grid-column-end: span 4; + min-width: 0; +} + +.block { + display: block; + border-bottom: 2px solid var(--dive-shadow-second); + border-radius: 5px; + padding-top: 0.1px; + padding-bottom: 0.1px; + width: 100%; + min-height: 1px; + background-color: var(--dive-white); +} + +.title { + margin-bottom: 15px; + font-size: 18px; + margin-top: 20px; + margin-right: 20px; + margin-left: 20px; +} + +.block-content { + justify-content: center; + display: flex; + margin-bottom: 15px; +} + +.text-glowing { + color: var(--dive-primary-color) !important; +} + +.profile-img { + width: 6.9rem; + height: 6.9rem; + border-radius: 50%; +} + +.menu-item { + color: var(--dive-dark-grey-second); + display: flex; + align-items: center; + padding: 5px 20px; + height: 38px; + cursor: pointer; + font-size: 1.1rem; + text-decoration: none; +} + +.menu-item._selected { + background-color: var(--dive-primary-color-trans); +} \ No newline at end of file diff --git a/src/main/resources/static/javascript/friends.js b/src/main/resources/static/javascript/friends.js new file mode 100644 index 0000000..991a248 --- /dev/null +++ b/src/main/resources/static/javascript/friends.js @@ -0,0 +1,20 @@ +$(document).ready(function() { + $(".friends-list-one").hover(function() { + $(this).find(".friends-list-one-info").find(".friends-list-one-info-actions").css("display", ""); + }, function() { + $(this).find(".friends-list-one-info").find(".friends-list-one-info-actions").css("display", "none"); + }); +}); + +function removeFriend(obj) { + let friend_id = $(obj).attr("data-friend-id"); + $.ajax({ + url: "/api/v1/friends/remove/", + method: "POST", + data: { + friend_id: friend_id + } + }).done(function() { + $(obj).parent().parent().parent().remove(); + }); +} \ No newline at end of file diff --git a/src/main/resources/static/javascript/games.js b/src/main/resources/static/javascript/games.js index 1daa4d0..3ba6d0a 100644 --- a/src/main/resources/static/javascript/games.js +++ b/src/main/resources/static/javascript/games.js @@ -151,7 +151,7 @@ function successPolling(data) { } } fids.push({id: friend.id, username: friend.username}); - let fr_html = '
'+friend.username+'
'; + let fr_html = '
'+friend.username+'
'; $(".friends-online-list").append(fr_html); } else if( friend.action == 'REMOVE' ) { for( let u = 0; u < fids.length; u++ ) { diff --git a/src/main/resources/templates/fragments/navbar.html b/src/main/resources/templates/fragments/navbar.html index 4bfb625..7ccb1c3 100644 --- a/src/main/resources/templates/fragments/navbar.html +++ b/src/main/resources/templates/fragments/navbar.html @@ -30,13 +30,13 @@