Skip to content
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ target
logs
attachments
*.patch
.env


9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,11 @@
- https://habr.com/ru/articles/259055/

Список выполненных задач:
...
1. Understand the project structure (onboarding).
2. Removed VK and Ya.
3. Introduce sensitive information to a specific file.
4. Change of tests from PostgreSQL to in-memory database.
5. Write tests for all public methods of the ProfileRestController controller.
6. Refactor the com.javarush.jira.bugtracking.attachment.FileUtil#upload method to use a modern approach to working with the file system.
7. Add new functionality: adding tags to a task (REST API + implementation on the service).
8. Add time counting: how much time the task has been in work and testing. Write 2 methods at the service level that take a task as a parameter and return the time spent.
12 changes: 12 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,18 @@
<optional>true</optional>
</dependency>

<dependency>
<groupId>me.paulschwarz</groupId>
<artifactId>spring-dotenv</artifactId>
<version>4.0.0</version>
</dependency>


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

<build>
Expand Down
9 changes: 0 additions & 9 deletions resources/static/fontawesome/css/all.css
Original file line number Diff line number Diff line change
Expand Up @@ -8603,9 +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,9 +9952,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,9 +10177,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
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,14 +7,9 @@
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.*;

@UtilityClass
public class FileUtil {
Expand All @@ -25,37 +20,36 @@ 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 dirPath = Paths.get(directoryPath);
try {
Files.createDirectories(dirPath);
Path filePath = dirPath.resolve(fileName);
Files.write(filePath, multipartFile.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
} catch (IOException ex) {
throw new IllegalRequestDataException("Failed to upload file: " + multipartFile.getOriginalFilename());
}
}

public static Resource download(String fileLink) {
Path path = Paths.get(fileLink);
try {
Resource resource = new UrlResource(path.toUri());
if (resource.exists() || resource.isReadable()) {
if (resource.exists() && resource.isReadable()) {
return resource;
} else {
throw new IllegalRequestDataException("Failed to download file " + resource.getFilename());
throw new IllegalRequestDataException("Failed to download file: " + resource.getFilename());
}
} catch (MalformedURLException ex) {
throw new NotFoundException("File" + fileLink + " not found");
throw new NotFoundException("File not found: " + fileLink);
}
}

public static void delete(String fileLink) {
Path path = Paths.get(fileLink);
try {
Files.delete(path);
Files.deleteIfExists(path);
} catch (IOException ex) {
throw new IllegalRequestDataException("File" + fileLink + " deletion failed.");
throw new IllegalRequestDataException("File deletion failed: " + fileLink);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
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 Down Expand Up @@ -73,4 +75,29 @@ private void updateTaskIfRequired(long taskId, String activityStatus, String act
}
}
}
public Duration getDurationInProgress(Task task) {
LocalDateTime inProgress = null;
LocalDateTime readyForReview = null;
List<Activity> activities = handler.getRepository().findAllByTaskIdOrderByUpdatedDesc(task.id());
for (Activity activity : activities) {
if ("in_progress".equals(activity.getStatusCode())) inProgress=activity.getUpdated();
if ("ready_for_review".equals(activity.getStatusCode())) readyForReview=activity.getUpdated();
}
if (inProgress==null||readyForReview==null) return Duration.ZERO;
else return Duration.between(inProgress, readyForReview);

}

public Duration getDurationInTesting(Task task) {
LocalDateTime done = null;
LocalDateTime readyForReview = null;
List<Activity> activities = handler.getRepository().findAllByTaskIdOrderByUpdatedDesc(task.id());
for (Activity activity : activities) {
if ("done".equals(activity.getStatusCode())) done=activity.getUpdated();
if ("ready_for_review".equals(activity.getStatusCode())) readyForReview=activity.getUpdated();
}
if (done==null||readyForReview==null) return Duration.ZERO;
else return Duration.between(readyForReview, done);
}
}

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("/{id}/tag")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void addTag(@PathVariable long id, @RequestBody String tag) {
taskService.addTag(id, tag);
}
}
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 @@ -10,6 +10,7 @@
import com.javarush.jira.bugtracking.task.to.TaskToExt;
import com.javarush.jira.bugtracking.task.to.TaskToFull;
import com.javarush.jira.common.error.DataConflictException;
import com.javarush.jira.common.error.IllegalRequestDataException;
import com.javarush.jira.common.error.NotFoundException;
import com.javarush.jira.common.util.Util;
import com.javarush.jira.login.AuthUser;
Expand Down Expand Up @@ -140,4 +141,18 @@ 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 taskId, String tag) {
if (tag == null || tag.isEmpty()) {
throw new IllegalRequestDataException("Tag must not be null or empty");
}
if (tag.length() > 32) {
throw new IllegalRequestDataException("Tag must not exceed 32 characters");
}

Task task = handler.getRepository().getExisted(taskId);
task.getTags().add(tag);

handler.getRepository().saveAndFlush(task);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.javarush.jira.common.internal.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

@Configuration
@Profile("nativeTest")
public class H2DataSourceConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.javarush.jira.common.internal.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

@Configuration
@Profile("native")
public class PostgreSqlDataSourceConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/jira");
dataSource.setUsername("jira");
dataSource.setPassword("JiraRush");
return dataSource;
}
}

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
25 changes: 1 addition & 24 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,7 @@ 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
Expand All @@ -83,16 +70,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
Expand Down
Loading