diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..83853db --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..63e9001 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..712ab9d --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..4b661a5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index c5786a0..09660ce 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,21 @@ +# Global Line Network Test +Test for Global Line Network + +## 1. Technologies Used +- Java 8 +- IntelliJ +- Maven +- SpringBoot +- Spring Data JPA +- h2database +- SpringBootTest + +## 2. Implementation details +- Implemented services to perfor curd operation for user +- Can be deployed and run through springboot +- Test is added to verify service + +## 3. Instalation and Testing +- It is Maven project with spring boot all libs can be added thorugh maven and project can run throgh spring boot +- Service can be called at http://localhost:8080/ -

- -

- - -Thanks for taking the time to do our front-end / full-stack practical coding challenge. - -The objective of this challenge is to evaluate your domain knowledge in front-end / full-stack development: code organization, style and best practices. - -# Overview: -The main challenge will be to build a simple user management tool that will perform basic CRUD operations on a user. Please use mockups as a reference -about look of the application. There are no business rules & guidelines other than to show us what you’re truly made of. It can be as simple or as complex as you want it to be. - -### Prerequisites -There are none :) Our main solutions stack include but not limited to Kotlin, Java, AngularJS, Flutter, Spring... -Feel free to use any languages and technologies you are comfortable with. - -## Mockups -

- - - -

- -### Front-end: -- For API please use https://reqres.in/. - -### Back-end: -- The API should be similar to https://reqres.in/, performing basic operations for user. - -_We'll be happy if you cover application with tests._ - -### Submission Guidelines -- Please fork the repo and then submit a Pull Request when you are done. -- Instructions must be provided to run the application, install any dependencies, and any other information needed. -- Please use version control and make sure we can see the history of how you went about it, rather than just uploading the complete project to GitHub. - -## Questions? ### -Please feel free to reach out and ask any questions while you are working on a solution. -Send your questions to [tech@chimaera.my](mailto:tech@chimaera.my). - - -Good luck! - - - - - diff --git a/coding-challenge.iml b/coding-challenge.iml new file mode 100644 index 0000000..78b2cc5 --- /dev/null +++ b/coding-challenge.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c3826d8 --- /dev/null +++ b/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.2.2.RELEASE + + + + org.example + coding-challenge + 1.0-SNAPSHOT + codingchallenge + codingchallenge + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + \ No newline at end of file diff --git a/src/main/java/com/gln/GLNApplication.java b/src/main/java/com/gln/GLNApplication.java new file mode 100644 index 0000000..4d21cbe --- /dev/null +++ b/src/main/java/com/gln/GLNApplication.java @@ -0,0 +1,13 @@ +package com.gln; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class GLNApplication { + + public static void main(String[] args) { + SpringApplication.run(GLNApplication.class, args); + } + +} diff --git a/src/main/java/com/gln/controller/UserController.java b/src/main/java/com/gln/controller/UserController.java new file mode 100644 index 0000000..684a0d6 --- /dev/null +++ b/src/main/java/com/gln/controller/UserController.java @@ -0,0 +1,50 @@ +package com.gln.controller; + +import com.gln.entity.User; +import com.gln.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Optional; + + +@RestController +@RequestMapping("/user") +public class UserController { + + @Autowired + UserService userService; + + @PostMapping("/create") + public User saveUser(@RequestBody User user) { + return userService.save(user); + } + + @PutMapping("/update") + public User update(@RequestBody User user) { + return userService.save(user); + } + + @DeleteMapping("/delete") + public ResponseEntity delete(@RequestBody User user) { + userService.delete(user); + return new ResponseEntity<>(HttpStatus.ACCEPTED); + } + + @GetMapping("/{id}") + public ResponseEntity getUser(@PathVariable Long id) { + Optional user = userService.get(id); + if (user.equals(Optional.empty())) + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + else + return new ResponseEntity<>(user.get(), HttpStatus.NOT_FOUND); + } + + @GetMapping("list") + public Page getUserList(@RequestParam Integer pageNo) { + return userService.getList(pageNo); + } +} \ No newline at end of file diff --git a/src/main/java/com/gln/entity/User.java b/src/main/java/com/gln/entity/User.java new file mode 100644 index 0000000..d551156 --- /dev/null +++ b/src/main/java/com/gln/entity/User.java @@ -0,0 +1,65 @@ +package com.gln.entity; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + private String email; + private String firstName; + private String lastName; + private String avatar; + + protected User() { + } + + public User(String firstName, String lastName, String email, String avatar) { + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.avatar = avatar; + } + + + public Long getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getEmail() { + return email; + } + + public String getAvatar() { + return avatar; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } +} diff --git a/src/main/java/com/gln/repository/UserRepository.java b/src/main/java/com/gln/repository/UserRepository.java new file mode 100644 index 0000000..a91e509 --- /dev/null +++ b/src/main/java/com/gln/repository/UserRepository.java @@ -0,0 +1,8 @@ +package com.gln.repository; + +import com.gln.entity.User; +import org.springframework.data.repository.PagingAndSortingRepository; + +public interface UserRepository extends PagingAndSortingRepository { + +} diff --git a/src/main/java/com/gln/service/UserService.java b/src/main/java/com/gln/service/UserService.java new file mode 100644 index 0000000..9ad4db2 --- /dev/null +++ b/src/main/java/com/gln/service/UserService.java @@ -0,0 +1,38 @@ +package com.gln.service; + +import com.gln.entity.User; +import com.gln.repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +public class UserService { + @Autowired + UserRepository repository; + + public User save(User user) { + return repository.save(user); + + } + + public void delete(User user) { + repository.delete(user); + + } + + public Optional get(Long id) { + return repository.findById(id); + + } + + public Page getList(int pageNo) { + Pageable pageable = PageRequest.of(pageNo, 6); + return repository.findAll(pageable); + + } +} diff --git a/src/test/java/com/gln/UserTest.java b/src/test/java/com/gln/UserTest.java new file mode 100644 index 0000000..af245cf --- /dev/null +++ b/src/test/java/com/gln/UserTest.java @@ -0,0 +1,92 @@ +package com.gln; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.gln.entity.User; +import com.gln.service.UserService; +import org.junit.jupiter.api.BeforeEach; +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.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +@SpringBootTest(classes = GLNApplication.class) +@AutoConfigureMockMvc +public class UserTest { + @Autowired + private MockMvc mockMvc; + @Autowired + private UserService userService; + @Autowired + private ObjectMapper mapper; + + private User user; + private String userJson; + + @BeforeEach + public void loadUser() throws Exception { + user = new User("first", "last", "abc@emil.com", "www.avatar.com"); + userJson = mapper.writeValueAsString(user); + } + + + @Test + public void createUserTest() throws Exception { + + this.mockMvc.perform(post("/user/create") + .contentType(MediaType.APPLICATION_JSON) + .content(userJson) + ).andExpect(status().isOk()); + } + + @Test + public void updateUserTest() throws Exception { + + this.mockMvc.perform(post("/user/create") + .contentType(MediaType.APPLICATION_JSON) + .content(userJson) + ).andExpect(status().isOk()); + + MvcResult result = this.mockMvc.perform(get("/user/1") + .contentType(MediaType.APPLICATION_JSON) + .content(userJson)).andReturn(); + + User updateUser = mapper.readValue(result.getResponse().getContentAsString(), User.class); + updateUser.setFirstName("ufirstName"); + updateUser.setLastName("ulastName"); + + + this.mockMvc.perform(put("/user/update") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(updateUser)) + ).andExpect(status().isOk()).andExpect(content().json(mapper.writeValueAsString(updateUser))); + } + + @Test + public void deleteUserTest() throws Exception { + + this.mockMvc.perform(post("/user/create") + .contentType(MediaType.APPLICATION_JSON) + .content(userJson) + ).andExpect(status().isOk()); + + MvcResult result = this.mockMvc.perform(get("/user/1") + .contentType(MediaType.APPLICATION_JSON) + .content(userJson)).andReturn(); + + User deleteUser = mapper.readValue(result.getResponse().getContentAsString(), User.class); + + + this.mockMvc.perform(delete("/user/delete") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(deleteUser)) + ).andExpect(status().isAccepted()); + } +}