Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
fb3ca49
Implemented compose.yaml for the database
AGuliaiev Oct 24, 2025
dbddf40
add dependency for lombok and docker compose
AGuliaiev Oct 24, 2025
8bace9a
2. Видалити соціальні мережі: vk, yandex.
AGuliaiev Oct 31, 2025
951904a
3. Винести чутливу інформацію до окремого проперті файлу:
AGuliaiev Oct 31, 2025
e427562
2. Видалити соціальні мережі: vk, yandex.
AGuliaiev Oct 31, 2025
5a8b7d2
4. Переробити тести так, щоб під час тестів використовувалася in memo…
AGuliaiev Nov 3, 2025
ee78cf0
4. Переробити тести так, щоб під час тестів використовувалася in memo…
AGuliaiev Nov 3, 2025
3c2cdd0
9. Написати Dockerfile для основного сервера
AGuliaiev Nov 3, 2025
cc3c2de
6. Зробити рефакторинг методу com.javarush.jira.bugtracking.attachmen…
AGuliaiev Nov 3, 2025
1c90f60
5. Написати тести для всіх публічних методів контролера ProfileRestCo…
AGuliaiev Nov 14, 2025
a536180
7. Додати новий функціонал: додавання тегів до завдання (REST API + р…
AGuliaiev Nov 14, 2025
f5852fa
8. Додати підрахунок часу: скільки завдання перебувало у роботі та те…
AGuliaiev Nov 14, 2025
057defe
10. Написати docker-compose файл для запуску контейнера сервера разом…
AGuliaiev Nov 14, 2025
363a9a8
refactor: application-test.yaml and application.yaml for testing
AGuliaiev Nov 14, 2025
645ddc2
Adding to README.md
AGuliaiev Nov 26, 2025
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


28 changes: 28 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# syntax=docker/dockerfile:1.7
FROM eclipse-temurin:17-jdk-jammy AS builder
WORKDIR /app

# Copy build files first to leverage Docker layer cache
COPY .mvn/ .mvn/
COPY mvnw pom.xml ./
RUN chmod +x mvnw
# Speed up builds by caching the Maven repo (BuildKit needed)
RUN --mount=type=cache,target=/root/.m2 ./mvnw -B -DskipTests dependency:go-offline

# Now add sources and build
COPY src/ src/
RUN --mount=type=cache,target=/root/.m2 ./mvnw -B -DskipTests clean package

FROM eclipse-temurin:17-jre-jammy
WORKDIR /app

# Run as non-root
RUN useradd -ms /bin/bash appuser
USER appuser

# Copy the fat jar
COPY --from=builder /app/target/*.jar /app/app.jar

EXPOSE 8080

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

Список выполненных задач:
...

# JiraRush Project: My Contributions & Enhancements

This document outlines my key contributions and improvements to the JiraRush project, covering aspects of security, testing, refactoring, new features, and deployment.

## My Contributions to the Project:

Here's a breakdown of the specific tasks and features I implemented:

1. 📘 **Project Structure Onboarding:** I successfully familiarized myself with the existing project structure and architecture, enabling effective subsequent modifications and new feature development.
2. 🚫 **Removal of Deprecated Social Integrations:** I removed outdated social media integrations (VK, Yandex) from the project, simplifying the codebase and mitigating potential security risks.
3. 🔑 **Externalization of Sensitive Information:** I moved sensitive data, such as database login credentials, OAuth registration/authorization identifiers, and email settings, into separate property files. These values are now securely loaded from machine environment variables upon server startup, significantly enhancing security and configuration flexibility.
4. 🧪 **Refactoring Tests for In-Memory H2 Database:** I adapted the test suite to utilize an in-memory H2 database instead of PostgreSQL. This involved defining two distinct Spring beans, with the active Spring profile dictating which database to use. Minor adjustments were also made to test data scripts to ensure compatibility with H2's features.
5. ✅ **Comprehensive `ProfileRestController` Test Coverage:** I developed a robust set of unit and integration tests for all public methods of the `ProfileRestController`. These tests meticulously validate both successful and various unsuccessful execution paths to guarantee the API's reliability and resilience.
6. 🔄 **Refactoring `FileUtil#upload` for Modern File System API:** I refactored the `com.javarush.jira.bugtracking.attachment.FileUtil#upload` method to leverage modern Java file system APIs, enhancing its efficiency, robustness, and maintainability for file operations.
7. 🏷️ **Implementation of Task Tagging System:** I introduced a new feature allowing users to add tags to tasks. This includes developing the dedicated REST API endpoint and implementing the corresponding service-layer logic, utilizing the existing `task_tag` database table.
8. ⏱️ **Adding Task Time Tracking Functionality:** I implemented two service-level methods to calculate the time a task spends in specific operational states:
* **Time in Work:** Calculated as the duration from `in_progress` to `ready_for_review` status.
* **Time in Testing:** Calculated as the duration from `ready_for_review` to `done` status.
To support this, I appended three critical `ACTIVITY` entries (with `in_progress`, `ready_for_review`, and `done` statuses) to the `changelog.sql` database initialization script.
9. 🐳 **Dockerfile for Application Server:** I created a `Dockerfile` to containerize the main application server, ensuring easy and consistent deployment across different environments.
10. 🚀 **Docker Compose for Full Stack Deployment:** I developed a `docker-compose.yml` file to orchestrate the entire application stack. This setup includes the application server, a PostgreSQL database, and an Nginx reverse proxy, leveraging the `config/nginx.conf` file (which can be modified as needed) for efficient routing and load balancing.

---
47 changes: 47 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
services:
db:
image: postgres
container_name: postgres
env_file:
- ./.env
ports:
- "5433:5432"
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- app_network

app:
build:
context: .
dockerfile: Dockerfile
container_name: app
env_file:
- ./.env
ports:
- "8080:8080"
depends_on:
- db
networks:
- app_network

nginx:
image: nginx:latest
container_name: nginx
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf
- ./resources/static:/opt/jirarush/resources/static
ports:
- "80:80"
depends_on:
- app
networks:
- app_network

networks:
app_network:
driver: bridge

volumes:
pgdata:
driver: local
90 changes: 51 additions & 39 deletions config/nginx.conf
Original file line number Diff line number Diff line change
@@ -1,40 +1,52 @@
# https://losst.ru/ustanovka-nginx-ubuntu-16-04
# https://pai-bx.com/wiki/nginx/2332-useful-redirects-in-nginx/#1
# sudo iptables -A INPUT ! -s 127.0.0.1 -p tcp -m tcp --dport 8080 -j DROP
server {
listen 80;

# https://www.digitalocean.com/community/tutorials/how-to-optimize-nginx-configuration
gzip on;
gzip_types text/css application/javascript application/json;
gzip_min_length 2048;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
root /opt/jirarush/resources;

if ($request_uri ~ ';') {return 404;}

# proxy_cookie_flags ~ secure samesite=none;

# static
location /static/ {
expires 30d;
access_log off;
}
location /robots.txt {
access_log off;
}

location ~ (/$|/view/|/ui/|/oauth2/) {
expires 0m;
proxy_pass http://localhost:8080;
proxy_connect_timeout 30s;
}
location ~ (/api/|/doc|/swagger-ui/|/v3/api-docs/) {
proxy_pass http://localhost:8080;
proxy_connect_timeout 150s;
}
location / {
try_files /view/404.html = 404;
}
# Основний блок налаштувань
user nginx;
worker_processes 1;

events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

# Ваш серверний блок
server {
listen 80;

# https://www.digitalocean.com/community/tutorials/how-to-optimize-nginx-configuration
gzip on;
gzip_types text/css application/javascript application/json;
gzip_min_length 2048;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
root /opt/jirarush/resources;

if ($request_uri ~ ';') { return 404; }

# Статичні файли
location /static/ {
expires 30d;
access_log off;
}

location /robots.txt {
access_log off;
}

location ~ (/$|/view/|/ui/|/oauth2/) {
expires 0m;
proxy_pass http://localhost:8080;
proxy_connect_timeout 30s;
}

location ~ (/api/|/doc|/swagger-ui/|/v3/api-docs/) {
proxy_pass http://localhost:8080;
proxy_connect_timeout 150s;
}

location / {
try_files /view/404.html '=' 404;
}
}
}
48 changes: 45 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.2</version>
<version>3.1.12</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

Expand Down Expand Up @@ -41,6 +41,19 @@
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>java-dotenv</artifactId>
<version>5.2.2</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-docker-compose</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>

<!-- jackson-->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
Expand Down Expand Up @@ -82,6 +95,12 @@
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

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

<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
Expand All @@ -96,7 +115,7 @@
<dependency>
<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 @@ -146,6 +165,29 @@

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>3.5.5</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
Expand Down Expand Up @@ -196,4 +238,4 @@
</build>
</profile>
</profiles>
</project>
</project>
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
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 @@ -25,14 +25,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());
}
try {
Path directory = Path.of(directoryPath);
Files.createDirectory(directory);
Path targetFile = directory.resolve(fileName);
multipartFile.transferTo(targetFile);
} catch (IOException e) {
throw new IllegalRequestDataException("Failed to upload file" + multipartFile.getOriginalFilename());
}
}

Expand Down
Loading