Skip to content
Open

pull #71

Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ logs
attachments
*.patch


src/main/resources/application.properties
src/test/resources/application-test.properties
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM openjdk:17

WORKDIR /app

COPY target/jira-1.0.jar /app/final-jira.jar
COPY src/main/resources/application.properties src/main/resources/application.properties

EXPOSE 8080

CMD ["java", "-jar", "/app/final-jira.jar"]
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,12 @@
- https://habr.com/ru/articles/259055/

Список выполненных задач:
...
1. Розібратися зі структурою проєкту (onboarding).
2. Видалити соціальні мережі: vk, yandex.
3. Винести чутливу інформацію до окремого проперті файлу
4. H2
5. Написати тести для всіх публічних методів контролера ProfileRestController
6. Сучасний підхід для роботи з файловою системою
7. Додавання тегів до завдання (REST API + реалізація на сервісі)
8. Додати підрахунок часу
9. Написати Dockerfile для основного сервера
2 changes: 1 addition & 1 deletion config/_application-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ app:
host-url: http://localhost
spring:
datasource:
url: jdbc:postgresql://localhost:5432/jira
url: jdbc:postgresql://localhost:5433/jira
username: jira
password: JiraRush

6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@
<version>1.15.3</version>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.220</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down
12 changes: 0 additions & 12 deletions resources/static/fontawesome/css/all.css
Original file line number Diff line number Diff line change
Expand Up @@ -8603,10 +8603,6 @@ readers do not read off random characters that represent icons */
content: "\f3e8";
}

.fa-vk:before {
content: "\f189";
}

.fa-untappd:before {
content: "\f405";
}
Expand Down Expand Up @@ -9955,10 +9951,6 @@ readers do not read off random characters that represent icons */
content: "\f3bc";
}

.fa-yandex:before {
content: "\f413";
}

.fa-readme:before {
content: "\f4d5";
}
Expand Down Expand Up @@ -10183,10 +10175,6 @@ readers do not read off random characters that represent icons */
content: "\f7c6";
}

.fa-yandex-international:before {
content: "\f414";
}

.fa-cc-amex:before {
content: "\f1f3";
}
Expand Down
2 changes: 1 addition & 1 deletion resources/static/fontawesome/css/all.min.css

Large diffs are not rendered by default.

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
8 changes: 0 additions & 8 deletions resources/view/unauth/register.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,6 @@ <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 @@ -7,10 +7,7 @@
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;
Expand All @@ -25,14 +22,13 @@ 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());
}
Path paths = Path.of(directoryPath);
try {
Files.createDirectories(paths);
Path filePath = paths.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,9 +5,12 @@
import com.javarush.jira.common.error.DataConflictException;
import com.javarush.jira.login.AuthUser;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.time.DurationFormatUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;

import static com.javarush.jira.bugtracking.task.TaskUtil.getLatestValue;
Expand All @@ -19,6 +22,10 @@ public class ActivityService {

private final Handlers.ActivityHandler handler;

public static final String IN_PROGRESS = "in_progress";
public static final String READY_FOR_REVIEW = "ready_for_review";
public static final String DONE = "done";

private static void checkBelong(HasAuthorId activity) {
if (activity.getAuthorId() != AuthUser.authId()) {
throw new DataConflictException("Activity " + activity.getId() + " doesn't belong to " + AuthUser.get());
Expand Down Expand Up @@ -73,4 +80,28 @@ private void updateTaskIfRequired(long taskId, String activityStatus, String act
}
}
}

private LocalDateTime getUpdatedTimeForStatus(long taskId, String statusCode) {
handler.getRepository().getExisted(taskId);
List<Activity> activities = handler.getRepository().findAllByTaskIdOrderByUpdatedDesc(taskId);
if (activities.isEmpty()) {
throw new DataConflictException(String.format("No activities found for task '%d'", taskId));
}

for (Activity activity : activities) {
if (statusCode.equals(activity.getStatusCode())) {
return activity.getUpdated();
}
}
throw new DataConflictException(String.format("No updated time found for status '%s' on task '%d'", statusCode, taskId));
}

public String calculateTaskDuration(long taskId, String startStatusCode, String endStatusCode) {
LocalDateTime startTime = getUpdatedTimeForStatus(taskId, startStatusCode);
LocalDateTime endTime = getUpdatedTimeForStatus(taskId, endStatusCode);

Duration duration = Duration.between(startTime, endTime);

return DurationFormatUtils.formatDuration(duration.toMillis(), "H:mm:ss", true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,10 @@ public TaskTreeNode(TaskTo taskTo) {
this(taskTo, new LinkedList<>());
}
}

@PostMapping("tags/{tagId}")
@ResponseStatus(HttpStatus.CREATED)
public void addTag(@PathVariable long tagId, @RequestBody String taskTag){
taskService.addTag(tagId, taskTag);
}
}
15 changes: 15 additions & 0 deletions src/main/java/com/javarush/jira/bugtracking/task/TaskService.java
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,19 @@ private void checkAssignmentActionPossible(long id, String userType, boolean ass
throw new DataConflictException(String.format(assign ? CANNOT_ASSIGN : CANNOT_UN_ASSIGN, userType, task.getStatusCode()));
}
}

@Transactional
public void addTag(long id, String tagName) {
if (id < 0) {
throw new IllegalArgumentException("Tag id cannot be negative");
}

Assert.hasText(tagName, "Tag name must not be empty");
Assert.notNull(tagName, "Tag name must not be null");

Task task = handler.getRepository().getExisted(id);
task.getTags().add(tagName);

handler.getRepository().saveAndFlush(task);
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class Contact implements HasId {

@NotBlank
@Size(min = 2, max = 256)
@Column(name = "value", nullable = false)
@Column(name = "val", nullable = false)
@NoHtml
private String value;

Expand Down
46 changes: 11 additions & 35 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# 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
host-url: ${HOST_URL}
test-mail: ${TEST_MAIL}
templates-update-cache: 5s
mail-sending-props:
core-pool-size: 8
Expand All @@ -26,9 +26,9 @@ spring:
# 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
url: ${DB_DATASOURCE}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}

liquibase:
changeLog: "classpath:db/changelog.sql"
Expand All @@ -51,48 +51,24 @@ spring:
client:
registration:
github:
client-id: 3d0d8738e65881fff266
client-secret: 0f97031ce6178b7dfb67a6af587f37e222a16120
client-id: ${GITHUB_CLIENT_ID}
client-secret: ${GITHUB_CLIENT_SECRET}
scope:
- email
google:
client-id: 329113642700-f8if6pu68j2repq3ef6umd5jgiliup60.apps.googleusercontent.com
client-secret: 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
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
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
client-id: ${GITLAB_CLIENT_ID}
client-secret: ${GITLAB_CLIENT_SECRET}
client-name: GitLab
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
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
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/data4dev/data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ insert into PROFILE (ID, LAST_FAILED_LOGIN, LAST_LOGIN, MAIL_NOTIFICATIONS)
values (1, null, null, 49),
(2, null, null, 14);

insert into CONTACT (ID, CODE, VALUE)
insert into CONTACT (ID, CODE, VAL)
values (1, 'skype', 'userSkype'),
(1, 'mobile', '+01234567890'),
(1, 'website', 'user.com'),
Expand Down
Loading