Skip to content

Commit 8fbeb64

Browse files
committed
feat: some changes
1 parent c58c837 commit 8fbeb64

File tree

12 files changed

+187
-114
lines changed

12 files changed

+187
-114
lines changed

.vscode/settings.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,11 @@
1414
"java.configuration.updateBuildConfiguration": "automatic",
1515

1616
// https://github.com/halcyon/asdf-java#asdf-java
17-
"java.jdt.ls.java.home": "~/.asdf/installs/java/openjdk-17.0.1"
17+
"java.jdt.ls.java.home": "~/.asdf/installs/java/openjdk-17.0.1",
18+
19+
"coverage-gutters.showLineCoverage": true,
20+
"coverage-gutters.showRulerCoverage": true,
21+
"coverage-gutters.coverageFileNames": [
22+
"jacoco.xml"
23+
]
1824
}

README.md

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -57,38 +57,43 @@ This project was started with [Spring Initializr](https://start.spring.io/#!type
5757
>[🚨 draw.io file here](./assets/database/diagram.drawio)
5858
5959
## Installation
60+
> 🚨 check [requirements](#requirements) or if you are using docker check [docker development instructions](#docker-examples)
6061
61-
```shell
62-
# clone the repository and access the directory.
63-
$ git clone git@github.com:Throyer/springboot-api-crud.git && cd springboot-api-crud
64-
65-
# download dependencies
66-
$ mvn install -DskipTests
67-
68-
# run the application
69-
$ mvn spring-boot:run
70-
71-
# run the tests
72-
$ mvn test
73-
74-
# to build for production
75-
$ mvn clean package
76-
77-
# to generate the coverage report after testing (available at: target/site/jacoco/index.html)
78-
$ mvn jacoco:report
79-
```
62+
- clone the repository and access the directory.
63+
```shell
64+
git clone git@github.com:Throyer/springboot-api-crud.git crud && cd crud
65+
```
66+
- download dependencies
67+
```shell
68+
mvn -f api/pom.xml install -DskipTests
69+
```
70+
- run the application
71+
```shell
72+
mvn -f api/pom.xml spring-boot:run
73+
```
74+
- running the tests
75+
```shell
76+
mvn -f api/pom.xml test
77+
```
78+
- to build for production
79+
```shell
80+
mvn -f api/pom.xml clean package
81+
```
82+
- to generate the coverage report after testing `(available at: target/site/jacoco/index.html)`
83+
```shell
84+
mvn -f api/pom.xml jacoco:report
85+
```
8086

8187
## Tests
8288
[![Coverage Status](https://coveralls.io/repos/github/Throyer/springboot-api-crud/badge.svg?branch=master)](https://coveralls.io/repos/github/Throyer/springboot-api-crud/badge.svg?branch=master)
8389

8490
## Running a specific test
8591
use the parameter `-Dtest=<class>#<method>`
8692

87-
88-
for example the integration test. creating a user:
89-
```
90-
$ mvn test -Dtest=UsersControllerIntegrationTests#should_save_a_new_user
91-
```
93+
- for example the integration test. creating a user:
94+
```shell
95+
mvn -f api/pom.xml test -Dtest=UsersControllerIntegrationTests#should_save_a_new_user
96+
```
9297

9398

9499
## Swagger
@@ -102,7 +107,7 @@ Once the application is up, it is available at: [localhost:8080/documentation](l
102107
## Database Migrations
103108
Creating database migration files
104109

105-
> 🚨 make sure you have maven in your environment and that you are in the correct directory __./api__
110+
> 🚨 check [requirements](#requirements)
106111
>
107112
> if you using docker-compose
108113
> ```
@@ -111,12 +116,12 @@ Creating database migration files
111116
112117
- Java based migrations
113118
```bash
114-
mvn migration:generate -Dname=my-migration-name
119+
mvn -f api/pom.xml migration:generate -Dname=my-migration-name
115120
```
116121
117122
- SQL based migrations
118123
```bash
119-
mvn migration:generate -Dname=my-migration-name -Dsql
124+
mvn -f api/pom.xml migration:generate -Dname=my-migration-name -Dsql
120125
```
121126

122127
---

api/pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@
231231
<configuration>
232232
<excludes>
233233
<exclude>db/migration/**/*</exclude>
234+
<exclude>com/github/throyer/common/springboot/configurations/**/*</exclude>
235+
<exclude>com/github/throyer/common/springboot/constants/**/*</exclude>
234236
</excludes>
235237
</configuration>
236238
</plugin>

api/src/main/java/com/github/throyer/common/springboot/constants/MAIL.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ public class MAIL {
44
private MAIL () {}
55

66
public static final Boolean CONTENT_IS_HTML = true;
7+
public static final String ERROR_SMTP_AUTH = "Error on SMTP authentication.";
78
public static final String ERROR_SENDING_EMAIL_MESSAGE = "Error sending email.";
89
public static final String ERROR_SENDING_EMAIL_MESSAGE_TO = "Error sending email to: {}";
910
public static final String EMAIL_SUCCESSFULLY_SENT_TO = "Email successfully sent to: {}";
Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,63 @@
11
package com.github.throyer.common.springboot.domain.mail.service;
22

3-
import com.github.throyer.common.springboot.domain.mail.model.Email;
3+
import static com.github.throyer.common.springboot.constants.MAIL.CONTENT_IS_HTML;
4+
import static com.github.throyer.common.springboot.constants.MAIL.EMAIL_SUCCESSFULLY_SENT_TO;
5+
import static com.github.throyer.common.springboot.constants.MAIL.ERROR_SENDING_EMAIL_MESSAGE;
6+
import static com.github.throyer.common.springboot.constants.MAIL.ERROR_SMTP_AUTH;
7+
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
8+
49
import javax.mail.MessagingException;
10+
import javax.mail.internet.MimeMessage;
511

6-
import org.slf4j.Logger;
7-
import org.slf4j.LoggerFactory;
812
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.mail.MailAuthenticationException;
914
import org.springframework.mail.MailException;
1015
import org.springframework.mail.javamail.JavaMailSender;
1116
import org.springframework.mail.javamail.MimeMessageHelper;
1217
import org.springframework.stereotype.Service;
1318
import org.springframework.web.server.ResponseStatusException;
1419
import org.thymeleaf.TemplateEngine;
1520

16-
import static com.github.throyer.common.springboot.constants.MAIL.*;
17-
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
21+
import com.github.throyer.common.springboot.domain.mail.model.Email;
22+
23+
import lombok.extern.slf4j.Slf4j;
1824

1925
@Service
26+
@Slf4j
2027
public class MailService {
2128

22-
private final TemplateEngine engine;
23-
private final JavaMailSender sender;
24-
25-
@Autowired
26-
public MailService(TemplateEngine engine, JavaMailSender sender) {
27-
this.engine = engine;
28-
this.sender = sender;
29+
private final TemplateEngine engine;
30+
private final JavaMailSender sender;
31+
32+
@Autowired
33+
public MailService(TemplateEngine engine, JavaMailSender sender) {
34+
this.engine = engine;
35+
this.sender = sender;
36+
}
37+
38+
public void send(Email email) {
39+
try {
40+
var message = createMessage(email);
41+
sender.send(message);
42+
log.info(EMAIL_SUCCESSFULLY_SENT_TO, email.getDestination());
43+
} catch (MailAuthenticationException exception) {
44+
log.error(ERROR_SMTP_AUTH);
45+
} catch (MessagingException | MailException exception) {
46+
log.error(ERROR_SENDING_EMAIL_MESSAGE, exception);
47+
throw new ResponseStatusException(INTERNAL_SERVER_ERROR, ERROR_SENDING_EMAIL_MESSAGE);
2948
}
49+
}
3050

31-
private static final Logger LOGGER = LoggerFactory.getLogger(MailService.class);
32-
33-
public void send(Email email) {
34-
try {
35-
var message = sender.createMimeMessage();
36-
var helper = new MimeMessageHelper(message);
37-
helper.setTo(email.getDestination());
38-
helper.setSubject(email.getSubject());
39-
helper.setText(engine.process(email.getTemplate(), email.getContext()), CONTENT_IS_HTML);
40-
sender.send(message);
41-
LOGGER.info(EMAIL_SUCCESSFULLY_SENT_TO, email.getDestination());
42-
} catch (MessagingException | MailException exception) {
43-
LOGGER.error(ERROR_SENDING_EMAIL_MESSAGE, exception);
44-
throw new ResponseStatusException(INTERNAL_SERVER_ERROR, ERROR_SENDING_EMAIL_MESSAGE);
45-
}
46-
}
51+
private MimeMessage createMessage(Email email) throws MessagingException {
52+
var message = sender.createMimeMessage();
53+
var helper = new MimeMessageHelper(message);
54+
55+
var html = engine.process(email.getTemplate(), email.getContext());
56+
57+
helper.setTo(email.getDestination());
58+
helper.setSubject(email.getSubject());
59+
helper.setText(html, CONTENT_IS_HTML);
60+
61+
return message;
62+
}
4763
}

api/src/test/java/com/github/throyer/common/springboot/InternationalizationTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ void should_return_error_messages_in_pt_BR() throws Exception {
3434
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
3535
.header(HttpHeaders.ACCEPT_LANGUAGE, "pt-BR"))
3636
.andExpect(status().isForbidden())
37-
.andExpect(jsonPath("$.message").value("Senha ou usuário invalido."));;
37+
.andExpect(jsonPath("$.message").value("Senha ou usuário invalido."));
3838
}
3939

4040
@Test

web/src/components/navbar/index.tsx

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,56 @@
1-
import { Button, Divider, Stack, Text } from "@chakra-ui/react";
2-
import { Link, useNavigate } from "react-router-dom";
1+
import { Button, Divider, Flex, Menu, MenuButton, MenuItem, MenuList, Stack, Text, Link as ChakraLink, Avatar } from "@chakra-ui/react";
2+
import { Link, useLocation, useNavigate } from "react-router-dom";
33
import { useAuthentication } from "../../hooks/use-authentication/use-authentication";
4+
import { BiChevronDown } from 'react-icons/bi'
5+
import { useUser } from "../../providers/user";
46

57
export const Navbar = () => {
6-
7-
const { logout } = useAuthentication()
8-
const navigate = useNavigate()
8+
const { user } = useUser()
9+
const { logout } = useAuthentication();
10+
const navigate = useNavigate();
11+
const { pathname } = useLocation();
912

1013
return (
1114
<>
12-
<Stack mt="10" direction='row'>
13-
<Link to="/">
14-
<Button
15-
p="3"
16-
variant="link">
17-
Home
18-
</Button>
19-
</Link>
20-
<Link to="/users">
21-
<Button
22-
p="3"
23-
variant="link">
24-
Users
25-
</Button>
26-
</Link>
27-
<Button
28-
onClick={() => {
29-
logout();
30-
navigate('/');
31-
}}
32-
p="3"
33-
variant="link">
34-
Logout
35-
</Button>
36-
</Stack>
15+
<Flex
16+
mt="10"
17+
py="2"
18+
gap="2"
19+
justifyContent="space-between"
20+
direction="row"
21+
>
22+
<Flex
23+
gap="2"
24+
justifyContent="space-between"
25+
direction="row"
26+
>
27+
<Link to="/home">
28+
<Text px="2" fontWeight={pathname === '/home' ? 'bold' : 'normal'} display="block">
29+
Home
30+
</Text>
31+
</Link>
32+
<Link to="/users">
33+
<Text px="2" fontWeight={pathname === '/users' ? 'bold' : 'normal'} display="block">
34+
Users
35+
</Text>
36+
</Link>
37+
</Flex>
38+
{user && (
39+
<Menu>
40+
<MenuButton as={ChakraLink}>
41+
<Avatar size="sm" name={user.name} src='https://bit.ly/broken-link' />
42+
</MenuButton>
43+
<MenuList>
44+
<MenuItem onClick={() => {
45+
logout();
46+
navigate('/');
47+
}}>
48+
Logout
49+
</MenuItem>
50+
</MenuList>
51+
</Menu>
52+
)}
53+
</Flex>
3754
<Divider />
3855
</>
3956
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export interface User {
2+
id: number;
3+
name: string;
4+
active: boolean;
5+
email: string;
6+
roles: string[]
7+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { useState } from "react"
2+
import { PaginationProps } from "../../components/pagination";
3+
import { User } from "./use-user.types"
4+
5+
export const useUsers = () => {
6+
7+
const [users, setUsers] = useState<User[]>([])
8+
const [loading, setLoading] = useState(false);
9+
const [pagination, setPagination] = useState<PaginationProps>({
10+
page: 0,
11+
size: 10,
12+
totalPages: 10
13+
});
14+
15+
const update = (page?: number, size?: number) => {
16+
17+
}
18+
19+
return {
20+
users,
21+
pagination,
22+
loading,
23+
update
24+
}
25+
}

web/src/pages/login/index.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
import { Box, Heading } from "@chakra-ui/layout";
2-
import { Button, Center, Code, FormControl, FormLabel, Input, VStack } from "@chakra-ui/react";
2+
import {
3+
Button,
4+
Center,
5+
Code,
6+
FormControl,
7+
FormLabel,
8+
Input,
9+
VStack
10+
} from "@chakra-ui/react";
311
import { FormEvent, useState } from "react";
4-
import { useNavigate } from "react-router-dom";
512
import { useAuthentication } from "../../hooks/use-authentication/use-authentication";
613
import { useUser } from "../../providers/user";
714

815
export const Login = () => {
916

1017
const { login } = useAuthentication();
1118
const { user } = useUser();
12-
const navigate = useNavigate()
1319

1420
const [email, setEmail] = useState('');
1521
const [password, setPassword] = useState('');

0 commit comments

Comments
 (0)