Skip to content

Commit

Permalink
[#1] Implements POST /users/login
Browse files Browse the repository at this point in the history
  • Loading branch information
raeperd committed Apr 14, 2021
1 parent fb02331 commit 4195715
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 0 deletions.
1 change: 1 addition & 0 deletions lombok.config
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# This file is generated by the 'io.freefair.lombok' Gradle plugin
config.stopBubbling = true
lombok.extern.findbugs.addSuppressFBWarnings = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.raeperd.realworld.application;

import io.github.raeperd.realworld.domain.User;
import lombok.Getter;

@Getter
public class UserLoginRequestDTO {

private final String email;
private final String password;

public UserLoginRequestDTO(String email, String password) {
this.email = email;
this.password = password;
}

public User toUser() {
return User.fromEmailAndPassword(email, password);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.github.raeperd.realworld.application;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.github.raeperd.realworld.domain.User;
import lombok.Getter;

@JsonTypeName("user")
@JsonTypeInfo(include = As.WRAPPER_OBJECT, use = Id.NAME)
@Getter
public class UserResponseDTO {

private final String email;
private final String token;
private final String username;
private final String bio;
private final String image;

public static UserResponseDTO fromUser(User user) {
return new UserResponseDTO(user);
}

private UserResponseDTO(User user) {
this.email = user.getEmail();
this.username = user.getUsername();
this.bio = user.getBio();
this.image = user.getImage();
// TODO: Generate token from user somewhere else
this.token = "";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.github.raeperd.realworld.application;

import io.github.raeperd.realworld.domain.UserRepository;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import static org.springframework.http.ResponseEntity.of;

@RestController
public class UserRestController {

private final UserRepository userRepository;

public UserRestController(UserRepository userRepository) {
this.userRepository = userRepository;
}

@PostMapping("/users/login")
public ResponseEntity<UserResponseDTO> login(@RequestBody UserLoginRequestDTO loginRequest) {
return of(userRepository.findFirstByEmailAndPassword(loginRequest.getEmail(), loginRequest.getPassword())
.map(UserResponseDTO::fromUser));
}

}
45 changes: 45 additions & 0 deletions src/main/java/io/github/raeperd/realworld/domain/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.github.raeperd.realworld.domain;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class User {

@Id
private long id;

private String email;
private String password;
private String username;
private String bio;
private String image;

protected User() {
}

public static User fromEmailAndPassword(String email, String password) {
return new User(email, password);
}

private User(String email, String password) {
this.email = email;
this.password = password;
}

public String getEmail() {
return email;
}

public String getUsername() {
return username;
}

public String getBio() {
return bio;
}

public String getImage() {
return image;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.github.raeperd.realworld.domain;

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserRepository extends JpaRepository<User, Long> {

Optional<User> findFirstByEmailAndPassword(String email, String password);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package io.github.raeperd.realworld.application;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.raeperd.realworld.domain.UserRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;

import static io.github.raeperd.realworld.domain.User.fromEmailAndPassword;
import static java.util.Optional.of;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@AutoConfigureMockMvc
@WebMvcTest(UserRestController.class)
class UserRestControllerTest {

@MockBean
private UserRepository userRepository;

@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;

@Test
void when_post_login_expect_userRepository_findFirstByEmailAndPassword_called() throws Exception {
final var loginDTO = new UserLoginRequestDTO("email", "password");
when(userRepository.findFirstByEmailAndPassword(loginDTO.getEmail(), loginDTO.getPassword()))
.thenReturn(of(fromEmailAndPassword(loginDTO.getEmail(), loginDTO.getPassword())));

mockMvc.perform(post("/users/login")
.contentType(APPLICATION_JSON)
.content(objectMapper.writeValueAsString(loginDTO)));

then(userRepository).should(times(1))
.findFirstByEmailAndPassword(loginDTO.getEmail(), loginDTO.getPassword());
}

@Test
void when_post_login_expect_valid_response_body() throws Exception {
when(userRepository.findFirstByEmailAndPassword(anyString(), anyString()))
.thenReturn(of(fromEmailAndPassword("email", "password")));

mockMvc.perform(post("/users/login")
.contentType(APPLICATION_JSON)
.content(objectMapper.writeValueAsString(new UserLoginRequestDTO("email", "password"))))
.andExpect(status().isOk())
.andExpect(jsonPath("$.user").exists())
.andExpect(jsonPath("$.user.email").exists())
.andExpect(jsonPath("$.user.bio").hasJsonPath())
.andExpect(jsonPath("$.user.image").hasJsonPath())
.andExpect(jsonPath("$.user.token").hasJsonPath());
}

}

0 comments on commit 4195715

Please sign in to comment.