Skip to content

Commit 3680e36

Browse files
author
Ivan Franchin
committed
add user page and overall proj refactor
1 parent a71f5da commit 3680e36

30 files changed

+443
-138
lines changed

README.md

+18-19
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ The goal of this project is to implement an application called `order-app` to ma
2424
| `GET /api/users` | Yes | `ADMIN` |
2525
| `GET /api/users/{username}` | Yes | `ADMIN` |
2626
| `DELETE /api/users/{username}` | Yes | `ADMIN` |
27-
| `GET /api/orders` | Yes | `ADMIN` |
28-
| `GET /api/orders/{id}` | Yes | `ADMIN`, `USER` |
27+
| `GET /api/orders [?text]` | Yes | `ADMIN` |
2928
| `POST /api/orders -d {"description"}` | Yes | `ADMIN`, `USER` |
3029
| `DELETE /api/orders/{id}` | Yes | `ADMIN` |
3130

@@ -136,8 +135,10 @@ The gif below shows ...
136135
```
137136
Code: 200
138137
{
139-
"id": "ccc4b36d-bda4-4f41-b6c2-f19c77f0243f",
140-
"description": "Buy two iPhones"
138+
"id": "718c9f40-5c06-4571-bc3e-3f888c52eff2",
139+
"description": "Buy two iPhones",
140+
"user": { "username": "user" },
141+
"createdAt": "..."
141142
}
142143
```
143144
@@ -155,42 +156,41 @@ The gif below shows ...
155156
2
156157
```
157158
158-
- Call `GET /api/orders/{id}` without JWT access token
159+
- Call `GET /api/orders` without JWT access token
159160
```
160-
curl -i localhost:8080/api/orders/6ce8cdf5-004d-4511-a6a1-604945246af8
161+
curl -i localhost:8080/api/orders
161162
```
162163
As for this endpoint a valid JWT access token is required, it should return
163164
```
164165
HTTP/1.1 401
165166
```
166167
167-
- Call `POST /auth/authenticate` to get `user` JWT access token
168+
- Call `POST /auth/authenticate` to get `admin` JWT access token
168169
```
169-
USER_ACCESS_TOKEN="$(curl -s -X POST http://localhost:8080/auth/login \
170+
ADMIN_ACCESS_TOKEN="$(curl -s -X POST http://localhost:8080/auth/authenticate \
170171
-H 'Content-Type: application/json' \
171-
-d '{"username": "user", "password": "user"}' | jq -r .accessToken)"
172+
-d '{"username": "admin", "password": "admin"}' | jq -r .accessToken)"
172173
```
173174
174-
- Call again `GET /api/orders/{id}`, now with `user` JWT access token
175+
- Call again `GET /api/orders`, now with `admin` JWT access token
175176
```
176-
curl -i -H "Authorization: Bearer $USER_ACCESS_TOKEN" localhost:8080/api/orders/6ce8cdf5-004d-4511-a6a1-604945246af8
177+
curl -i -H "Authorization: Bearer $ADMIN_ACCESS_TOKEN" localhost:8080/api/orders
177178
```
178-
It should return
179+
It should return an empty array or an array with orders
179180
```
180181
HTTP/1.1 200
181-
{ "id":"6ce8cdf5-004d-4511-a6a1-604945246af8", "description":"Buy one MacBook Pro" }
182+
[ ... ]
182183
```
183184
184-
- Call `GET /api/users/me` to get more information about the `user`
185+
- Call `GET /api/users/me` to get more information about the `admin`
185186
```
186-
curl -i -H "Authorization: Bearer $USER_ACCESS_TOKEN" localhost:8080/api/users/me
187+
curl -i -H "Authorization: Bearer $ADMIN_ACCESS_TOKEN" localhost:8080/api/users/me
187188
```
188189
It should return
189190
```
190191
HTTP/1.1 200
191-
{
192-
"id": 2, "username": "user", "name": "User", "email": "[email protected]", "role": "USER",
193-
"orders": [ ... ]
192+
{ "id": 1, "username": "admin", "name": "Admin", "email": "[email protected]", "role": "ADMIN",
193+
"orders": []
194194
}
195195
```
196196
@@ -234,7 +234,6 @@ The gif below shows ...
234234
......................... + ............. + ........... + ............ |
235235
GET /api/orders | 401 | 403 | 200 |
236236
POST /api/orders | 401 | 201 | 201 |
237-
GET /api/orders/{id} | 401 | 200 | 200 |
238237
DELETE /api/orders/{id} | 401 | 403 | 200 |
239238
------------------------------------------------------------------------
240239
[200] Success - [201] Created - [401] Unauthorized - [403] Forbidden

order-api/pom.xml

+34-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
<?xml version="1.0" encoding="UTF-8"?>
2-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
43
<modelVersion>4.0.0</modelVersion>
54
<parent>
65
<groupId>org.springframework.boot</groupId>
76
<artifactId>spring-boot-starter-parent</artifactId>
87
<version>2.2.6.RELEASE</version>
9-
<relativePath/> <!-- lookup parent from repository -->
8+
<relativePath /> <!-- lookup parent from repository -->
109
</parent>
1110
<groupId>com.mycompany</groupId>
1211
<artifactId>order-api</artifactId>
@@ -16,8 +15,9 @@
1615

1716
<properties>
1817
<java.version>1.8</java.version>
19-
<springfox.version>2.9.2</springfox.version>
2018
<jjwt.version>0.11.1</jjwt.version>
19+
<springfox.version>2.9.2</springfox.version>
20+
<org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
2121
</properties>
2222

2323
<dependencies>
@@ -65,6 +65,13 @@
6565
<version>${springfox.version}</version>
6666
</dependency>
6767

68+
<!-- Mapstruct -->
69+
<dependency>
70+
<groupId>org.mapstruct</groupId>
71+
<artifactId>mapstruct</artifactId>
72+
<version>${org.mapstruct.version}</version>
73+
</dependency>
74+
6875
<dependency>
6976
<groupId>mysql</groupId>
7077
<artifactId>mysql-connector-java</artifactId>
@@ -94,7 +101,28 @@
94101
<groupId>org.springframework.boot</groupId>
95102
<artifactId>spring-boot-maven-plugin</artifactId>
96103
</plugin>
104+
<plugin>
105+
<groupId>org.apache.maven.plugins</groupId>
106+
<artifactId>maven-compiler-plugin</artifactId>
107+
<version>3.8.1</version>
108+
<configuration>
109+
<source>1.8</source>
110+
<target>1.8</target>
111+
<annotationProcessorPaths>
112+
<path>
113+
<groupId>org.mapstruct</groupId>
114+
<artifactId>mapstruct-processor</artifactId>
115+
<version>${org.mapstruct.version}</version>
116+
</path>
117+
<path>
118+
<groupId>org.projectlombok</groupId>
119+
<artifactId>lombok</artifactId>
120+
<version>1.18.12</version>
121+
</path>
122+
</annotationProcessorPaths>
123+
</configuration>
124+
</plugin>
97125
</plugins>
98126
</build>
99127

100-
</project>
128+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.mycompany.orderapi.mapper;
2+
3+
import com.mycompany.orderapi.model.Order;
4+
import com.mycompany.orderapi.rest.dto.CreateOrderRequest;
5+
import com.mycompany.orderapi.rest.dto.OrderDto;
6+
7+
import org.mapstruct.Mapper;
8+
import org.springframework.context.annotation.Configuration;
9+
import org.mapstruct.NullValuePropertyMappingStrategy;
10+
import org.mapstruct.ReportingPolicy;
11+
12+
@Configuration
13+
@Mapper(
14+
componentModel = "spring",
15+
unmappedTargetPolicy = ReportingPolicy.IGNORE,
16+
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE
17+
)
18+
public interface OrderMapper {
19+
20+
Order toOrder(CreateOrderRequest createOrderRequest);
21+
22+
OrderDto toOrderDto(Order order);
23+
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.mycompany.orderapi.mapper;
2+
3+
import com.mycompany.orderapi.model.User;
4+
import com.mycompany.orderapi.rest.dto.UserDto;
5+
6+
import org.mapstruct.Mapper;
7+
import org.springframework.context.annotation.Configuration;
8+
import org.mapstruct.NullValuePropertyMappingStrategy;
9+
import org.mapstruct.ReportingPolicy;
10+
11+
@Configuration
12+
@Mapper(
13+
componentModel = "spring",
14+
unmappedTargetPolicy = ReportingPolicy.IGNORE,
15+
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE
16+
)
17+
public interface UserMapper {
18+
19+
UserDto toUserDto(User user);
20+
21+
}
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
package com.mycompany.orderapi.model;
22

3-
import com.fasterxml.jackson.annotation.JsonIgnore;
43
import lombok.AllArgsConstructor;
54
import lombok.Data;
65
import lombok.NoArgsConstructor;
76

7+
import java.time.ZonedDateTime;
8+
89
import javax.persistence.Entity;
910
import javax.persistence.FetchType;
1011
import javax.persistence.Id;
1112
import javax.persistence.JoinColumn;
1213
import javax.persistence.ManyToOne;
14+
import javax.persistence.PrePersist;
1315
import javax.persistence.Table;
1416

1517
@Data
1618
@NoArgsConstructor
17-
@AllArgsConstructor
1819
@Entity
1920
@Table(name = "orders")
2021
public class Order {
@@ -24,9 +25,21 @@ public class Order {
2425

2526
private String description;
2627

27-
@JsonIgnore
2828
@ManyToOne(fetch = FetchType.LAZY)
2929
@JoinColumn(name = "user_id")
3030
private User user;
3131

32+
private ZonedDateTime createdAt;
33+
34+
public Order(String id, String description, User user) {
35+
this.id = id;
36+
this.description = description;
37+
this.user = user;
38+
}
39+
40+
@PrePersist
41+
public void onPrePersist() {
42+
createdAt = ZonedDateTime.now();
43+
}
44+
3245
}

order-api/src/main/java/com/mycompany/orderapi/model/User.java

-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.mycompany.orderapi.model;
22

3-
import com.fasterxml.jackson.annotation.JsonIgnore;
43
import lombok.Data;
54
import lombok.NoArgsConstructor;
65

@@ -29,10 +28,7 @@ public class User {
2928
private Long id;
3029

3130
private String username;
32-
33-
@JsonIgnore
3431
private String password;
35-
3632
private String name;
3733
private String email;
3834
private String role;
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
package com.mycompany.orderapi.repository;
22

3+
import java.util.List;
4+
35
import com.mycompany.orderapi.model.Order;
46
import org.springframework.data.jpa.repository.JpaRepository;
57

68
public interface OrderRepository extends JpaRepository<Order, String> {
9+
10+
List<Order> findAllByOrderByCreatedAtDesc();
11+
12+
List<Order> findByIdContainingOrDescriptionContainingOrderByCreatedAt(String id, String description);
13+
714
}

order-api/src/main/java/com/mycompany/orderapi/rest/AuthController.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ public AuthController(UserService userService, PasswordEncoder passwordEncoder,
4141
@PostMapping("/authenticate")
4242
public AuthResponse login(@Valid @RequestBody LoginRequest loginRequest) {
4343
String token = authenticateAndGetToken(loginRequest.getUsername(), loginRequest.getPassword());
44-
User user = userService.validateAndGetUserByUsername(loginRequest.getUsername());
45-
return new AuthResponse(user.getId(), user.getName(), user.getRole(), token);
44+
return new AuthResponse(token);
4645
}
4746

4847
@ResponseStatus(HttpStatus.CREATED)
@@ -55,10 +54,10 @@ public AuthResponse signUp(@Valid @RequestBody SignUpRequest signUpRequest) {
5554
throw new DuplicatedUserInfoException(String.format("Email %s already been used", signUpRequest.getEmail()));
5655
}
5756

58-
User user = userService.saveUser(mapSignUpRequestToUser(signUpRequest));
57+
userService.saveUser(mapSignUpRequestToUser(signUpRequest));
5958

6059
String token = authenticateAndGetToken(signUpRequest.getUsername(), signUpRequest.getPassword());
61-
return new AuthResponse(user.getId(), user.getName(), user.getRole(), token);
60+
return new AuthResponse(token);
6261
}
6362

6463
private String authenticateAndGetToken(String username, String password) {
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.mycompany.orderapi.rest;
22

3+
import com.mycompany.orderapi.mapper.OrderMapper;
34
import com.mycompany.orderapi.model.Order;
45
import com.mycompany.orderapi.model.User;
56
import com.mycompany.orderapi.rest.dto.CreateOrderRequest;
7+
import com.mycompany.orderapi.rest.dto.OrderDto;
68
import com.mycompany.orderapi.security.CustomUserDetails;
79
import com.mycompany.orderapi.service.OrderService;
810
import com.mycompany.orderapi.service.UserService;
@@ -14,47 +16,53 @@
1416
import org.springframework.web.bind.annotation.PostMapping;
1517
import org.springframework.web.bind.annotation.RequestBody;
1618
import org.springframework.web.bind.annotation.RequestMapping;
19+
import org.springframework.web.bind.annotation.RequestParam;
1720
import org.springframework.web.bind.annotation.ResponseStatus;
1821
import org.springframework.web.bind.annotation.RestController;
1922

2023
import javax.validation.Valid;
2124
import java.util.List;
2225
import java.util.UUID;
26+
import java.util.stream.Collectors;
2327

2428
@RestController
2529
@RequestMapping("/api/orders")
2630
public class OrderController {
2731

2832
private final UserService userService;
2933
private final OrderService orderService;
34+
private final OrderMapper orderMapper;
3035

31-
public OrderController(UserService userService, OrderService orderService) {
36+
public OrderController(UserService userService, OrderService orderService, OrderMapper orderMapper) {
3237
this.userService = userService;
3338
this.orderService = orderService;
39+
this.orderMapper = orderMapper;
3440
}
3541

3642
@GetMapping
37-
public List<Order> getOrders() {
38-
return orderService.getOrders();
39-
}
40-
41-
@GetMapping("/{id}")
42-
public Order getOrder(@PathVariable UUID id) {
43-
return orderService.validateAndGetOrder(id.toString());
43+
public List<OrderDto> getOrders(@RequestParam(value = "text", required = false) String text) {
44+
List<Order> orders = (text == null) ? orderService.getOrders() : orderService.getOrderContainingText(text);
45+
return orders.stream()
46+
.map(order -> orderMapper.toOrderDto(order))
47+
.collect(Collectors.toList());
4448
}
4549

4650
@ResponseStatus(HttpStatus.CREATED)
4751
@PostMapping
48-
public Order createOrder(@AuthenticationPrincipal CustomUserDetails currentUser, @Valid @RequestBody CreateOrderRequest createOrderRequest) {
52+
public OrderDto createOrder(@AuthenticationPrincipal CustomUserDetails currentUser,
53+
@Valid @RequestBody CreateOrderRequest createOrderRequest) {
4954
User user = userService.validateAndGetUserByUsername(currentUser.getUsername());
50-
return orderService.saveOrder(new Order(UUID.randomUUID().toString(), createOrderRequest.getDescription(), user));
55+
Order order = orderMapper.toOrder(createOrderRequest);
56+
order.setId(UUID.randomUUID().toString());
57+
order.setUser(user);
58+
return orderMapper.toOrderDto(orderService.saveOrder(order));
5159
}
5260

5361
@DeleteMapping("/{id}")
54-
public Order deleteOrders(@PathVariable UUID id) {
62+
public OrderDto deleteOrders(@PathVariable UUID id) {
5563
Order order = orderService.validateAndGetOrder(id.toString());
5664
orderService.deleteOrder(order);
57-
return order;
65+
return orderMapper.toOrderDto(order);
5866
}
5967

6068
}

0 commit comments

Comments
 (0)