[+/M] Add new node /user/login and test, reformat code.
This commit is contained in:
@@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Validated
|
||||
@RestController
|
||||
@@ -32,7 +33,7 @@ public class UserController {
|
||||
// TODO: This method should be synchronized to avoid race condition.
|
||||
// Also, this method should not be private, or else cannot use userRepository.
|
||||
|
||||
// TODO: 2021/1/22 Need a better design!
|
||||
// TODO: 2021/1/22 Need a better design!
|
||||
// Controller Return error code list as List<String>, or return uuid as String.
|
||||
@SuppressWarnings("rawtypes")
|
||||
public synchronized ResponseEntity register(
|
||||
@@ -65,16 +66,30 @@ public class UserController {
|
||||
return DigestUtils.md5DigestAsHex(beforeMd5.getBytes()).toLowerCase();
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public synchronized ResponseEntity<String> delete(@RequestHeader String username, @RequestHeader String password) {
|
||||
// Check username & password.
|
||||
// user not exists -> http 404, password not match -> http 401; all match -> do and return do's result String.
|
||||
private ResponseEntity<String> checkPasswordAndDo(String username, String password,
|
||||
Function<User, String> operation) {
|
||||
User user = userRepository.queryByUsername(username);
|
||||
if (user == null) return ResponseEntity.notFound().build();
|
||||
|
||||
if (user.getPasswordMd5().equals(userToSaltedMd5(username, password))) {
|
||||
userRepository.delete(user);
|
||||
return ResponseEntity.ok("");
|
||||
}
|
||||
if (!user.getPasswordMd5().equals(userToSaltedMd5(username, password)))
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("");
|
||||
String result = operation.apply(user);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public synchronized ResponseEntity<String> delete(@RequestHeader String username, @RequestHeader String password) {
|
||||
return checkPasswordAndDo(username, password, user -> {
|
||||
userRepository.delete(user);
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
||||
@PostMapping("login")
|
||||
public synchronized ResponseEntity<String> login(@RequestHeader String username, @RequestHeader String password) {
|
||||
return checkPasswordAndDo(username, password, user -> userRepository.queryByUsername(username).getUuid());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,5 +8,6 @@ import org.springframework.stereotype.Repository;
|
||||
public interface UserRepository extends JpaRepository<User, String> {
|
||||
// https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods
|
||||
boolean existsByUsername(String username);
|
||||
|
||||
User queryByUsername(String username);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.hydev.clock_api
|
||||
|
||||
import org.hamcrest.Matchers
|
||||
import org.hamcrest.Matchers.matchesPattern
|
||||
import org.hydev.clock_api.entity.User
|
||||
import org.hydev.clock_api.error.ErrorCode.*
|
||||
import org.hydev.clock_api.repository.UserRepository
|
||||
@@ -44,6 +45,7 @@ class UserRegisterDeleteNodeTest {
|
||||
private const val TEST_NODE = "/user"
|
||||
private const val REGISTER_NODE = "${TEST_NODE}/register"
|
||||
private const val DELETE_NODE = "${TEST_NODE}/delete"
|
||||
private const val LOGIN_NODE = "${TEST_NODE}/login"
|
||||
|
||||
private const val H_USERNAME = "username"
|
||||
private const val V_USERNAME = "vanilla"
|
||||
@@ -194,4 +196,21 @@ class UserRegisterDeleteNodeTest {
|
||||
assertEquals(false, userRepository.existsByUsername(V_USERNAME))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUserLogin() {
|
||||
mockMvc.perform(post(REGISTER_NODE).header(H_USERNAME, V_USERNAME).header(H_PASSWORD, V_PASSWORD))
|
||||
// https://stackoverflow.com/questions/49722217/how-do-i-validate-a-json-field-is-formatted-correctly-using-mockmvcresultmatcher
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(content().string(matchesPattern(R_UUID)))
|
||||
.andDo {
|
||||
// Missing field, username not exists, password not match cases already test in testDeleteUser().
|
||||
// Test successful login cases, status 200 and current user's uuid.
|
||||
mockMvc.perform(post(LOGIN_NODE).header(H_USERNAME, V_USERNAME).header(H_PASSWORD, V_PASSWORD))
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(content().string(it.response.contentAsString))
|
||||
|
||||
userRepository.deleteById(it.response.contentAsString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user