From 0e2d7e2e1503131c28e41fac5cdcae31952a97dd Mon Sep 17 00:00:00 2001 From: Dezolus Date: Sat, 7 Sep 2024 12:54:51 +0300 Subject: [PATCH 01/12] Task 2 done --- pom.xml | 1 + resources/view/login.html | 8 ----- resources/view/unauth/register.html | 8 ----- .../handler/VkOAuth2UserDataHandler.java | 35 ------------------- .../handler/YandexOAuth2UserDataHandler.java | 21 ----------- src/main/resources/application.yaml | 24 ------------- src/main/resources/data4dev/data.sql | 3 +- src/main/resources/db/changelog.sql | 1 - .../profile/internal/web/ProfileTestData.java | 2 -- src/test/resources/data.sql | 3 +- 10 files changed, 3 insertions(+), 103 deletions(-) delete mode 100644 src/main/java/com/javarush/jira/login/internal/sociallogin/handler/VkOAuth2UserDataHandler.java delete mode 100644 src/main/java/com/javarush/jira/login/internal/sociallogin/handler/YandexOAuth2UserDataHandler.java diff --git a/pom.xml b/pom.xml index f6c152c68..8b89f90eb 100644 --- a/pom.xml +++ b/pom.xml @@ -97,6 +97,7 @@ org.projectlombok lombok true + 1.18.34 org.mapstruct diff --git a/resources/view/login.html b/resources/view/login.html index 8765ca8ff..d49ce5691 100644 --- a/resources/view/login.html +++ b/resources/view/login.html @@ -48,14 +48,6 @@

Sign in

type="button"> - - - - - - diff --git a/resources/view/unauth/register.html b/resources/view/unauth/register.html index 2ba955045..52a892bd3 100644 --- a/resources/view/unauth/register.html +++ b/resources/view/unauth/register.html @@ -77,14 +77,6 @@

Registration

type="button"> - - - - - - diff --git a/src/main/java/com/javarush/jira/login/internal/sociallogin/handler/VkOAuth2UserDataHandler.java b/src/main/java/com/javarush/jira/login/internal/sociallogin/handler/VkOAuth2UserDataHandler.java deleted file mode 100644 index e8e05be05..000000000 --- a/src/main/java/com/javarush/jira/login/internal/sociallogin/handler/VkOAuth2UserDataHandler.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.javarush.jira.login.internal.sociallogin.handler; - -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Map; - -@Component("vk") -public class VkOAuth2UserDataHandler implements OAuth2UserDataHandler { - @Override - public String getFirstName(OAuth2UserData oAuth2UserData) { - return getAttribute(oAuth2UserData, "first_name"); - } - - @Override - public String getLastName(OAuth2UserData oAuth2UserData) { - return getAttribute(oAuth2UserData, "last_name"); - } - - @Override - public String getEmail(OAuth2UserData oAuth2UserData) { - return oAuth2UserData.getData("email"); - } - - private String getAttribute(OAuth2UserData oAuth2UserData, String name) { - List> attributesResponse = oAuth2UserData.getData("response"); - if (attributesResponse != null) { - Map attributes = attributesResponse.get(0); - if (attributes != null) { - return (String) attributes.get(name); - } - } - return null; - } -} diff --git a/src/main/java/com/javarush/jira/login/internal/sociallogin/handler/YandexOAuth2UserDataHandler.java b/src/main/java/com/javarush/jira/login/internal/sociallogin/handler/YandexOAuth2UserDataHandler.java deleted file mode 100644 index e8ea1ac1d..000000000 --- a/src/main/java/com/javarush/jira/login/internal/sociallogin/handler/YandexOAuth2UserDataHandler.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.javarush.jira.login.internal.sociallogin.handler; - -import org.springframework.stereotype.Component; - -@Component("yandex") -public class YandexOAuth2UserDataHandler implements OAuth2UserDataHandler { - @Override - public String getFirstName(OAuth2UserData oAuth2UserData) { - return oAuth2UserData.getData("first_name"); - } - - @Override - public String getLastName(OAuth2UserData oAuth2UserData) { - return oAuth2UserData.getData("last_name"); - } - - @Override - public String getEmail(OAuth2UserData oAuth2UserData) { - return oAuth2UserData.getData("default_email"); - } -} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 7fcba1570..d9660eb05 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -61,20 +61,6 @@ spring: scope: - email - profile - vk: - client-id: 51562377 - client-secret: jNM1YHQy1362Mqs49wUN - client-name: Vkontakte - redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}" - client-authentication-method: client_secret_post - authorization-grant-type: authorization_code - scope: email - yandex: - client-id: 2f3395214ba84075956b76a34b231985 - client-secret: ed236c501e444a609b0f419e5e88f1e1 - client-name: Yandex - redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}" - authorization-grant-type: authorization_code gitlab: client-id: b8520a3266089063c0d8261cce36971defa513f5ffd9f9b7a3d16728fc83a494 client-secret: e72c65320cf9d6495984a37b0f9cc03ec46be0bb6f071feaebbfe75168117004 @@ -83,16 +69,6 @@ spring: authorization-grant-type: authorization_code scope: read_user provider: - vk: - authorization-uri: https://oauth.vk.com/authorize - token-uri: https://oauth.vk.com/access_token - user-info-uri: https://api.vk.com/method/users.get?v=8.1 - user-name-attribute: response - yandex: - authorization-uri: https://oauth.yandex.ru/authorize - token-uri: https://oauth.yandex.ru/token - user-info-uri: https://login.yandex.ru/info - user-name-attribute: login gitlab: authorization-uri: https://gitlab.com/oauth/authorize token-uri: https://gitlab.com/oauth/token diff --git a/src/main/resources/data4dev/data.sql b/src/main/resources/data4dev/data.sql index a7d43cbad..28b494155 100644 --- a/src/main/resources/data4dev/data.sql +++ b/src/main/resources/data4dev/data.sql @@ -54,8 +54,7 @@ values (1, 'skype', 'userSkype'), (1, 'mobile', '+01234567890'), (1, 'website', 'user.com'), (2, 'github', 'adminGitHub'), - (2, 'tg', 'adminTg'), - (2, 'vk', 'adminVk'); + (2, 'tg', 'adminTg'); delete from ATTACHMENT; diff --git a/src/main/resources/db/changelog.sql b/src/main/resources/db/changelog.sql index 68591336d..1595f97d3 100644 --- a/src/main/resources/db/changelog.sql +++ b/src/main/resources/db/changelog.sql @@ -218,7 +218,6 @@ values ('task', 'Task', 2), ('mobile', 'Mobile', 0), ('phone', 'Phone', 0), ('website', 'Website', 0), - ('vk', 'VK', 0), ('linkedin', 'LinkedIn', 0), ('github', 'GitHub', 0), -- PRIORITY diff --git a/src/test/java/com/javarush/jira/profile/internal/web/ProfileTestData.java b/src/test/java/com/javarush/jira/profile/internal/web/ProfileTestData.java index fb4407268..cc0513971 100644 --- a/src/test/java/com/javarush/jira/profile/internal/web/ProfileTestData.java +++ b/src/test/java/com/javarush/jira/profile/internal/web/ProfileTestData.java @@ -44,7 +44,6 @@ public static ProfileTo getUpdatedTo() { new ContactTo("website", "new.com"), new ContactTo("github", "newGitHub"), new ContactTo("tg", "newTg"), - new ContactTo("vk", "newVk"), new ContactTo("linkedin", "newLinkedin"))); } @@ -57,7 +56,6 @@ public static Profile getUpdated(long id) { new Contact(id, "website", "new.com"), new Contact(id, "github", "newGitHub"), new Contact(id, "tg", "newTg"), - new Contact(id, "vk", "newVk"), new Contact(id, "linkedin", "newLinkedin"))); return profile; } diff --git a/src/test/resources/data.sql b/src/test/resources/data.sql index 5087dbddc..bc26161e4 100644 --- a/src/test/resources/data.sql +++ b/src/test/resources/data.sql @@ -53,8 +53,7 @@ values (1, 'skype', 'userSkype'), (1, 'mobile', '+01234567890'), (1, 'website', 'user.com'), (2, 'github', 'adminGitHub'), - (2, 'tg', 'adminTg'), - (2, 'vk', 'adminVk'); + (2, 'tg', 'adminTg'); insert into PROJECT (code, title, description, type_code, parent_id) From fd1e4c9415833bcecfd672d19b42a2c10d704cae Mon Sep 17 00:00:00 2001 From: Dezolus Date: Sat, 7 Sep 2024 12:57:14 +0300 Subject: [PATCH 02/12] Task 2 done(fixed sql script) --- src/main/resources/data4dev/data.sql | 3 ++- src/main/resources/db/changelog.sql | 1 + src/test/resources/data.sql | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/resources/data4dev/data.sql b/src/main/resources/data4dev/data.sql index 28b494155..a7d43cbad 100644 --- a/src/main/resources/data4dev/data.sql +++ b/src/main/resources/data4dev/data.sql @@ -54,7 +54,8 @@ values (1, 'skype', 'userSkype'), (1, 'mobile', '+01234567890'), (1, 'website', 'user.com'), (2, 'github', 'adminGitHub'), - (2, 'tg', 'adminTg'); + (2, 'tg', 'adminTg'), + (2, 'vk', 'adminVk'); delete from ATTACHMENT; diff --git a/src/main/resources/db/changelog.sql b/src/main/resources/db/changelog.sql index 1595f97d3..68591336d 100644 --- a/src/main/resources/db/changelog.sql +++ b/src/main/resources/db/changelog.sql @@ -218,6 +218,7 @@ values ('task', 'Task', 2), ('mobile', 'Mobile', 0), ('phone', 'Phone', 0), ('website', 'Website', 0), + ('vk', 'VK', 0), ('linkedin', 'LinkedIn', 0), ('github', 'GitHub', 0), -- PRIORITY diff --git a/src/test/resources/data.sql b/src/test/resources/data.sql index bc26161e4..5087dbddc 100644 --- a/src/test/resources/data.sql +++ b/src/test/resources/data.sql @@ -53,7 +53,8 @@ values (1, 'skype', 'userSkype'), (1, 'mobile', '+01234567890'), (1, 'website', 'user.com'), (2, 'github', 'adminGitHub'), - (2, 'tg', 'adminTg'); + (2, 'tg', 'adminTg'), + (2, 'vk', 'adminVk'); insert into PROJECT (code, title, description, type_code, parent_id) From 4f58fa6715fd096322616952a29101955837fd92 Mon Sep 17 00:00:00 2001 From: Dezolus Date: Sat, 7 Sep 2024 13:00:32 +0300 Subject: [PATCH 03/12] Task 3 done --- src/main/resources/application.yaml | 47 ++------------------------- src/main/resources/secrets.yaml | 49 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 45 deletions(-) create mode 100644 src/main/resources/secrets.yaml diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index d9660eb05..c1273ec83 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -1,13 +1,14 @@ # https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html app: host-url: http://localhost:8080 - test-mail: jira4jr@gmail.com templates-update-cache: 5s mail-sending-props: core-pool-size: 8 max-pool-size: 100 spring: + config: + import: classpath:secrets.yaml init: mode: never jpa: @@ -25,10 +26,6 @@ spring: default_batch_fetch_size: 20 # https://stackoverflow.com/questions/21257819/what-is-the-difference-between-hibernate-jdbc-fetch-size-and-hibernate-jdbc-batc jdbc.batch_size: 20 - datasource: - url: jdbc:postgresql://localhost:5432/jira - username: jira - password: JiraRush liquibase: changeLog: "classpath:db/changelog.sql" @@ -46,50 +43,10 @@ spring: cache-names: users caffeine.spec: maximumSize=10000,expireAfterAccess=5m - 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 - sql: init: mode: always - mail: - properties: - mail: - smtp: - starttls: - enable: true - auth: true - host: smtp.gmail.com - username: jira4jr@gmail.com - password: zdfzsrqvgimldzyj - port: 587 thymeleaf.check-template-location: false mvc.throw-exception-if-no-handler-found: true diff --git a/src/main/resources/secrets.yaml b/src/main/resources/secrets.yaml new file mode 100644 index 000000000..ea14d923f --- /dev/null +++ b/src/main/resources/secrets.yaml @@ -0,0 +1,49 @@ +app: + test-mail: ${APP_TEST_MAIL:jira4jr@gmail.com} + +spring: + datasource: + url: ${DEV_DATABASE_URL:jdbc:postgresql://localhost:5432/jira} + username: ${DEV_DATABASE_USERNAME:jira} + password: ${DEV_DATABASE_PASSWORD:JiraRush} + security: + oauth2: + client: + registration: + github: + client-id: ${GITHUB_CLIENT_ID:3d0d8738e65881fff266} + client-secret: ${GITHUB_CLIENT_SECRET:0f97031ce6178b7dfb67a6af587f37e222a16120} + scope: + - email + google: + client-id: ${GOOGLE_CLIENT_ID:329113642700-f8if6pu68j2repq3ef6umd5jgiliup60.apps.googleusercontent.com} + client-secret: ${GOOGLE_CLIENT_SECRET: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} + scope: + - email + - profile + gitlab: + client-id: ${GITLAB_CLIENT_ID:b8520a3266089063c0d8261cce36971defa513f5ffd9f9b7a3d16728fc83a494} + client-secret: ${GITLAB_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: ${MAIL_HOST:smtp.gmail.com} + username: ${MAIL_USERNAME:jira4jr@gmail.com} + password: ${MAIL_PASSWORD:zdfzsrqvgimldzyj} + port: ${MAIL_PORT:587} \ No newline at end of file From fc7085c3afee71ab79a869b5bdb8b47a1fdca71d Mon Sep 17 00:00:00 2001 From: Dezolus Date: Sat, 7 Sep 2024 19:17:32 +0300 Subject: [PATCH 04/12] Task 4 added postgres testContainer, Task 5 done. --- pom.xml | 27 ++++ .../java/com/javarush/jira/BaseTests.java | 28 +++- .../web/ProfileRestControllerTest.java | 126 ++++++++++++++++++ .../profile/internal/web/ProfileTestData.java | 3 + 4 files changed, 183 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8b89f90eb..b0529bb0d 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,18 @@ UTF-8 + + + + org.testcontainers + testcontainers-bom + 1.20.1 + pom + import + + + + org.springframework.boot @@ -143,6 +155,21 @@ junit-platform-launcher test + + org.testcontainers + postgresql + test + + + org.testcontainers + junit-jupiter + test + + + org.testcontainers + testcontainers + test + diff --git a/src/test/java/com/javarush/jira/BaseTests.java b/src/test/java/com/javarush/jira/BaseTests.java index b6ed2d1aa..2c979b63b 100644 --- a/src/test/java/com/javarush/jira/BaseTests.java +++ b/src/test/java/com/javarush/jira/BaseTests.java @@ -1,9 +1,35 @@ package com.javarush.jira; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.PostgreSQLContainer; -@SpringBootTest +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles("test") abstract class BaseTests { + + + static PostgreSQLContainer postgres = new PostgreSQLContainer<>( + "postgres:16-alpine"); + + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.datasource.url", postgres::getJdbcUrl); + registry.add("spring.datasource.username", postgres::getUsername); + registry.add("spring.datasource.password", postgres::getPassword); + } + + @BeforeAll + static void setup() { + postgres.start(); + } + @AfterAll + static void tearDown() { + postgres.stop(); + } } diff --git a/src/test/java/com/javarush/jira/profile/internal/web/ProfileRestControllerTest.java b/src/test/java/com/javarush/jira/profile/internal/web/ProfileRestControllerTest.java index a6fd5e3bf..0dcd33d87 100644 --- a/src/test/java/com/javarush/jira/profile/internal/web/ProfileRestControllerTest.java +++ b/src/test/java/com/javarush/jira/profile/internal/web/ProfileRestControllerTest.java @@ -1,8 +1,134 @@ package com.javarush.jira.profile.internal.web; import com.javarush.jira.AbstractControllerTest; +import com.javarush.jira.common.util.JsonUtil; +import com.javarush.jira.login.AuthUser; +import com.javarush.jira.profile.ProfileTo; +import com.javarush.jira.profile.internal.ProfileMapper; +import com.javarush.jira.profile.internal.ProfileRepository; +import com.javarush.jira.profile.internal.model.Profile; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithUserDetails; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import static com.javarush.jira.login.internal.web.UserTestData.GUEST_MAIL; +import static com.javarush.jira.login.internal.web.UserTestData.USER_MAIL; +import static com.javarush.jira.profile.internal.web.ProfileTestData.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; class ProfileRestControllerTest extends AbstractControllerTest { + private static final String REST_URL = ProfileRestController.REST_URL; + + @Autowired + ProfileMapper profileMapper; + @Autowired + ProfileRepository profileRepository; + + @Test + @WithUserDetails(value = USER_MAIL) + void shouldGetProfile() throws Exception { + perform(MockMvcRequestBuilders.get(REST_URL)) + .andExpect(status().isOk()) + .andDo(print()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(PROFILE_TO_MATCHER.contentJson(USER_PROFILE_TO)); + } + + @Test + @WithUserDetails(value = GUEST_MAIL) + void shouldGetGuestProfile() throws Exception { + perform(MockMvcRequestBuilders.get(REST_URL)) + .andExpect(status().isOk()) + .andDo(print()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(PROFILE_TO_MATCHER.contentJson(GUEST_PROFILE_EMPTY_TO)); + } + + @Test + void getUnAuthorized() throws Exception { + perform(MockMvcRequestBuilders.get(REST_URL)) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithUserDetails(value = USER_MAIL) + void getNewProfile() throws Exception { + AuthUser auth = AuthUser.safeGet(); + Profile newProfile = ProfileTestData.getNew(auth.id()); + profileRepository.save(newProfile); + + ResultActions resultActions = perform(MockMvcRequestBuilders.get(REST_URL)) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + ProfileTo resp = PROFILE_TO_MATCHER.readFromJson(resultActions); + ProfileTo newProfileTo = ProfileTestData.getNewTo(); + newProfileTo.setId(resp.getId()); + PROFILE_TO_MATCHER.assertMatch(resp, newProfileTo); + } + + @Test + @WithUserDetails(value = USER_MAIL) + void shouldUpdateProfile() throws Exception { + AuthUser auth = AuthUser.safeGet(); + ProfileTo updatedTo = ProfileTestData.getUpdatedTo(); + updatedTo.setId(auth.id()); + perform(MockMvcRequestBuilders.put(REST_URL) + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.writeValue(updatedTo))) + .andExpect(status().isNoContent()); + + Profile updatedInRepo = profileRepository.findById(updatedTo.id()).get(); + Profile updatedFromRepo = ProfileTestData.getUpdated(auth.id()); + PROFILE_MATCHER.assertMatch(updatedInRepo, updatedFromRepo); + } + + @Test + @WithUserDetails(value = USER_MAIL) + void updateInvalidProfileTo() throws Exception { + ProfileTo invalidTo = ProfileTestData.getInvalidTo(); + perform(MockMvcRequestBuilders.put(REST_URL) + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.writeValue(invalidTo))) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + @WithUserDetails(value = USER_MAIL) + void updateWithUnknownNotification() throws Exception { + ProfileTo invalidTo = ProfileTestData.getWithUnknownNotificationTo(); + perform(MockMvcRequestBuilders.put(REST_URL) + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.writeValue(invalidTo))) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + @WithUserDetails(value = USER_MAIL) + void updateWithUnknownContactTo() throws Exception { + ProfileTo invalidTo = ProfileTestData.getWithUnknownContactTo(); + perform(MockMvcRequestBuilders.put(REST_URL) + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.writeValue(invalidTo))) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + @WithUserDetails(value = USER_MAIL) + void updateWithUnsafeContactHTML() throws Exception { + ProfileTo profileTo = ProfileTestData.getWithContactHtmlUnsafeTo(); + perform(MockMvcRequestBuilders.put(REST_URL) + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.writeValue(profileTo))) + .andExpect(status().isUnprocessableEntity()); + } + + } \ No newline at end of file diff --git a/src/test/java/com/javarush/jira/profile/internal/web/ProfileTestData.java b/src/test/java/com/javarush/jira/profile/internal/web/ProfileTestData.java index cc0513971..3ed6d8424 100644 --- a/src/test/java/com/javarush/jira/profile/internal/web/ProfileTestData.java +++ b/src/test/java/com/javarush/jira/profile/internal/web/ProfileTestData.java @@ -13,6 +13,9 @@ public class ProfileTestData { public static MatcherFactory.Matcher PROFILE_MATCHER = MatcherFactory.usingIgnoringFieldsComparator(Profile.class, "user"); + public static MatcherFactory.Matcher PROFILE_TO_MATCHER = + MatcherFactory.usingIgnoringFieldsComparator(ProfileTo.class, "id"); + public static ProfileTo USER_PROFILE_TO = new ProfileTo(null, Set.of("assigned", "overdue", "deadline"), Set.of(new ContactTo("skype", "userSkype"), From d6c571bd8bc1ba9d2afe8c5f110c46cd6a3a8190 Mon Sep 17 00:00:00 2001 From: Dezolus Date: Sat, 7 Sep 2024 19:45:56 +0300 Subject: [PATCH 05/12] Task 6 done. --- .../jira/bugtracking/attachment/FileUtil.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/javarush/jira/bugtracking/attachment/FileUtil.java b/src/main/java/com/javarush/jira/bugtracking/attachment/FileUtil.java index 6cffbe175..58b48a5e9 100644 --- a/src/main/java/com/javarush/jira/bugtracking/attachment/FileUtil.java +++ b/src/main/java/com/javarush/jira/bugtracking/attachment/FileUtil.java @@ -7,14 +7,13 @@ import org.springframework.core.io.UrlResource; import org.springframework.web.multipart.MultipartFile; -import java.io.File; -import java.io.FileOutputStream; + import java.io.IOException; -import java.io.OutputStream; import java.net.MalformedURLException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; @UtilityClass public class FileUtil { @@ -24,15 +23,18 @@ public static void upload(MultipartFile multipartFile, String directoryPath, Str if (multipartFile.isEmpty()) { throw new IllegalRequestDataException("Select a file to upload."); } + Path path = Path.of(directoryPath, fileName); - 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 { + if (!Files.exists(path)) { + Files.createDirectories(path); } + Path filePath = path.resolve(fileName); + + Files.copy(multipartFile.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING); + + } catch (IOException e) { + throw new IllegalRequestDataException("Failed to upload file" + multipartFile.getOriginalFilename()); } } From 90c846c99180a16eb150ee4f64669e5e2592d726 Mon Sep 17 00:00:00 2001 From: Dezolus Date: Sat, 7 Sep 2024 23:28:42 +0300 Subject: [PATCH 06/12] Task 7 done.(no front) --- .../jira/bugtracking/task/TaskController.java | 19 +++++++++++++++++++ .../jira/bugtracking/task/TaskService.java | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/main/java/com/javarush/jira/bugtracking/task/TaskController.java b/src/main/java/com/javarush/jira/bugtracking/task/TaskController.java index b53f7ff37..9bef228f4 100644 --- a/src/main/java/com/javarush/jira/bugtracking/task/TaskController.java +++ b/src/main/java/com/javarush/jira/bugtracking/task/TaskController.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import java.util.Set; import static com.javarush.jira.common.BaseHandler.createdResponse; @@ -156,4 +157,22 @@ public TaskTreeNode(TaskTo taskTo) { this(taskTo, new LinkedList<>()); } } + + @PutMapping("/{id}/tags") + public void addTag(@PathVariable long id, @RequestParam Set tags) { + log.info("added tags for task {}: {}", id, tags); + taskService.addTags(id, tags); + } + + @PatchMapping("/{id}/tags") + public void updateTag(@PathVariable long id, @RequestParam Set tags) { + log.info("updated tags for task {}: {}", id, tags); + taskService.updateTag(id, tags); + } + + @DeleteMapping("/{id}/tags") + public void deleteTags(@PathVariable long id, @RequestParam Set tags) { + log.info("deleted tags from task {}: {}", id, tags); + taskService.deleteTags(id, tags); + } } diff --git a/src/main/java/com/javarush/jira/bugtracking/task/TaskService.java b/src/main/java/com/javarush/jira/bugtracking/task/TaskService.java index e6f385548..ea61afa35 100644 --- a/src/main/java/com/javarush/jira/bugtracking/task/TaskService.java +++ b/src/main/java/com/javarush/jira/bugtracking/task/TaskService.java @@ -21,6 +21,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Set; import static com.javarush.jira.bugtracking.ObjectType.TASK; import static com.javarush.jira.bugtracking.task.TaskUtil.fillExtraFields; @@ -86,6 +87,23 @@ public void update(TaskToExt taskTo, long id) { } } + public void addTags(long taskId, Set tag) { + Task task = handler.getRepository().getExisted(taskId); + task.getTags().addAll(tag); + handler.getRepository().save(task); + } + + public void updateTag(long taskId, Set tag) { + Task task = handler.getRepository().getExisted(taskId); + task.setTags(tag); + handler.getRepository().save(task); + } + + public void deleteTags(long taskId, Set tag) { + Task task = handler.getRepository().getExisted(taskId); + task.getTags().removeAll(tag); + } + public TaskToFull get(long id) { Task task = Util.checkExist(id, handler.getRepository().findFullById(id)); TaskToFull taskToFull = fullMapper.toTo(task); From 2edb58cc932ff2017d52447f15f58dd0a2b6af1b Mon Sep 17 00:00:00 2001 From: Dezolus Date: Sun, 8 Sep 2024 14:15:41 +0300 Subject: [PATCH 07/12] Task 8 done. --- .../jira/bugtracking/task/TaskController.java | 12 ++++++ .../jira/bugtracking/task/TaskService.java | 38 +++++++++++++++++++ src/main/resources/db/changelog.sql | 5 +++ 3 files changed, 55 insertions(+) diff --git a/src/main/java/com/javarush/jira/bugtracking/task/TaskController.java b/src/main/java/com/javarush/jira/bugtracking/task/TaskController.java index 9bef228f4..4ffa1738c 100644 --- a/src/main/java/com/javarush/jira/bugtracking/task/TaskController.java +++ b/src/main/java/com/javarush/jira/bugtracking/task/TaskController.java @@ -175,4 +175,16 @@ public void deleteTags(@PathVariable long id, @RequestParam Set tags) { log.info("deleted tags from task {}: {}", id, tags); taskService.deleteTags(id, tags); } + + @GetMapping("/{id}/devTime") + public void getDevelopmentTime(@PathVariable long id) { + log.info("get dev time for task with id={}", id); + taskService.developmentTime(id); + } + + @GetMapping("/{id}/testTime") + public void getTestTime(@PathVariable long id) { + log.info("get test time for task with id={}", id); + taskService.testingTime(id); + } } diff --git a/src/main/java/com/javarush/jira/bugtracking/task/TaskService.java b/src/main/java/com/javarush/jira/bugtracking/task/TaskService.java index ea61afa35..e00bd2644 100644 --- a/src/main/java/com/javarush/jira/bugtracking/task/TaskService.java +++ b/src/main/java/com/javarush/jira/bugtracking/task/TaskService.java @@ -19,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; +import java.time.Duration; import java.time.LocalDateTime; import java.util.List; import java.util.Set; @@ -99,6 +100,42 @@ public void updateTag(long taskId, Set tag) { handler.getRepository().save(task); } + public long developmentTime(long taskId) { + List activities = handler.getRepository().getExisted(taskId).getActivities(); + LocalDateTime startTime = null; + LocalDateTime endTime = null; + + for (Activity activity : activities) { + if (activity.getStatusCode() == null) + continue; + + if (activity.getStatusCode().equals("in_progress")) { + startTime = activity.getUpdated(); + } else if (activity.getStatusCode().equals("ready_for_review")) { + endTime = activity.getUpdated(); + } + } + return (startTime != null && endTime != null) ? Duration.between(startTime, endTime).toMinutes() : 0; + } + + public long testingTime(long taskId) { + List activities = handler.getRepository().getExisted(taskId).getActivities(); + LocalDateTime startTime = null; + LocalDateTime endTime = null; + + for (Activity activity : activities) { + if (activity.getStatusCode() == null) + continue; + + if (activity.getStatusCode().equals("ready_for_review")) { + startTime = activity.getUpdated(); + } else if (activity.getStatusCode().equals("done")) { + endTime = activity.getUpdated(); + } + } + return (startTime != null && endTime != null) ? Duration.between(startTime, endTime).toMinutes() : 0; + } + public void deleteTags(long taskId, Set tag) { Task task = handler.getRepository().getExisted(taskId); task.getTags().removeAll(tag); @@ -158,4 +195,5 @@ private void checkAssignmentActionPossible(long id, String userType, boolean ass throw new DataConflictException(String.format(assign ? CANNOT_ASSIGN : CANNOT_UN_ASSIGN, userType, task.getStatusCode())); } } + } diff --git a/src/main/resources/db/changelog.sql b/src/main/resources/db/changelog.sql index 68591336d..9b9a634c1 100644 --- a/src/main/resources/db/changelog.sql +++ b/src/main/resources/db/changelog.sql @@ -329,3 +329,8 @@ values ('todo', 'ToDo', 3, 'in_progress,canceled|'), drop index UK_USER_BELONG; create unique index UK_USER_BELONG on USER_BELONG (OBJECT_ID, OBJECT_TYPE, USER_ID, USER_TYPE_CODE) where ENDPOINT is null; + +insert into ACTIVITY ( ID, AUTHOR_ID, TASK_ID, UPDATED, STATUS_CODE ) +values (nextval('activity_id_seq'), 1,1, '2023-05-17 12:05:10', 'in_progress'), + (nextval('activity_id_seq'), 1,1, '2023-05-16 10:05:10', 'ready_for_review'), + (nextval('activity_id_seq'), 1,1, '2023-05-15 02:05:10', 'done'); \ No newline at end of file From 4d8a0109a54992279a3e2b214e2ef4614120890c Mon Sep 17 00:00:00 2001 From: Dezolus Date: Mon, 9 Sep 2024 19:13:23 +0300 Subject: [PATCH 08/12] Task 9 done. Added clear-checksums for sql changes --- Dockerfile | 16 ++++++++++++++++ src/main/resources/application.yaml | 1 + 2 files changed, 17 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..c0cdb0512 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM openjdk:17-jdk-alpine + +WORKDIR /app + +COPY pom.xml ./pom.xml +RUN apk add --no-cache maven +RUN mvn dependency:go-offline -B +COPY src ./src +COPY resources ./resources + +RUN mvn clean package -Pprod + +EXPOSE 8080 + +ENTRYPOINT ["java", "-jar", "--spring.profiles.active=prod", "app/target/jira.jar"] + diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index c1273ec83..d35037375 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -28,6 +28,7 @@ spring: jdbc.batch_size: 20 liquibase: + clear-checksums: true changeLog: "classpath:db/changelog.sql" # Jackson Fields Serialization From 5df135ba8c0841c57c8f31b0d598c134e9e4aabb Mon Sep 17 00:00:00 2001 From: Dezolus Date: Tue, 10 Sep 2024 00:19:06 +0300 Subject: [PATCH 09/12] Task 10 done. Fixed Dockerfile. --- Dockerfile | 5 ++--- config/nginx.conf | 2 +- dc-prop.env | 4 ++++ docker-compose.yaml | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 dc-prop.env create mode 100644 docker-compose.yaml diff --git a/Dockerfile b/Dockerfile index c0cdb0512..21fc085cb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,9 @@ -FROM openjdk:17-jdk-alpine +FROM maven:3.8.5-openjdk-17 AS build WORKDIR /app + COPY pom.xml ./pom.xml -RUN apk add --no-cache maven -RUN mvn dependency:go-offline -B COPY src ./src COPY resources ./resources diff --git a/config/nginx.conf b/config/nginx.conf index 82b9e234d..634d2c528 100644 --- a/config/nginx.conf +++ b/config/nginx.conf @@ -10,7 +10,7 @@ server { gzip_min_length 2048; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - root /opt/jirarush/resources; + root /resources; if ($request_uri ~ ';') {return 404;} diff --git a/dc-prop.env b/dc-prop.env new file mode 100644 index 000000000..b2a57682f --- /dev/null +++ b/dc-prop.env @@ -0,0 +1,4 @@ + +POSTGRES_DB_URL=jdbc:postgresql://db:5432/jira +POSTGRES_DB_USER=jira +POSTGRES_DB_PASSWORD=JiraRush diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 000000000..631dc8ff8 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,40 @@ +version: '3.8' + +services: + app: + container_name: app_container + image: jira:latest + build: + context: . + dockerfile: Dockerfile + ports: + - "8080:8080" + env_file: + - dc-prop.env + depends_on: + - db + - nginx + restart: always + + + db: + container_name: db_container + image: postgres:latest + environment: + POSTGRES_USER: jira + POSTGRES_PASSWORD: JiraRush + ports: + - "5432:5432" + volumes: + - ./data/db:/var/lib/postgresql/data + restart: always + + + nginx: + container_name: nginx_container + image: nginx:latest + ports: + - "80:80" + volumes: + - ./config/nginx.conf:/etc/nginx/nginx.conf + restart: always \ No newline at end of file From 357d02310fe944e446bbdd16658aa1560c04c194 Mon Sep 17 00:00:00 2001 From: Dezolus Date: Tue, 10 Sep 2024 16:45:22 +0300 Subject: [PATCH 10/12] Task 11 done. --- resources/mails/email-confirmation.html | 10 +-- resources/mails/password-reset.html | 10 +-- resources/view/index.html | 16 ++++- resources/view/layout/footer.html | 44 ++++++------ resources/view/layout/header.html | 11 +-- resources/view/layout/sidebar.html | 20 +++--- resources/view/login.html | 22 +++--- .../common/internal/config/LocaleConfig.java | 35 ++++++++++ src/main/resources/application.yaml | 1 - src/main/resources/messages.properties | 67 +++++++++++++++++++ src/main/resources/messages_en.properties | 59 ++++++++++++++++ src/main/resources/messages_es.properties | 58 ++++++++++++++++ src/main/resources/messages_ru.properties | 58 ++++++++++++++++ 13 files changed, 349 insertions(+), 62 deletions(-) create mode 100644 src/main/java/com/javarush/jira/common/internal/config/LocaleConfig.java create mode 100644 src/main/resources/messages.properties create mode 100644 src/main/resources/messages_en.properties create mode 100644 src/main/resources/messages_es.properties create mode 100644 src/main/resources/messages_ru.properties diff --git a/resources/mails/email-confirmation.html b/resources/mails/email-confirmation.html index 106e6129a..4993bf8c1 100644 --- a/resources/mails/email-confirmation.html +++ b/resources/mails/email-confirmation.html @@ -1,13 +1,13 @@ - + - JiraRush - подтверждение почты + JiraRush - подтверждение почты -

-

Чтобы завершить настройку учетной записи и начать пользоваться JiraRush, подтвердите, что вы правильно указали вашу +

+

Чтобы завершить настройку учетной записи и начать пользоваться JiraRush, подтвердите, что вы правильно указали вашу электронную почту.

-Подтвердить почту +Подтвердить почту \ No newline at end of file diff --git a/resources/mails/password-reset.html b/resources/mails/password-reset.html index b37a49007..36d4e26d8 100644 --- a/resources/mails/password-reset.html +++ b/resources/mails/password-reset.html @@ -1,12 +1,12 @@ - + - JiraRush - установить новый пароль + JiraRush - установить новый пароль -

-

-Установить пароль +

+

+Установить пароль \ No newline at end of file diff --git a/resources/view/index.html b/resources/view/index.html index e8656ef96..f1f41c11a 100644 --- a/resources/view/index.html +++ b/resources/view/index.html @@ -1,13 +1,23 @@ - + -

JiraRush Home page

+

JiraRush Home page

+
+
+ + +
+
- +
diff --git a/resources/view/layout/footer.html b/resources/view/layout/footer.html index abd5ae968..67c9aea78 100644 --- a/resources/view/layout/footer.html +++ b/resources/view/layout/footer.html @@ -1,5 +1,5 @@ - +
diff --git a/resources/view/layout/header.html b/resources/view/layout/header.html index 451f9652d..929bda86e 100644 --- a/resources/view/layout/header.html +++ b/resources/view/layout/header.html @@ -1,15 +1,16 @@ - +