Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
38a493d
Remove VK and Yandex links and labels on the login and register pages.
Xba1337 Oct 24, 2024
93b64c5
Merge pull request #1 from Xba1337/TASK-2
Xba1337 Oct 24, 2024
f2e706a
Remove VK and Yandex links and labels on the login and register pages.
Xba1337 Oct 24, 2024
abec27c
Remove sensitive DB, OAuth2 and mail settings information
Xba1337 Oct 24, 2024
c1d2d3b
Create file. Transfer sensitive DB, OAuth2 and mail settings informat…
Xba1337 Oct 24, 2024
f492246
Merge pull request #2 from Xba1337/TASK-3
Xba1337 Oct 24, 2024
b41543e
Change and create settings for H2 DB tests.
Xba1337 Oct 26, 2024
f2a3afe
Change and create settings for H2 DB tests.
Xba1337 Oct 26, 2024
5f8aec4
Merge pull request #3 from Xba1337/TASK-4
Xba1337 Oct 26, 2024
f1918cb
Try to fix original tests.
Xba1337 Oct 26, 2024
7b97335
Change IO to NIO API in upload method of FileUtil class.
Xba1337 Oct 26, 2024
00600a5
Merge pull request #4 from Xba1337/TASK-6
Xba1337 Oct 27, 2024
92cfc53
Create additional sql scripts, "test" and "prod" profiles for H2 test…
Xba1337 Oct 27, 2024
e086c32
Update data-test.sql
Xba1337 Oct 27, 2024
a895463
Merge pull request #5 from Xba1337/TASK-4
Xba1337 Oct 27, 2024
08d0d92
TASK-11. Create two messages.properties for RU and EN.
Xba1337 Oct 28, 2024
f6290cd
Change paths in annotation for AbstractControllerTest.java
Xba1337 Oct 29, 2024
bf69ae7
Delete excess information
Xba1337 Oct 29, 2024
443d8d3
Was changed name and removed.
Xba1337 Oct 29, 2024
b326a6d
Was removed excess annotation for active profile choosing.
Xba1337 Oct 29, 2024
56999f4
Data.sql script was simplified for H2 db
Xba1337 Oct 29, 2024
474fd78
Changelog.sql was copied to test folder, renamed to changelog-test.sq…
Xba1337 Oct 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
Expand Down Expand Up @@ -142,6 +143,12 @@
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>

<build>
Expand Down
11 changes: 5 additions & 6 deletions resources/mails/email-confirmation.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<html lang="${#locale.language}" xmlns:th="http://www.thymeleaf.org">
<head>
<title>JiraRush - подтверждение почты</title>
<title th:text="#{email.confirmation.subject}"></title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
</head>
<body>
<p th:text="'Привет, ' + ${user.firstName} + '.'"/>
<p>Чтобы завершить настройку учетной записи и начать пользоваться JiraRush, подтвердите, что вы правильно указали вашу
электронную почту.</p>
<a th:href="${confirmationUrl}">Подтвердить почту</a>
<p th:text="#{email.confirmation.greeting(${user.firstName})}"></p>
<p th:text="#{email.confirmation.body}"></p>
<a th:href="${confirmationUrl}" th:text="#{email.confirmation.link}"></a>
</body>
</html>
14 changes: 8 additions & 6 deletions resources/view/index.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<!DOCTYPE html>
<html lang="ru" xmlns:th="http://www.thymeleaf.org">
<!--/*@thymesVar id="authUser" type="com.javarush.jira.login.AuthUser"*/-->

<th:block th:replace="~{layout/main::page(title='JiraRush: mini bugtracking system',appMain=~{::appMain})}">
<html lang="${#locale.language}" xmlns:th="http://www.thymeleaf.org">
<th:block th:replace="~{layout/main::page(title=#{home.title},appMain=~{::appMain})}">
<appMain>
<h1>JiraRush Home page</h1>
<h1 th:text="#{home.title}">JiraRush Home page</h1>
<div>
<a href="?lang=en" th:text="#{home.language.en}">English</a> |
<a href="?lang=ru" th:text="#{home.language.ru}">Русский</a>
</div>
<div th:if="${authUser} != null">
<form action="/ui/logout" method="post">
<button class="btn btn-primary btn-lg mt-3" type="submit">Logout</button>
<button class="btn btn-primary btn-lg mt-3" type="submit" th:text="#{home.logout}"></button>
</form>
</div>
</appMain>
Expand Down
8 changes: 0 additions & 8 deletions resources/view/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,6 @@ <h3 class="mb-3">Sign in</h3>
type="button">
<i class="fa-brands fa-google"></i>
</a>
<a class="btn btn-primary btn-lg me-2" href="/oauth2/authorization/vk" style="padding-left: 17px; padding-right: 17px;"
type="button">
<i class="fa-brands fa-vk"></i>
</a>
<a class="btn btn-danger btn-lg me-2" href="/oauth2/authorization/yandex" style="padding-left: 21px; padding-right: 21px;"
type="button">
<i class="fa-brands fa-yandex"></i>
</a>
<a class="btn btn-dark btn-lg me-2" href="/oauth2/authorization/github" type="button">
<i class="fa-brands fa-github"></i>
</a>
Expand Down
9 changes: 1 addition & 8 deletions resources/view/unauth/register.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,7 @@ <h3 class="mb-3">Registration</h3>
type="button">
<i class="fa-brands fa-google"></i>
</a>
<a class="btn btn-primary btn-lg me-2" href="/oauth2/authorization/vk" style="padding-left: 17px; padding-right: 17px;"
type="button">
<i class="fa-brands fa-vk"></i>
</a>
<a class="btn btn-danger btn-lg me-2" href="/oauth2/authorization/yandex" style="padding-left: 21px; padding-right: 21px;"
type="button">
<i class="fa-brands fa-yandex"></i>
</a>

<a class="btn btn-dark btn-lg me-2" href="/oauth2/authorization/github" type="button">
<i class="fa-brands fa-github"></i>
</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,18 @@ public static void upload(MultipartFile multipartFile, String directoryPath, Str
throw new IllegalRequestDataException("Select a file to upload.");
}

File dir = new File(directoryPath);
if (dir.exists() || dir.mkdirs()) {
File file = new File(directoryPath + fileName);
try (OutputStream outStream = new FileOutputStream(file)) {
outStream.write(multipartFile.getBytes());
} catch (IOException ex) {
throw new IllegalRequestDataException("Failed to upload file" + multipartFile.getOriginalFilename());
try {
Path dir = Paths.get(directoryPath);
if (Files.notExists(dir)) {
Files.createDirectories(dir);
}

Path filePath = dir.resolve(fileName);

Files.write(filePath, multipartFile.getBytes());

} catch (IOException ex) {
throw new IllegalRequestDataException("Failed to upload file " + multipartFile.getOriginalFilename());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule;
import com.javarush.jira.common.util.JsonUtil;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.http.ProblemDetail;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.sql.DataSource;
import java.util.Map;
import java.util.concurrent.Executor;

Expand Down Expand Up @@ -52,6 +56,16 @@ public boolean isTest() {
return env.acceptsProfiles(Profiles.of("test"));
}

@Profile("prod")
public DataSource prodDataSource() {
return DataSourceBuilder.create().build();
}

@Profile("test")
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}

@Autowired
void configureAndStoreObjectMapper(ObjectMapper objectMapper) {
objectMapper.registerModule(new Hibernate5JakartaModule());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,26 @@
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.ui.ModelMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.filter.ForwardedHeaderFilter;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.servlet.mvc.UrlFilenameViewController;

import java.time.Duration;
import java.util.Locale;
import java.util.Properties;

//@EnableWebMvc : http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-spring-mvc-auto-configuration
Expand All @@ -32,6 +37,29 @@
public class MvcConfig implements WebMvcConfigurer {
private final AppProperties appProperties;


@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.ENGLISH);
return localeResolver;
}

@Bean
public ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}

@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang");
return interceptor;
}

// Add authUser to view model
private final HandlerInterceptor authInterceptor = new WebRequestHandlerInterceptorAdapter(new WebRequestInterceptor() {
@Override
Expand All @@ -56,6 +84,7 @@ public void preHandle(WebRequest request) {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor).excludePathPatterns("/api/**");
registry.addInterceptor(localeChangeInterceptor());
}

// http://www.codejava.net/frameworks/spring/spring-mvc-url-based-view-resolution-with-urlfilenameviewcontroller-example
Expand All @@ -79,6 +108,7 @@ ForwardedHeaderFilter forwardedHeaderFilter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");

}

@Override
Expand Down
25 changes: 19 additions & 6 deletions src/main/java/com/javarush/jira/mail/MailService.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.javarush.jira.mail.internal.MailCaseRepository;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import jakarta.servlet.http.HttpServletRequest;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -19,6 +20,8 @@
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring6.SpringTemplateEngine;

Expand All @@ -29,7 +32,6 @@
@Service
@RequiredArgsConstructor
public class MailService {
private static final Locale LOCALE_RU = Locale.forLanguageTag("ru");
private static final String OK = "OK";

private final MailCaseRepository mailCaseRepository;
Expand All @@ -50,20 +52,31 @@ public static boolean isOk(String result) {
return OK.equals(result);
}

private Locale determineUserLocale() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String acceptLanguage = request.getHeader("Accept-Language");
if (acceptLanguage != null && !acceptLanguage.isEmpty()) {
return Locale.forLanguageTag(acceptLanguage.split(",")[0]);
}

return Locale.ENGLISH;
}

public String sendToUserWithParams(@NonNull String template, @NonNull User user, @NonNull Map<String, Object> params) {
String email = Objects.requireNonNull(user.getEmail());
Map<String, Object> extParams = Util.mergeMap(params, Map.of("user", user));
return send(appConfig.isProd() ? email : appProperties.getTestMail(), user.getFirstName(), template, extParams);
Locale locale = determineUserLocale();
return send(appConfig.isProd() ? email : appProperties.getTestMail(), user.getFirstName(), template, extParams, locale);
}

public String send(String toEmail, String toName, String template, Map<String, Object> params) {
public String send(String toEmail, String toName, String template, Map<String, Object> params, Locale locale) {
log.debug("Send email to {}, {} with template {}", toEmail, toName, template);
String result = OK;
try {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, "UTF-8");
message.setFrom(email, "JiraRush");
String content = getContent(template, params);
String content = getContent(template, params, locale);
message.setText(content, true);
message.setSubject(Util.getTitle(content)); // TODO calculate title for group emailing only once
message.setTo(new InternetAddress(toEmail, toName, "UTF-8"));
Expand All @@ -78,8 +91,8 @@ public String send(String toEmail, String toName, String template, Map<String, O
return result;
}

private String getContent(String template, Map<String, Object> params) {
Context context = new Context(LOCALE_RU, params);
private String getContent(String template, Map<String, Object> params, Locale locale) {
Context context = new Context(locale, params);
return templateEngine.process(template, context);
}

Expand Down
46 changes: 46 additions & 0 deletions src/main/resources/application-secrets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
spring:
datasource:
url: jdbc:postgresql://localhost:5432/jira
username: jira
password: JiraRush

security:
oauth2:
client:
registration:
github:
client-id: 3d0d8738e65881fff266
client-secret: 0f97031ce6178b7dfb67a6af587f37e222a16120
scope:
- email
google:
client-id: 329113642700-f8if6pu68j2repq3ef6umd5jgiliup60.apps.googleusercontent.com
client-secret: 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
scope:
- email
- profile
gitlab:
client-id: b8520a3266089063c0d8261cce36971defa513f5ffd9f9b7a3d16728fc83a494
client-secret: e72c65320cf9d6495984a37b0f9cc03ec46be0bb6f071feaebbfe75168117004
client-name: GitLab
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
authorization-grant-type: authorization_code
scope: read_user
provider:
gitlab:
authorization-uri: https://gitlab.com/oauth/authorize
token-uri: https://gitlab.com/oauth/token
user-info-uri: https://gitlab.com/api/v4/user
user-name-attribute: email

mail:
properties:
mail:
smtp:
starttls:
enable: true
auth: true
host: smtp.gmail.com
username: jira4jr@gmail.com
password: zdfzsrqvgimldzyj
port: 587
Loading