Profile page, friend requests
This commit is contained in:
parent
fbcaa886c1
commit
4a67bac3d9
@ -169,6 +169,15 @@ public class APIController {
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@PostMapping("/api/v1/friends/follow")
|
||||
public ResponseEntity<String> followFriend( @RequestParam("userId") Long friendId ) {
|
||||
if( userService.findById(friendId) == 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.followUser(userId, friendId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@PostMapping("/async/notify/get/")
|
||||
@ResponseBody
|
||||
public DeferredResult<LongPollResult> getNotify(@RequestParam("last_chat_id") Long last_chat_id,
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.game.controller;
|
||||
|
||||
import com.alterdekim.game.dto.AuthApiObject;
|
||||
import com.alterdekim.game.dto.FriendPageResult;
|
||||
import com.alterdekim.game.dto.SelectOption;
|
||||
import com.alterdekim.game.entities.Image;
|
||||
import com.alterdekim.game.entities.User;
|
||||
import com.alterdekim.game.repository.ImageRepository;
|
||||
@ -16,10 +17,15 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Controller
|
||||
public class StaticController {
|
||||
@ -65,9 +71,30 @@ public class StaticController {
|
||||
return "friends";
|
||||
}
|
||||
|
||||
@GetMapping("/profile/{id}")
|
||||
public String profilePage(@PathVariable("id") Long id, Model model) {
|
||||
AuthenticationUtil.authProfile(model, userService);
|
||||
User u = userService.findById(id);
|
||||
model.addAttribute("page_user", new FriendPageResult("", "background-image: url(\"/image/store/"+u.getAvatarId()+"\");", u.getUsername(), u.getId(), u.getDisplayName()));
|
||||
return "profile";
|
||||
}
|
||||
|
||||
@GetMapping("/settings")
|
||||
public String settingsPage(Model model) {
|
||||
Long userId = AuthenticationUtil.authProfile(model, userService).getId();
|
||||
User u = AuthenticationUtil.authProfile(model, userService);
|
||||
List<SelectOption> options = new ArrayList<>();
|
||||
options.add(new SelectOption("she/her", true));
|
||||
options.add(new SelectOption("he/him", false));
|
||||
options.add(new SelectOption("they/them", false));
|
||||
options.add(new SelectOption("idc", false));
|
||||
String p = u.getPronouns();
|
||||
options = options.stream().map(o -> {
|
||||
if(p.equals(o.getText())) {
|
||||
return new SelectOption(o.getText(), true);
|
||||
}
|
||||
return new SelectOption(o.getText(), false);
|
||||
}).collect(Collectors.toList());
|
||||
model.addAttribute("options", options);
|
||||
return "settings";
|
||||
}
|
||||
|
||||
|
11
src/main/java/com/alterdekim/game/dto/SelectOption.java
Normal file
11
src/main/java/com/alterdekim/game/dto/SelectOption.java
Normal file
@ -0,0 +1,11 @@
|
||||
package com.alterdekim.game.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class SelectOption {
|
||||
private String text;
|
||||
private Boolean selected;
|
||||
}
|
@ -20,4 +20,12 @@ public interface FriendRepository extends JpaRepository<FriendStatus, Long> {
|
||||
@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);
|
||||
|
||||
@Query(value = "SELECT f FROM FriendStatus f WHERE ((f.firstUserId = :userId AND f.secondUserId = :friendId) OR (f.firstUserId = :friendId AND f.secondUserId = :userId)) AND f.status = 1")
|
||||
FriendStatus getFollow(@Param("userId") Long userId, @Param("friendId") Long friendId);
|
||||
|
||||
@Transactional
|
||||
@Modifying
|
||||
@Query(value = "UPDATE FriendStatus f SET f.status = 2 WHERE ((f.firstUserId = :userId AND f.secondUserId = :friendId) OR (f.firstUserId = :friendId AND f.secondUserId = :userId)) AND f.status = 1")
|
||||
void setFriend(@Param("userId") Long userId, @Param("friendId") Long friendId);
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.alterdekim.game.service;
|
||||
|
||||
import com.alterdekim.game.entities.FriendStatus;
|
||||
import com.alterdekim.game.repository.FriendRepository;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -18,4 +19,12 @@ public class FriendServiceImpl {
|
||||
public void removeFriend(Long userId, Long friendId) {
|
||||
repository.removeFriend(userId, friendId);
|
||||
}
|
||||
|
||||
public void followUser(Long userId, Long friendId) {
|
||||
if( repository.getFollow(userId, friendId) == null ) {
|
||||
repository.save(new FriendStatus(userId, friendId, 1));
|
||||
return;
|
||||
}
|
||||
repository.setFriend(userId, friendId);
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ public class AuthenticationUtil {
|
||||
model.addAttribute("profile", new FriendPageResult("/profile/" + u.getId(), "/image/store/"+u.getAvatarId(), u.getUsername(), u.getId(), u.getDisplayName()));
|
||||
return u;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
// log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
58
src/main/resources/static/css/profile.css
Normal file
58
src/main/resources/static/css/profile.css
Normal file
@ -0,0 +1,58 @@
|
||||
.profile-info-avatar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
border-radius: 100%;
|
||||
width: 15rem;
|
||||
height: 15rem;
|
||||
background: center/cover no-repeat;
|
||||
}
|
||||
|
||||
.profile-info-nick {
|
||||
font-size: 45px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.profile-top-info {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.profile-stat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.profile-top-stat-list {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
margin-left: 25px;
|
||||
width: 600px;
|
||||
height: 61px;
|
||||
}
|
||||
|
||||
._val {
|
||||
font-size: 35px;
|
||||
font-weight: 300;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
._key {
|
||||
margin-top: 8px;
|
||||
margin-right: 10px;
|
||||
line-height: 10px;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.profile-top-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 200px;
|
||||
max-height: 60px;
|
||||
}
|
||||
|
||||
.profile-second-row {
|
||||
display: flex;
|
||||
margin-top: 15px;
|
||||
}
|
12
src/main/resources/static/javascript/profile.js
Normal file
12
src/main/resources/static/javascript/profile.js
Normal file
@ -0,0 +1,12 @@
|
||||
function followUser(obj) {
|
||||
let uid = $(obj).attr('data-profile-id');
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/api/v1/friends/follow",
|
||||
data: {
|
||||
userId: uid
|
||||
}
|
||||
}).done(function() {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
40
src/main/resources/templates/profile.html
Normal file
40
src/main/resources/templates/profile.html
Normal file
@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/head}"></th:block>
|
||||
<link rel="stylesheet" href="/static/css/profile.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/navbar}"></th:block>
|
||||
|
||||
<div class="container mt-5 min-vh-100" style="max-width: 1000px">
|
||||
<div class="profile-top-info">
|
||||
<div class="profile-info-avatar" th:style="${page_user.avatar}"></div>
|
||||
<span class="profile-info-nick" th:text="${page_user.displayName}"></span>
|
||||
</div>
|
||||
<div class="profile-second-row">
|
||||
<div class="profile-top-actions">
|
||||
<button class="btn btn-primary" onClick="followUser(this)" th:data-profile-id="${page_user.id}">Follow</button>
|
||||
</div>
|
||||
<div class="profile-top-stat-list">
|
||||
<div class="profile-stat">
|
||||
<div class="_val">5</div>
|
||||
<div class="_key">Friends</div>
|
||||
</div>
|
||||
<div class="profile-stat">
|
||||
<div class="_val">5</div>
|
||||
<div class="_key">Friends</div>
|
||||
</div>
|
||||
<div class="profile-stat">
|
||||
<div class="_val">5</div>
|
||||
<div class="_key">Friends</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<th:block th:insert="~{fragments/footer}"></th:block>
|
||||
<th:block th:insert="~{fragments/essentials}"></th:block>
|
||||
<script src="/static/javascript/profile.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -32,10 +32,7 @@
|
||||
<div class="mb-3">
|
||||
<label for="pronouns-select" class="form-label">Pronouns</label>
|
||||
<select class="form-select" id="pronouns-select" aria-label="">
|
||||
<option value="1" selected>she/her</option>
|
||||
<option value="2">he/him</option>
|
||||
<option value="3">they/them</option>
|
||||
<option value="4">idc</option>
|
||||
<option th:each="option : ${options}" th:value="${option.text}" th:text="${option.text}" th:selected="${option.selected}"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
|
Loading…
x
Reference in New Issue
Block a user