[+/M] Add new node /user/login and test, reformat code.

This commit is contained in:
VergeDX
2021-01-22 22:27:09 +08:00
parent 6f9cc3d2a3
commit 2fb8280a3e
3 changed files with 43 additions and 8 deletions
@@ -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)
}
}
}