diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f2d48b8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +target/ +!target/*.jar +.git +.gitignore +.idea +*.iml +*.log +docker-compose*.yml +README.md diff --git a/Dockerfile b/Dockerfile index e69de29..0d751f8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -0,0 +1,35 @@ +# Этап сборки +FROM eclipse-temurin:17-jdk-alpine AS builder + +WORKDIR /app + +# Копируем Gradle wrapper и конфигурацию +COPY gradlew build.gradle settings.gradle ./ +COPY gradle gradle + +# Загружаем зависимости (кэшируется) +RUN ./gradlew dependencies --no-daemon + +# Копируем исходники +COPY src src + +# Собираем JAR +RUN ./gradlew bootJar --no-daemon + +# Этап запуска +FROM eclipse-temurin:17-jre-alpine + +WORKDIR /app + +# Создаём пользователя для безопасности +RUN addgroup -S appgroup && adduser -S appuser -G appgroup + +# Копируем JAR из builder +COPY --from=builder /app/build/libs/*.jar app.jar + +# Переключаемся на непривилегированного пользователя +USER appuser + +EXPOSE 8080 + +ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/README.md b/README.md index dc890a6..c650b32 100644 --- a/README.md +++ b/README.md @@ -41,4 +41,20 @@ cd teacher-diary -docker run -d -p 1025:1025 -p 8025:8025 --name mailhog mailhog/mailhog \ No newline at end of file +docker run -d -p 1025:1025 -p 8025:8025 --name mailhog mailhog/mailhog +``` + +## 🐳 Docker +### Войти в Docker Hub +```docker login``` + +### Собрать образ +```docker build -t malexple/teacher-diary:latest .``` + +### Отправить в Docker Hub +```docker push malexple/teacher-diary:latest``` + +### Быстрый запуск +```bash +docker-compose up -d +``` \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index e158225..b8a4d73 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,29 +1,35 @@ version: '3.8' services: - postgres: - image: postgres:16-alpine - container_name: teacher-diary-db + app: + image: malexple/teacher-diary:latest + ports: + - "8080:8080" environment: - POSTGRES_DB: teacher_diary_dev + SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/teacher_diary + SPRING_DATASOURCE_USERNAME: postgres + SPRING_DATASOURCE_PASSWORD: postgres + SPRING_JPA_HIBERNATE_DDL_AUTO: update + depends_on: + db: + condition: service_healthy + restart: unless-stopped + + db: + image: postgres:16-alpine + environment: + POSTGRES_DB: teacher_diary POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres - ports: - - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data + ports: + - "5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] - interval: 10s + interval: 5s timeout: 5s retries: 5 - mailhog: - image: mailhog/mailhog:latest - container_name: teacher-diary-mail - ports: - - "1025:1025" # SMTP - - "8025:8025" # Web UI - volumes: postgres_data: diff --git a/src/main/java/ru/mcs/diary/auth/AuthService.java b/src/main/java/ru/mcs/diary/auth/AuthService.java index b7f1c25..e1db8c2 100644 --- a/src/main/java/ru/mcs/diary/auth/AuthService.java +++ b/src/main/java/ru/mcs/diary/auth/AuthService.java @@ -184,7 +184,7 @@ } public Optional validateParentInviteToken(String token) { - return parentInviteTokenRepository.findByTokenAndUsedFalse(token) + return parentInviteTokenRepository.findByTokenWithParent(token) // используем новый метод .filter(t -> t.getExpiresAt() == null || LocalDateTime.now().isBefore(t.getExpiresAt())); } diff --git a/src/main/java/ru/mcs/diary/auth/ParentInviteTokenRepository.java b/src/main/java/ru/mcs/diary/auth/ParentInviteTokenRepository.java index ef4319d..2d22bb4 100644 --- a/src/main/java/ru/mcs/diary/auth/ParentInviteTokenRepository.java +++ b/src/main/java/ru/mcs/diary/auth/ParentInviteTokenRepository.java @@ -1,6 +1,8 @@ package ru.mcs.diary.auth; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import ru.mcs.diary.parent.Parent; @@ -14,4 +16,7 @@ Optional findByParentAndUsedFalse(Parent parent); boolean existsByParentAndUsedFalse(Parent parent); + + @Query("SELECT t FROM ParentInviteToken t JOIN FETCH t.parent WHERE t.token = :token AND t.used = false") + Optional findByTokenWithParent(@Param("token") String token); } diff --git a/src/main/java/ru/mcs/diary/common/service/MailService.java b/src/main/java/ru/mcs/diary/common/service/MailService.java index b1f8022..491856f 100644 --- a/src/main/java/ru/mcs/diary/common/service/MailService.java +++ b/src/main/java/ru/mcs/diary/common/service/MailService.java @@ -85,6 +85,8 @@ mailSender.send(message); log.info("Email sent successfully to: {}", to); + log.info("subject sent successfully to: {}", subject); + log.info("htmlContent sent successfully to: {}", htmlContent); } catch (MessagingException e) { log.error("Failed to send email to: {}", to, e); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 15dd520..3f6b89f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -60,6 +60,7 @@ mail: host: localhost port: 1025 + enabled: true # Messages messages: diff --git a/src/main/resources/templates/auth/parent-invite-error.html b/src/main/resources/templates/auth/parent-invite-error.html index a9949b3..fa2e79c 100644 --- a/src/main/resources/templates/auth/parent-invite-error.html +++ b/src/main/resources/templates/auth/parent-invite-error.html @@ -1,23 +1,26 @@ - - - -
-
- -
-

Приглашение недействительно

-

Ссылка приглашения устарела или уже была использована.

-

Свяжитесь с преподавателем для получения нового приглашения.

- -