Commit b1c044c0 authored by Viacheslev Kabanovich's avatar Viacheslev Kabanovich

Improved controller to return 403 and error message instead of 500.

parent e8b7dac5
......@@ -24,33 +24,33 @@ public class FriendsController {
private FriendsService friendsService;
@PostMapping(value = "/request", headers = "Authorization")
public ResponseEntity<Boolean> request(@RequestParam String friendname,
public ResponseEntity<String> request(@RequestParam String friendname,
@AuthenticationPrincipal UserDetails signedUser) {
return new ResponseEntity<Boolean>(friendsService.request(friendname, signedUser), HttpStatus.OK);
return friendsService.request(friendname, signedUser);
}
@PostMapping(value = "/reject", headers = "Authorization")
public ResponseEntity<Boolean> reject(@RequestParam String friendname,
public ResponseEntity<String> reject(@RequestParam String friendname,
@AuthenticationPrincipal UserDetails signedUser) {
return new ResponseEntity<Boolean>(friendsService.reject(friendname, signedUser), HttpStatus.OK);
return friendsService.reject(friendname, signedUser);
}
@PostMapping(value = "/accept", headers = "Authorization")
public ResponseEntity<Boolean> accept(@RequestParam String friendname,
public ResponseEntity<String> accept(@RequestParam String friendname,
@AuthenticationPrincipal UserDetails signedUser) {
return new ResponseEntity<Boolean>(friendsService.accept(friendname, signedUser), HttpStatus.OK);
return friendsService.accept(friendname, signedUser);
}
@PostMapping(value = "/makeBest", headers = "Authorization")
public ResponseEntity<Boolean> makeBest(@RequestParam String friendname,
public ResponseEntity<String> makeBest(@RequestParam String friendname,
@AuthenticationPrincipal UserDetails signedUser) {
return new ResponseEntity<Boolean>(friendsService.makeBest(friendname, signedUser), HttpStatus.OK);
return friendsService.makeBest(friendname, signedUser);
}
@PostMapping(value = "/undoBest", headers = "Authorization")
public ResponseEntity<Boolean> undoBest(@RequestParam String friendname,
public ResponseEntity<String> undoBest(@RequestParam String friendname,
@AuthenticationPrincipal UserDetails signedUser) {
return new ResponseEntity<Boolean>(friendsService.undoBest(friendname, signedUser), HttpStatus.OK);
return friendsService.undoBest(friendname, signedUser);
}
@GetMapping(value = "/all", headers = "Authorization")
......
......@@ -7,6 +7,8 @@ import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.DelegatingMessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
......@@ -17,7 +19,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.microsocialnetwork.users.dto.SignupRequest;
import com.microsocialnetwork.users.exceptions.MicroSocialNetworkException;
import com.microsocialnetwork.users.model.User;
import com.microsocialnetwork.users.repository.UserRepository;
......@@ -33,18 +34,19 @@ public class UserController {
@PostMapping("/sign-up")
@Validated
public void signUp(@RequestBody @Valid SignupRequest request,
public ResponseEntity<String> signUp(@RequestBody @Valid SignupRequest request,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
DelegatingMessageSource d = new DelegatingMessageSource();
String message = bindingResult.getAllErrors().stream()
.map(error -> d.getMessage(error, Locale.getDefault()))
.collect(Collectors.joining(", "));
throw new MicroSocialNetworkException(message);
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(message);
}
User user = new User(request.getUsername(), request.getEmail(),
bCryptPasswordEncoder.encode(request.getPassword()));
userRepository.save(user);
return new ResponseEntity<>("Signed up as " + request.getUsername(), HttpStatus.OK);
}
@GetMapping(headers = {"Authorization"})
......
package com.microsocialnetwork.users.service;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
......@@ -11,6 +11,8 @@ import java.util.stream.Collectors;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
......@@ -32,8 +34,11 @@ public class FriendsService {
private FriendLinkRepository linkRepository;
@Transactional
public Boolean request(String friendname, UserDetails signedUser) {
public ResponseEntity<String> request(String friendname, UserDetails signedUser) {
Context ctx = new Context(friendname, signedUser);
if (ctx.error != null) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ctx.error);
}
if (ctx.direct == null) {
// 1. There were no prior requests
ctx.createNewLink();
......@@ -42,8 +47,9 @@ public class FriendsService {
// 2. There was a rejection, try new request.
if (ctx.reverse.getRejectCount() >= 3) {
//However, if the target side rejected source repeatedly, deny.
throw new MicroSocialNetworkException("Request denied: You have bean rejected by "
+ friendname + " " + ctx.reverse.getRejectCount() + " times.");
String message = "Request denied: You have bean rejected by "
+ friendname + " " + ctx.reverse.getRejectCount() + " times.";
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(message);
}
ctx.direct.setStatus(FriendStatusEnum.REQUEST_TO_THE_OTHER);
ctx.direct.setRejectCount(0);
......@@ -53,48 +59,46 @@ public class FriendsService {
ctx.direct.onAccept();
ctx.reverse.onAccepted();
} else {
return false;
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("You have already sent the request.");
}
ctx.save();
return true;
return ResponseEntity.status(HttpStatus.OK).body("Request is sent to " + friendname);
}
@Transactional
public Boolean reject(String friendname, UserDetails signedUser) {
public ResponseEntity<String> reject(String friendname, UserDetails signedUser) {
Context ctx = new Context(friendname, signedUser);
if (ctx.direct != null && (ctx.direct.getStatus().isFriend() || ctx.direct.getStatus() == FriendStatusEnum.REQUEST_BY_THE_OTHER)) {
if (ctx.error == null && ctx.direct != null && (ctx.direct.getStatus().isFriend() || ctx.direct.getStatus() == FriendStatusEnum.REQUEST_BY_THE_OTHER)) {
//If you are requested, you may reject the request;
//If you two are friends, you may reject the friendship.
ctx.direct.onReject();
ctx.reverse.onRejected();
ctx.save();
return true;
return ResponseEntity.status(HttpStatus.OK).body("You rejected friendship of " + friendname + ".");
} else {
//You cannot reject a person who is not your friend, nor requested you.
return false;
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("You cannot reject a person who is not your friend, nor requested you.");
}
}
@Transactional
public Boolean accept(String friendname, UserDetails signedUser) {
public ResponseEntity<String> accept(String friendname, UserDetails signedUser) {
Context ctx = new Context(friendname, signedUser);
if (ctx.direct != null && (ctx.direct.getStatus() == FriendStatusEnum.REQUEST_BY_THE_OTHER)) {
if (ctx.error == null && ctx.direct != null && (ctx.direct.getStatus() == FriendStatusEnum.REQUEST_BY_THE_OTHER)) {
//If you are requested, you may reject the request;
//If you two are friends, you may reject the friendship.
ctx.direct.onAccept();
ctx.reverse.onAccepted();
ctx.save();
return true;
return ResponseEntity.status(HttpStatus.OK).body("You named " + friendname + " your friend!");
} else {
//You cannot reject a person who is not your friend, nor requested you.
return false;
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(friendname + " did not request for your friennship, but may extends your request.");
}
}
@Transactional
public Boolean makeBest(String friendname, UserDetails signedUser) {
public ResponseEntity<String> makeBest(String friendname, UserDetails signedUser) {
Context ctx = new Context(friendname, signedUser);
if (ctx.direct != null && (ctx.direct.getStatus().isFriend() && !ctx.direct.getStatus().isBestFriend())) {
if (ctx.error == null && ctx.direct != null && (ctx.direct.getStatus().isFriend() && !ctx.direct.getStatus().isBestFriend())) {
if (ctx.reverse.getStatus().isBestFriend()) {
ctx.direct.setStatus(FriendStatusEnum.MUTUAL_BEST_FRIENDSHIP);
ctx.reverse.setStatus(FriendStatusEnum.MUTUAL_BEST_FRIENDSHIP);
......@@ -103,17 +107,16 @@ public class FriendsService {
ctx.reverse.setStatus(FriendStatusEnum.BEST_FRIENDSHIP_BY_THE_OTHER);
}
ctx.save();
return true;
return ResponseEntity.status(HttpStatus.OK).body("You named " + friendname + " your best friend!");
} else {
//You must be a friend to choose him the best friend.
return false;
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("You can only select the best friend of your friends.");
}
}
@Transactional
public Boolean undoBest(String friendname, UserDetails signedUser) {
public ResponseEntity<String> undoBest(String friendname, UserDetails signedUser) {
Context ctx = new Context(friendname, signedUser);
if (ctx.direct != null && (ctx.direct.getStatus().isBestFriend())) {
if (ctx.error == null && ctx.direct != null && (ctx.direct.getStatus().isBestFriend())) {
if (!ctx.reverse.getStatus().isBestFriend()) {
ctx.direct.setStatus(FriendStatusEnum.FRIENDSHIP);
ctx.reverse.setStatus(FriendStatusEnum.FRIENDSHIP);
......@@ -122,10 +125,9 @@ public class FriendsService {
ctx.reverse.setStatus(FriendStatusEnum.BEST_FRIENDSHIP_TO_THE_OTHER);
}
ctx.save();
return true;
return ResponseEntity.status(HttpStatus.OK).body("You excluded " + friendname + " from your best friends. He is still your friend, though...");
} else {
//You did not set him a best friend.
return false;
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(friendname + "was not your the best friend.");
}
}
......@@ -168,16 +170,21 @@ public class FriendsService {
public class Context {
String error = null;
User source;
User target;
FriendLink direct;
FriendLink reverse;
Context(String friendname, UserDetails signedUser) {
source = userRepository.findByUsername(signedUser.getUsername()).get();
target = userRepository.findByUsername(friendname).orElseThrow(() -> new MicroSocialNetworkException("User " + friendname + " not found."));
direct = linkRepository.findByUserAndFriend(source, target).orElse(null);
reverse = linkRepository.findByUserAndFriend(target, source).orElse(null);
target = userRepository.findByUsername(friendname).orElse(null);
if (target == null) {
error = "User " + friendname + " not found.";
} else {
source = userRepository.findByUsername(signedUser.getUsername()).get();
direct = linkRepository.findByUserAndFriend(source, target).orElse(null);
reverse = linkRepository.findByUserAndFriend(target, source).orElse(null);
}
}
void createNewLink() {
......
......@@ -4,6 +4,7 @@ import static org.junit.Assert.assertTrue;
import java.util.Base64;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -29,7 +30,8 @@ public class SignUpTest {
@Autowired
WebApplicationContext webApplicationContext;
void init() {
@BeforeEach
public void init() {
if (mvc == null) {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
......@@ -37,7 +39,6 @@ public class SignUpTest {
@Test
public void signUp() throws Exception {
init();
String uri = "/users/sign-up";
MvcResult mvcResult = mvc.perform(
MockMvcRequestBuilders.post(uri)
......@@ -46,28 +47,25 @@ public class SignUpTest {
.accept(MediaType.APPLICATION_JSON_VALUE)
).andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();
assertTrue("Expected name of signed up user in the response body.", mvcResult.getResponse().getContentAsString().indexOf("user_1") >= 0);
}
@Test
public void signUpWithUnacceptedUserName() throws Exception {
init();
String uri = "/users/sign-up";
try {
mvc.perform(
MockMvcRequestBuilders.post(uri)
.content("{\"username\":\"user 2\",\"password\":\"p\",\"email\":\"user_2@best.com\"}")
.header("Content-Type", "application/json")
.accept(MediaType.APPLICATION_JSON_VALUE)
).andExpect(MockMvcResultMatchers.status().isInternalServerError());
} catch (NestedServletException e) {
assertTrue(e.getCause().getMessage().startsWith("Username must use only letters"));
}
MvcResult mvcResult = mvc.perform(
MockMvcRequestBuilders.post(uri)
.content("{\"username\":\"user 2\",\"password\":\"p\",\"email\":\"user_2@best.com\"}")
.header("Content-Type", "application/json")
.accept(MediaType.APPLICATION_JSON_VALUE)
).andExpect(MockMvcResultMatchers.status().isForbidden())
.andReturn();
assertTrue("Expected description of valid username.", mvcResult.getResponse().getContentAsString().indexOf("must use only letters") >= 0);
}
@Test
public void getUsers() throws Exception {
init();
// signUp();
// signUp(); //do not need it as database is not reset.
String uri = "/users";
String auth = Base64.getEncoder().encodeToString("user_1:p".getBytes());
MvcResult mvcResult = mvc.perform(
......@@ -77,7 +75,6 @@ public class SignUpTest {
).andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();
String body = mvcResult.getResponse().getContentAsString();
System.out.println(body);
assertTrue(body.indexOf("user_1@best.com") >= 0);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment