diff --git a/src/main/java/ru/soune/nocopy/configuration/ApplicationConfig.java b/src/main/java/ru/soune/nocopy/configuration/ApplicationConfig.java index 92598e7..b33c275 100644 --- a/src/main/java/ru/soune/nocopy/configuration/ApplicationConfig.java +++ b/src/main/java/ru/soune/nocopy/configuration/ApplicationConfig.java @@ -12,21 +12,17 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; -import ru.soune.nocopy.entity.file.FileEntity; -import ru.soune.nocopy.entity.file.ProtectionStatus; -import ru.soune.nocopy.repository.FileEntityRepository; -import ru.soune.nocopy.util.FileUtil; -import java.util.List; +import java.util.Collections; @Configuration @EnableAutoConfiguration @AllArgsConstructor public class ApplicationConfig { - private final FileEntityRepository fileEntityRepository; +// private final FileEntityRepository fileEntityRepository; - private final FileUtil fileUtil; +// private final FileUtil fileUtil; @Bean PasswordEncoder passwordEncoder() { @@ -44,11 +40,11 @@ public class ApplicationConfig { AudioFilePathProvider audioFilePathProvider, DocumentLocalSearch documentLocalSearch) { - List initialFiles = loadProcessingFile(); +// List initialFiles = loadProcessingFile(); //TODO инициализация файлов при создании return new com.vrt.NoCopyFileService( - initialFiles, + Collections.emptyList(), fileProvider, processingListener, imageUniqueCheck, @@ -59,12 +55,12 @@ public class ApplicationConfig { ); } - private List loadProcessingFile() { - List byProtectionStatus = - fileEntityRepository.findByProtectionStatus(ProtectionStatus.PROCESSING); - - return byProtectionStatus.stream().map(fileEntity -> - fileUtil.createFileInfo(fileEntity, null)).toList(); - } +// private List loadProcessingFile() { +// List byProtectionStatus = +// fileEntityRepository.findByProtectionStatus(ProtectionStatus.PROCESSING); +// +// return byProtectionStatus.stream().map(fileEntity -> +// fileUtil.createFileInfo(fileEntity, null)).toList(); +// } } diff --git a/src/main/java/ru/soune/nocopy/configuration/HandlerConfig.java b/src/main/java/ru/soune/nocopy/configuration/HandlerConfig.java index 1bdd94a..926fa69 100644 --- a/src/main/java/ru/soune/nocopy/configuration/HandlerConfig.java +++ b/src/main/java/ru/soune/nocopy/configuration/HandlerConfig.java @@ -34,7 +34,8 @@ public class HandlerConfig { GlobalSearchHandler globalSearchHandler, ViolationNotionHandler violationNotionHandler, ComplaintEntityHandler complaintEntityHandler, - UserInfoHandler userInfoHandler + UserInfoHandler userInfoHandler, + NotificationHandler notificationHandler ) { Map map = new HashMap<>(); map.put(20001, login); @@ -60,6 +61,7 @@ public class HandlerConfig { map.put(30012, violationNotionHandler); map.put(30013, complaintEntityHandler); map.put(30014, userInfoHandler); + map.put(30015, notificationHandler); return map; } diff --git a/src/main/java/ru/soune/nocopy/dto/notification/ActivateNotificationRequest.java b/src/main/java/ru/soune/nocopy/dto/notification/ActivateNotificationRequest.java new file mode 100644 index 0000000..45d0da0 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/notification/ActivateNotificationRequest.java @@ -0,0 +1,8 @@ +package ru.soune.nocopy.dto.notification; + +import lombok.Data; + +@Data +public class ActivateNotificationRequest { + private String authToken; +} diff --git a/src/main/java/ru/soune/nocopy/dto/notification/ActiveNotificationsResponse.java b/src/main/java/ru/soune/nocopy/dto/notification/ActiveNotificationsResponse.java new file mode 100644 index 0000000..2ad4b82 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/notification/ActiveNotificationsResponse.java @@ -0,0 +1,13 @@ +package ru.soune.nocopy.dto.notification; + +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +@Data +@Builder +public class ActiveNotificationsResponse { + private List notifications; + private long unreadCount; +} diff --git a/src/main/java/ru/soune/nocopy/dto/notification/MarkAsReadRequest.java b/src/main/java/ru/soune/nocopy/dto/notification/MarkAsReadRequest.java new file mode 100644 index 0000000..e3a6dd9 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/notification/MarkAsReadRequest.java @@ -0,0 +1,11 @@ +package ru.soune.nocopy.dto.notification; + +import lombok.Data; + +import java.util.List; + +@Data +public class MarkAsReadRequest { + private List notificationIds; + private String authToken; +} diff --git a/src/main/java/ru/soune/nocopy/dto/notification/MarkAsReadResponse.java b/src/main/java/ru/soune/nocopy/dto/notification/MarkAsReadResponse.java new file mode 100644 index 0000000..76ec790 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/notification/MarkAsReadResponse.java @@ -0,0 +1,11 @@ +package ru.soune.nocopy.dto.notification; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class MarkAsReadResponse { + private boolean success; + private int updatedCount; +} diff --git a/src/main/java/ru/soune/nocopy/dto/notification/NotificationDto.java b/src/main/java/ru/soune/nocopy/dto/notification/NotificationDto.java new file mode 100644 index 0000000..85368b1 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/notification/NotificationDto.java @@ -0,0 +1,18 @@ +package ru.soune.nocopy.dto.notification; + +import lombok.Builder; +import lombok.Data; +import ru.soune.nocopy.entity.notification.NotificationStatus; +import ru.soune.nocopy.entity.notification.NotificationType; + +import java.time.LocalDateTime; + +@Data +@Builder +public class NotificationDto { + private Long id; + private String message; + private NotificationType type; + private NotificationStatus status; + private LocalDateTime createdAt; +} diff --git a/src/main/java/ru/soune/nocopy/dto/notification/NotificationListRequest.java b/src/main/java/ru/soune/nocopy/dto/notification/NotificationListRequest.java new file mode 100644 index 0000000..106afcc --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/notification/NotificationListRequest.java @@ -0,0 +1,18 @@ +package ru.soune.nocopy.dto.notification; + +import lombok.Data; +import ru.soune.nocopy.entity.notification.NotificationStatus; +import ru.soune.nocopy.entity.notification.NotificationType; + +import java.util.List; + +@Data +public class NotificationListRequest { + private int page = 0; + private int size = 10; + private String sortBy = "createdAt"; + private String sortDirection = "DESC"; + private List types; + private List statuses; + private String authToken; +} diff --git a/src/main/java/ru/soune/nocopy/dto/notification/NotificationListResponse.java b/src/main/java/ru/soune/nocopy/dto/notification/NotificationListResponse.java new file mode 100644 index 0000000..9061131 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/notification/NotificationListResponse.java @@ -0,0 +1,15 @@ +package ru.soune.nocopy.dto.notification; + +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +@Data +@Builder +public class NotificationListResponse { + private List notifications; + private int currentPage; + private int totalPages; + private long totalElements; +} diff --git a/src/main/java/ru/soune/nocopy/entity/monitoring/MonitoringType.java b/src/main/java/ru/soune/nocopy/entity/monitoring/MonitoringType.java index 21a8b84..8892939 100644 --- a/src/main/java/ru/soune/nocopy/entity/monitoring/MonitoringType.java +++ b/src/main/java/ru/soune/nocopy/entity/monitoring/MonitoringType.java @@ -1,6 +1,14 @@ package ru.soune.nocopy.entity.monitoring; +import lombok.Getter; +@Getter public enum MonitoringType { - MONITORING_DAILY, MONITORING_WEEKLY, MONITORING_MONTHLY, NONE + MONITORING_DAILY(1), MONITORING_WEEKLY(7), MONITORING_MONTHLY(30), NONE(0); + + private final int days; + + MonitoringType(int days) { + this.days = days; + } } diff --git a/src/main/java/ru/soune/nocopy/entity/notification/Notification.java b/src/main/java/ru/soune/nocopy/entity/notification/Notification.java new file mode 100644 index 0000000..31035cb --- /dev/null +++ b/src/main/java/ru/soune/nocopy/entity/notification/Notification.java @@ -0,0 +1,49 @@ +package ru.soune.nocopy.entity.notification; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.*; +import lombok.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import ru.soune.nocopy.entity.user.User; + +import java.time.LocalDateTime; + +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Getter @Setter +@Builder +@Table(name = "notifications", indexes = { + @Index(name = "idx_user_status", columnList = "user_id, status"), + @Index(name = "idx_user_created", columnList = "user_id, created_at DESC") +}) +public class Notification { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "created_at", updatable = false) + @CreatedDate + private LocalDateTime createdAt; + + @LastModifiedDate + @Column(name = "updated_at") + private LocalDateTime updatedAt; + + @Column(name = "message") + private String message; + + @Enumerated(EnumType.STRING) + @Column(name = "notification_type") + private NotificationType notificationType; + + @Column(name = "status") + private NotificationStatus status = NotificationStatus.NEW; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + @JsonIgnore + private User user; +} diff --git a/src/main/java/ru/soune/nocopy/entity/notification/NotificationMessage.java b/src/main/java/ru/soune/nocopy/entity/notification/NotificationMessage.java new file mode 100644 index 0000000..0085299 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/entity/notification/NotificationMessage.java @@ -0,0 +1,14 @@ +package ru.soune.nocopy.entity.notification; + +import lombok.Getter; + +@Getter +public enum NotificationMessage { + FILE_SEARCH("notification.file.search"); + + private final String messageKey; + + NotificationMessage(String messageKey) { + this.messageKey = messageKey; + } +} diff --git a/src/main/java/ru/soune/nocopy/entity/notification/NotificationStatus.java b/src/main/java/ru/soune/nocopy/entity/notification/NotificationStatus.java new file mode 100644 index 0000000..5c3bb1c --- /dev/null +++ b/src/main/java/ru/soune/nocopy/entity/notification/NotificationStatus.java @@ -0,0 +1,5 @@ +package ru.soune.nocopy.entity.notification; + +public enum NotificationStatus { + NEW, READIED +} diff --git a/src/main/java/ru/soune/nocopy/entity/notification/NotificationType.java b/src/main/java/ru/soune/nocopy/entity/notification/NotificationType.java new file mode 100644 index 0000000..159fe35 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/entity/notification/NotificationType.java @@ -0,0 +1,31 @@ +package ru.soune.nocopy.entity.notification; + +import lombok.Getter; + +@Getter +public enum NotificationType { + SEARCH_RESULT("notification.search.result"), + MONITORING_RESULT("notification.monitoring.result"), + OPERATION_IMPOSSIBLE("notification.operation.impossible"), + START_FAILED_NOW("notification.start.failed.now"), + START_FAILED_NEXT("notification.start.failed.next"), + PAYOUT_RESULT("notification.payout.result"), + PAYMENT_RESULT("notification.payment.result"), + REFERRAL_DEPOSIT("notification.referral.deposit"), + REFERRAL_REGISTERED("notification.referral.registered"), + REFERRAL_ACTIVATED("notification.referral.activated"), + COMPLAINT_STATUS_CHANGED("notification.complaint.status"), + CASE_STATUS_CHANGED("notification.case.status"), + INCOMING_MESSAGE("notification.incoming.message"), + TARIFF_EXPIRING("notification.tariff.expiring"), + TOKEN_NOT_FOUND("notification.token.not.found"), + FILE_MODERATION_EVENT("notification.file.moderation"), + FILE_ADDED_TO_SYSTEM("notification.file.added"), + SEARCH_OPERATION_FAILED("notification.search.operation.filed"); + + private final String messageKey; + + NotificationType(String messageKey) { + this.messageKey = messageKey; + } +} diff --git a/src/main/java/ru/soune/nocopy/entity/tarif/TariffTimeTerm.java b/src/main/java/ru/soune/nocopy/entity/tarif/TariffTimeTerm.java index b3a9441..5754e56 100644 --- a/src/main/java/ru/soune/nocopy/entity/tarif/TariffTimeTerm.java +++ b/src/main/java/ru/soune/nocopy/entity/tarif/TariffTimeTerm.java @@ -2,14 +2,21 @@ package ru.soune.nocopy.entity.tarif; import lombok.Getter; +import java.util.List; + @Getter public enum TariffTimeTerm { - MONTHLY(30),YEAR(365); + MONTHLY(30, "MONTHLY"),YEAR(365, "YEAR"); private final Integer days; + private final String name; - TariffTimeTerm(Integer days) { + TariffTimeTerm(Integer days, String name) { this.days = days; + this.name = name; } + public static List validTerms() { + return List.of(MONTHLY.name(), YEAR.name()); + } } diff --git a/src/main/java/ru/soune/nocopy/handler/NotificationHandler.java b/src/main/java/ru/soune/nocopy/handler/NotificationHandler.java new file mode 100644 index 0000000..6db1c55 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/handler/NotificationHandler.java @@ -0,0 +1,147 @@ +package ru.soune.nocopy.handler; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Component; +import ru.soune.nocopy.dto.BaseRequest; +import ru.soune.nocopy.dto.BaseResponse; +import ru.soune.nocopy.dto.MessageCode; +import ru.soune.nocopy.dto.file.ActionResponse; +import ru.soune.nocopy.service.notification.NotificationService; +import com.fasterxml.jackson.databind.type.TypeFactory; +import ru.soune.nocopy.dto.notification.*; +import ru.soune.nocopy.entity.notification.Notification; +import ru.soune.nocopy.entity.user.User; +import ru.soune.nocopy.service.register.AuthService; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +@Slf4j +@Component +@RequiredArgsConstructor +public class NotificationHandler implements RequestHandler { + + private final NotificationService notificationService; + + private final ObjectMapper objectMapper; + + private final AuthService authService; + + @Override + public BaseResponse handle(BaseRequest request) throws Exception { + Map bodyMap = objectMapper.convertValue(request.getMessageBody(), + TypeFactory.defaultInstance().constructMapType(Map.class, String.class, Object.class)); + + String action = (String) bodyMap.get("action"); + + if (action == null) { + ActionResponse response = ActionResponse.builder() + .action(action) + .availableActions(Arrays.asList("list", "active", "markRead")) + .build(); + + return new BaseResponse(request.getMsgId(), + MessageCode.INVALID_FIELD.getCode(), + "Action is required", + response); + } + + switch (action) { + case "list": { + NotificationListRequest listRequest = objectMapper.convertValue(request.getMessageBody(), + NotificationListRequest.class); + User user = authService.getUser(listRequest.getAuthToken()); + + Page page = notificationService.getAllNotifications( + user, + listRequest.getPage(), + listRequest.getSize(), + listRequest.getSortBy(), + listRequest.getSortDirection(), + listRequest.getTypes(), + listRequest.getStatuses()); + + List dtos = page.getContent().stream() + .map(this::toDto) + .collect(Collectors.toList()); + + NotificationListResponse response = NotificationListResponse.builder() + .notifications(dtos) + .currentPage(page.getNumber()) + .totalPages(page.getTotalPages()) + .totalElements(page.getTotalElements()) + .build(); + + return new BaseResponse(request.getMsgId(), + MessageCode.SUCCESS.getCode(), + MessageCode.SUCCESS.getDescription(), + response); + } + + case "active": { + ActivateNotificationRequest activateRequest = objectMapper.convertValue(request.getMessageBody(), + ActivateNotificationRequest.class); + User user = authService.getUser(activateRequest.getAuthToken()); + + List recent = notificationService.getActiveNotifications(user); + + long unreadCount = notificationService.getUnreadCount(user); + + ActiveNotificationsResponse response = ActiveNotificationsResponse.builder() + .notifications(recent.stream().map(this::toDto).collect(Collectors.toList())) + .unreadCount(unreadCount) + .build(); + + return new BaseResponse(request.getMsgId(), + MessageCode.SUCCESS.getCode(), + MessageCode.SUCCESS.getDescription(), + response); + } + + case "markRead": { + MarkAsReadRequest markRequest = objectMapper.convertValue(request.getMessageBody(), + MarkAsReadRequest.class); + User user = authService.getUser(markRequest.getAuthToken()); + + int updated = notificationService.markAsRead(user, markRequest.getNotificationIds()); + + MarkAsReadResponse response = MarkAsReadResponse.builder() + .success(true) + .updatedCount(updated) + .build(); + + return new BaseResponse(request.getMsgId(), + MessageCode.SUCCESS.getCode(), + MessageCode.SUCCESS.getDescription(), + response); + } + + default: + ActionResponse response = ActionResponse.builder() + .action(action) + .availableActions(Arrays.asList("list", "active", "markRead")) + .build(); + + return new BaseResponse(request.getMsgId(), + MessageCode.INVALID_ACTION.getCode(), + "Invalid action: " + action, + response); + } + } + + private NotificationDto toDto(Notification notification) { + return NotificationDto.builder() + .id(notification.getId()) + .message(notification.getMessage()) + .type(notification.getNotificationType()) + .status(notification.getStatus()) + .createdAt(notification.getCreatedAt()) + .build(); + } +} diff --git a/src/main/java/ru/soune/nocopy/handler/TariffHandler.java b/src/main/java/ru/soune/nocopy/handler/TariffHandler.java index 036bc2a..af98a80 100644 --- a/src/main/java/ru/soune/nocopy/handler/TariffHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/TariffHandler.java @@ -123,6 +123,16 @@ public class TariffHandler implements RequestHandler { private BaseResponse handleGetTariffs(BaseRequest request, TariffRequest tariffRequest) { AuthToken authToken = authTokenRepository.findByToken(tariffRequest.getUserToken()).orElseThrow(); User user = authToken.getUser(); + + if (tariffRequest.getTariffTerm() == null || !TariffTimeTerm.validTerms().contains( + tariffRequest.getTariffTerm())) { + return new BaseResponse( + request.getMsgId(), + MessageCode.SUCCESS.getCode(), + "Not valid tariff_term", + Map.of("Valid term", TariffTimeTerm.validTerms())); + } + List allTariffs = tariffService.getTariffByAccountTypeAndTariffTerm(user, TariffTimeTerm.valueOf(tariffRequest.getTariffTerm().toUpperCase())); diff --git a/src/main/java/ru/soune/nocopy/repository/NotificationRepository.java b/src/main/java/ru/soune/nocopy/repository/NotificationRepository.java new file mode 100644 index 0000000..50e3762 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/repository/NotificationRepository.java @@ -0,0 +1,40 @@ +package ru.soune.nocopy.repository; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import ru.soune.nocopy.entity.notification.Notification; +import ru.soune.nocopy.entity.notification.NotificationStatus; +import ru.soune.nocopy.entity.notification.NotificationType; +import ru.soune.nocopy.entity.user.User; + +import java.util.List; + +public interface NotificationRepository extends JpaRepository { + Page findByUser(User user, Pageable pageable); + + Page findByUserAndNotificationTypeIn(User user, List types, Pageable pageable); + + Page findByUserAndStatusIn(User user, List statuses, Pageable pageable); + + Page findByUserAndNotificationTypeInAndStatusIn(User user, List types, + List statuses, + Pageable pageable); + + List findTop5ByUserAndStatusOrderByCreatedAtDesc(User user, NotificationStatus status); + + long countByUserAndStatus(User user, NotificationStatus status); + + @Modifying + @Query("UPDATE Notification n SET n.status = :newStatus WHERE n.id IN :ids AND n.user = :user AND " + + "n.status = :oldStatus") + int updateStatus(@Param("ids") List ids, + @Param("user") User user, + @Param("oldStatus") NotificationStatus oldStatus, + @Param("newStatus") NotificationStatus newStatus); + + Page getNotificationsByUser(User user, Pageable pageable); +} diff --git a/src/main/java/ru/soune/nocopy/scheduler/MonitoringScheduler.java b/src/main/java/ru/soune/nocopy/scheduler/MonitoringScheduler.java index 442bcbe..37be081 100644 --- a/src/main/java/ru/soune/nocopy/scheduler/MonitoringScheduler.java +++ b/src/main/java/ru/soune/nocopy/scheduler/MonitoringScheduler.java @@ -7,11 +7,16 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import ru.soune.nocopy.entity.monitoring.FileMonitoringEntity; +import ru.soune.nocopy.entity.notification.NotificationType; import ru.soune.nocopy.repository.FileMonitoringRepository; import ru.soune.nocopy.service.monitoring.MonitoringSearchService; +import ru.soune.nocopy.service.notification.NotificationService; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; @Slf4j @Component @@ -22,6 +27,8 @@ public class MonitoringScheduler { private final MonitoringSearchService monitoringSearchService; + private final NotificationService notificationService; + @Scheduled(cron = "0 1 2 * * *", zone = "Europe/Moscow") @Transactional public void processScheduledMonitoring() { @@ -29,6 +36,8 @@ public class MonitoringScheduler { LocalDateTime now = LocalDateTime.now(); List readyForRun = monitoringRepository.findReadyForRun(now); + Map> groupingFilesMonitoring = readyForRun.stream() + .collect(Collectors.groupingBy(FileMonitoringEntity::getUserId)); log.info("Found {} files ready for monitoring", readyForRun.size()); @@ -43,5 +52,10 @@ public class MonitoringScheduler { monitoringRepository.save(monitoring); } } + + Set usersForNotifications = groupingFilesMonitoring.keySet(); + for (Long userId : usersForNotifications) { + notificationService.addNotification(NotificationType.MONITORING_RESULT, userId); + } } } \ No newline at end of file diff --git a/src/main/java/ru/soune/nocopy/service/complaint/ComplaintEntityService.java b/src/main/java/ru/soune/nocopy/service/complaint/ComplaintEntityService.java index 3287a0b..a87f27a 100644 --- a/src/main/java/ru/soune/nocopy/service/complaint/ComplaintEntityService.java +++ b/src/main/java/ru/soune/nocopy/service/complaint/ComplaintEntityService.java @@ -1,7 +1,5 @@ package ru.soune.nocopy.service.complaint; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; @@ -13,12 +11,14 @@ import ru.soune.nocopy.dto.complaint.ComplaintResponse; import ru.soune.nocopy.entity.complaint.ComplaintEntity; import ru.soune.nocopy.entity.complaint.ComplaintStatus; import ru.soune.nocopy.entity.file.FileStatus; +import ru.soune.nocopy.entity.notification.NotificationType; import ru.soune.nocopy.entity.violation.Violation; import ru.soune.nocopy.exception.ComplaintNotFoundException; import ru.soune.nocopy.exception.DuplicateComplaintException; import ru.soune.nocopy.exception.ViolationNotFoundException; import ru.soune.nocopy.repository.ComplaintEntityRepository; import ru.soune.nocopy.repository.ViolationRepository; +import ru.soune.nocopy.service.notification.NotificationService; import ru.soune.nocopy.service.violation.ViolationService; import ru.soune.nocopy.service.violation.ViolationStatus; @@ -37,6 +37,8 @@ public class ComplaintEntityService { private final ViolationService violationService; + private final NotificationService notificationService; + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); public ComplaintResponse createComplaint(ComplaintRequest request) { @@ -101,7 +103,12 @@ public class ComplaintEntityService { } if (request.getComplaintText() != null) complaint.setComplaintText(request.getComplaintText()); if (request.getEmail() != null) complaint.setEmail(request.getEmail()); - if (request.getStatus() != null) complaint.setStatus(ComplaintStatus.valueOf(request.getStatus())); + if (request.getStatus() != null) { + complaint.setStatus(ComplaintStatus.valueOf(request.getStatus())); + + notificationService.addNotification(NotificationType.COMPLAINT_STATUS_CHANGED, complaint.getViolation() + .getFileEntity().getUserId(), request.getStatus()); + } return mapToResponse(complaintRepository.save(complaint)); } diff --git a/src/main/java/ru/soune/nocopy/service/file/FileEntityService.java b/src/main/java/ru/soune/nocopy/service/file/FileEntityService.java index e801dac..5c720bb 100644 --- a/src/main/java/ru/soune/nocopy/service/file/FileEntityService.java +++ b/src/main/java/ru/soune/nocopy/service/file/FileEntityService.java @@ -82,11 +82,11 @@ public class FileEntityService { .map(User::getId) .toList()) { allFiles.addAll(fileEntityRepository.findByUserIdAndStatusIn(uId, - List.of(FileStatus.ACTIVE, FileStatus.BLOCKED))); + List.of(FileStatus.ACTIVE, FileStatus.BLOCKED, FileStatus.MODERATION))); } } else { allFiles = fileEntityRepository.findByUserIdAndStatusIn(userId, - List.of(FileStatus.ACTIVE, FileStatus.BLOCKED)); + List.of(FileStatus.ACTIVE, FileStatus.BLOCKED, FileStatus.MODERATION)); } return allFiles; @@ -102,12 +102,12 @@ public class FileEntityService { .map(User::getId) .toList()) { allFiles.addAll(fileEntityRepository.findByUserIdAndStatusIn(uId, - List.of(FileStatus.ACTIVE, FileStatus.BLOCKED))); + List.of(FileStatus.ACTIVE, FileStatus.BLOCKED, FileStatus.MODERATION))); } } else { allFiles = fileEntityRepository.findByUserIdAndStatusIn(userId, - List.of(FileStatus.ACTIVE, FileStatus.BLOCKED)); + List.of(FileStatus.ACTIVE, FileStatus.BLOCKED, FileStatus.MODERATION)); } int start = (page - 1) * pageSize; diff --git a/src/main/java/ru/soune/nocopy/service/file/impl/FileUploadServiceImpl.java b/src/main/java/ru/soune/nocopy/service/file/impl/FileUploadServiceImpl.java index 3f381f4..af9f173 100644 --- a/src/main/java/ru/soune/nocopy/service/file/impl/FileUploadServiceImpl.java +++ b/src/main/java/ru/soune/nocopy/service/file/impl/FileUploadServiceImpl.java @@ -18,6 +18,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import ru.soune.nocopy.dto.file.UploadProgressResponse; import ru.soune.nocopy.entity.file.*; +import ru.soune.nocopy.entity.notification.NotificationType; import ru.soune.nocopy.exception.*; import ru.soune.nocopy.repository.FileEntityRepository; import ru.soune.nocopy.repository.FileUploadSessionRepository; @@ -29,6 +30,7 @@ import ru.soune.nocopy.service.file.FileEntityService; import ru.soune.nocopy.service.file.FileUploadService; import ru.soune.nocopy.service.file.cloud.CloudStorageService; import ru.soune.nocopy.service.tariff.TariffConstants; +import ru.soune.nocopy.service.notification.NotificationService; import ru.soune.nocopy.service.tariff.TariffInfoService; import ru.soune.nocopy.util.FileUtil; @@ -87,6 +89,8 @@ public class FileUploadServiceImpl implements FileUploadService { private final TariffInfoService tariffInfoService; + private final NotificationService notificationService; + private final CloudStorageService cloudStorageService; @PostConstruct @@ -374,6 +378,8 @@ public class FileUploadServiceImpl implements FileUploadService { session.setStatus(UploadStatus.COMPLETED); session.setFilePath(finalFilePath); + notificationService.addNotification(NotificationType.FILE_ADDED_TO_SYSTEM, session.getUserId()); + FileStatus status = findSimilar == 0 ? FileStatus.MODERATION: FileStatus.TEMP; if (status == FileStatus.TEMP) { diff --git a/src/main/java/ru/soune/nocopy/service/file/moderation/ModerationService.java b/src/main/java/ru/soune/nocopy/service/file/moderation/ModerationService.java index 4e8b01f..090dc59 100644 --- a/src/main/java/ru/soune/nocopy/service/file/moderation/ModerationService.java +++ b/src/main/java/ru/soune/nocopy/service/file/moderation/ModerationService.java @@ -11,6 +11,7 @@ import org.springframework.transaction.annotation.Transactional; import ru.soune.nocopy.dto.file.*; import ru.soune.nocopy.entity.file.*; import ru.soune.nocopy.entity.file.moderation.ModerationLog; +import ru.soune.nocopy.entity.notification.NotificationType; import ru.soune.nocopy.exception.FileEntityNotFoundException; import ru.soune.nocopy.exception.InvalidAppealException; @@ -18,6 +19,7 @@ import ru.soune.nocopy.repository.FileAppealRepository; import ru.soune.nocopy.repository.FileEntityRepository; import ru.soune.nocopy.repository.ModerationLogRepository; import ru.soune.nocopy.service.file.FileEntityService; +import ru.soune.nocopy.service.notification.NotificationService; import java.io.IOException; import java.time.LocalDateTime; @@ -35,6 +37,8 @@ public class ModerationService { private final FileEntityService fileEntityService; + private final NotificationService notificationService; + private static final List MODERATION_NEEDED_STATUSES = Arrays.asList( FileStatus.MODERATION, FileStatus.BLOCKED @@ -84,6 +88,8 @@ public class ModerationService { throw new RuntimeException(e); } } + + notificationService.addNotification(NotificationType.FILE_MODERATION_EVENT, file.getUserId()); } /** diff --git a/src/main/java/ru/soune/nocopy/service/monitoring/MonitoringSearchService.java b/src/main/java/ru/soune/nocopy/service/monitoring/MonitoringSearchService.java index bcfdabb..755c83d 100644 --- a/src/main/java/ru/soune/nocopy/service/monitoring/MonitoringSearchService.java +++ b/src/main/java/ru/soune/nocopy/service/monitoring/MonitoringSearchService.java @@ -3,6 +3,7 @@ package ru.soune.nocopy.service.monitoring; import jakarta.mail.MessagingException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.MessageSource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ru.soune.nocopy.configuration.search.SearchProperties; @@ -10,6 +11,8 @@ import ru.soune.nocopy.dto.file.YandexSearchResponse; import ru.soune.nocopy.dto.tarriff.TariffDTO; import ru.soune.nocopy.entity.monitoring.FileMonitoringEntity; import ru.soune.nocopy.entity.monitoring.MonitoringType; +import ru.soune.nocopy.entity.notification.NotificationMessage; +import ru.soune.nocopy.entity.notification.NotificationType; import ru.soune.nocopy.entity.tarif.TariffInfo; import ru.soune.nocopy.entity.tarif.TariffType; import ru.soune.nocopy.entity.user.User; @@ -17,6 +20,7 @@ import ru.soune.nocopy.exception.TariffNotFoundException; import ru.soune.nocopy.repository.FileMonitoringRepository; import ru.soune.nocopy.repository.UserRepository; import ru.soune.nocopy.service.mail.EmailService; +import ru.soune.nocopy.service.notification.NotificationService; import ru.soune.nocopy.service.search.SearchImageService; import ru.soune.nocopy.service.tariff.TariffInfoService; import ru.soune.nocopy.service.tariff.TariffService; @@ -48,6 +52,10 @@ public class MonitoringSearchService { private final SearchProperties searchProperties; + private final NotificationService notificationService; + + private final MessageSource messageSource; + @Transactional(noRollbackFor = TariffNotFoundException.class) public void processFileSearch(FileMonitoringEntity monitoring) throws MessagingException, IOException { monitoring.setLastRun(LocalDateTime.now()); @@ -123,7 +131,8 @@ public class MonitoringSearchService { } monitoring.setLastRunStatus("SUCCESS"); - + updateNextRun(monitoring); + monitoringRepository.save(monitoring); if (uniqueResults.isEmpty()) { log.info("No results found for monitoring file {}", monitoring.getFile().getId()); } @@ -134,15 +143,24 @@ public class MonitoringSearchService { int currentTokens = activeTariffInfo.getTokens() + activeTariffInfo.getBoughtTokens(); emailService.sendTokensNotFoundEmail(user, currentTokens, tariffMonitoring.getTokens()); + monitoring.setLastRunStatus("ERROR: " + e.getMessage()); + updateNextRun(monitoring); + monitoringRepository.save(monitoring); + notificationService.addNotification(NotificationType.TOKEN_NOT_FOUND, user.getId(), + NotificationMessage.FILE_SEARCH.getMessageKey()); } catch (Exception e) { + User user = userRepository.findById(monitoring.getUserId()).orElseThrow(); log.error("Error processing monitoring search", e); monitoring.setLastRunStatus("ERROR: " + e.getMessage()); updateNextRun(monitoring); + monitoringRepository.save(monitoring); + + notificationService.addNotification(NotificationType.SEARCH_OPERATION_FAILED, user.getId()); } } diff --git a/src/main/java/ru/soune/nocopy/service/notification/NotificationService.java b/src/main/java/ru/soune/nocopy/service/notification/NotificationService.java index 5bb807a..e820789 100644 --- a/src/main/java/ru/soune/nocopy/service/notification/NotificationService.java +++ b/src/main/java/ru/soune/nocopy/service/notification/NotificationService.java @@ -2,11 +2,115 @@ package ru.soune.nocopy.service.notification; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.MessageSource; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.soune.nocopy.entity.notification.Notification; +import ru.soune.nocopy.entity.notification.NotificationStatus; +import ru.soune.nocopy.entity.notification.NotificationType; +import ru.soune.nocopy.entity.user.User; +import ru.soune.nocopy.repository.NotificationRepository; +import ru.soune.nocopy.repository.UserRepository; +import ru.soune.nocopy.service.user.UserService; + +import java.util.List; +import java.util.Locale; @Service @Slf4j @RequiredArgsConstructor public class NotificationService { + private final NotificationRepository notificationRepository; + + private final UserRepository userRepository; + + private final MessageSource messageSource; + + @Transactional + public void addNotification(NotificationType notificationType, long userId, Object... args) { + Locale locale = Locale.forLanguageTag("ru"); + + String message = messageSource.getMessage(notificationType.getMessageKey(), args, locale); + + Notification notification = Notification.builder() + .notificationType(notificationType) + .user(userRepository.findById(userId).orElseThrow()) + .status(NotificationStatus.NEW) + .message(message) + .build(); + + notificationRepository.save(notification); + } + + @Transactional + public void deleteNotification(Notification notification) { + notificationRepository.delete(notification); + } + + /** + Получение всех нотификаций с сортировкой + */ + + @Transactional + public Page allUserNotifications(User user, int page, int size, String propertyToSort) { + Pageable pageable = PageRequest.of(page, size, Sort.by(propertyToSort).descending()); + + return notificationRepository.getNotificationsByUser(user, pageable); + } + + public Page getAllNotifications(User user, + int page, + int size, + String sortBy, + String sortDirection, + List types, + List statuses) { + Sort sort = Sort.by(Sort.Direction.fromString(sortDirection), sortBy); + PageRequest pageable = PageRequest.of(page, size, sort); + + boolean hasTypes = types != null && !types.isEmpty(); + boolean hasStatuses = statuses != null && !statuses.isEmpty(); + + if (hasTypes && hasStatuses) { + return notificationRepository.findByUserAndNotificationTypeInAndStatusIn(user, types, statuses, pageable); + } else if (hasTypes) { + return notificationRepository.findByUserAndNotificationTypeIn(user, types, pageable); + } else if (hasStatuses) { + return notificationRepository.findByUserAndStatusIn(user, statuses, pageable); + } else { + return notificationRepository.findByUser(user, pageable); + } + } + + /** + * 5 последних непрочитанных уведомлений. + */ + public List getActiveNotifications(User user) { + return notificationRepository.findTop5ByUserAndStatusOrderByCreatedAtDesc(user, NotificationStatus.NEW); + } + + /** + * Общее количество непрочитанных уведомлений. + */ + public long getUnreadCount(User user) { + return notificationRepository.countByUserAndStatus(user, NotificationStatus.NEW); + } + + /** + * Пометить выбранные уведомления как прочитанные. + * @return количество обновлённых записей + */ + @Transactional + public int markAsRead(User user, List notificationIds) { + if (notificationIds == null || notificationIds.isEmpty()) { + return 0; + } + return notificationRepository.updateStatus(notificationIds, user, NotificationStatus.NEW, + NotificationStatus.READIED); + } } diff --git a/src/main/java/ru/soune/nocopy/service/payment/PaymentService.java b/src/main/java/ru/soune/nocopy/service/payment/PaymentService.java index 96c9f74..dac9c50 100644 --- a/src/main/java/ru/soune/nocopy/service/payment/PaymentService.java +++ b/src/main/java/ru/soune/nocopy/service/payment/PaymentService.java @@ -4,9 +4,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import ru.soune.ReferralRepo; import ru.soune.ReferralService; import ru.soune.nocopy.client.YooKassaClient; import ru.soune.nocopy.dto.payment.PaymentMethodDTO; +import ru.soune.nocopy.entity.notification.NotificationType; import ru.soune.nocopy.entity.payment.Payment; import ru.soune.nocopy.entity.payment.PaymentMethod; import ru.soune.nocopy.entity.payment.PaymentOperationType; @@ -19,6 +21,7 @@ import ru.soune.nocopy.exception.PaymentNotFoundException; import ru.soune.nocopy.exception.TariffNotFoundException; import ru.soune.nocopy.exception.UserNotFoundException; import ru.soune.nocopy.repository.*; +import ru.soune.nocopy.service.notification.NotificationService; import ru.soune.nocopy.service.tariff.TariffInfoService; import java.time.LocalDateTime; @@ -46,6 +49,10 @@ public class PaymentService { private final YooKassaClient yooKassaClient; + private final ReferralRepo referralRepo; + + private final NotificationService notificationService; + @Transactional public Payment createPayment(String email, Long tariffId, String operationType, String paymentUuid) { User user = userRepository.findByEmail(email); @@ -158,15 +165,19 @@ public class PaymentService { savePaymentMethod(payment.getUser(), paymentMethod); referralService.onUserAccountRefill(payment.getUser().getId(), intPrice); + +// long inviterIdForUser = referralRepo.getInviterIdForUser(payment.getUser().getId()); + +// notificationService.addNotification(NotificationType.REFERRAL_ACTIVATED, inviterIdForUser); } else if ("payment.canceled".equals(eventType)) { payment.setStatus(PaymentStatus.CANCELED); Map cancellationDetails = (Map) object.get("cancellation_details"); - if (cancellationDetails != null) { - String reason = (String) cancellationDetails.get("reason"); - payment.setCancellationReason(reason); - } + String reason = (String) cancellationDetails.get("reason"); + payment.setCancellationReason(reason); + + notificationService.addNotification(NotificationType.PAYMENT_RESULT, payment.getUser().getId(), reason); } else if ("payment.waiting_for_capture".equals(eventType)) { payment.setStatus(PaymentStatus.WAITING); payment.setCancellationReason(null); @@ -175,10 +186,11 @@ public class PaymentService { payment.setStatus(PaymentStatus.FAILED); Map cancellationDetails = (Map) object.get("cancellation_details"); - if (cancellationDetails != null) { - String reason = (String) cancellationDetails.get("reason"); - payment.setCancellationReason(reason); - } + + String reason = (String) cancellationDetails.get("reason"); + payment.setCancellationReason(reason); + + notificationService.addNotification(NotificationType.PAYMENT_RESULT, payment.getUser().getId(), reason); } paymentRepository.save(payment); diff --git a/src/main/java/ru/soune/nocopy/service/referral/ReferralRepoImpl.java b/src/main/java/ru/soune/nocopy/service/referral/ReferralRepoImpl.java index b02d0b4..c5493e4 100644 --- a/src/main/java/ru/soune/nocopy/service/referral/ReferralRepoImpl.java +++ b/src/main/java/ru/soune/nocopy/service/referral/ReferralRepoImpl.java @@ -11,9 +11,11 @@ import org.springframework.transaction.annotation.Transactional; import ru.soune.Referral; import ru.soune.ReferralInvitee; import ru.soune.ReferralRepo; +import ru.soune.nocopy.entity.notification.NotificationType; import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.repository.ReferralJpaRepository; import ru.soune.nocopy.repository.UserRepository; +import ru.soune.nocopy.service.notification.NotificationService; import java.lang.reflect.Constructor; @@ -31,6 +33,8 @@ public class ReferralRepoImpl implements ReferralRepo { private final UserRepository userRepository; + private final NotificationService notificationService; + @Override public @NotNull String getUserReferralLink(long userId) { ru.soune.nocopy.entity.referral.Referral referral = @@ -150,6 +154,8 @@ public class ReferralRepoImpl implements ReferralRepo { @Override public void createReferralEntity(@NotNull Referral entity) { ru.soune.nocopy.entity.referral.Referral referral = new ru.soune.nocopy.entity.referral.Referral(); + Long inviter = entity.getInviter(); + referral.setUserId(entity.getUserId()); referral.setReferralLink(entity.getReferralLink()); referral.setInviterId(entity.getInviter()); @@ -160,6 +166,10 @@ public class ReferralRepoImpl implements ReferralRepo { referral.setActive(entity.getActive()); referralRepository.save(referral); + + if (inviter != null){ + notificationService.addNotification(NotificationType.REFERRAL_REGISTERED, inviter); + } } @Override diff --git a/src/main/java/ru/soune/nocopy/service/register/AuthService.java b/src/main/java/ru/soune/nocopy/service/register/AuthService.java index 652d45b..89848c5 100644 --- a/src/main/java/ru/soune/nocopy/service/register/AuthService.java +++ b/src/main/java/ru/soune/nocopy/service/register/AuthService.java @@ -106,6 +106,26 @@ public class AuthService { return authToken.getUser().getId(); } + @Transactional + public User getUser(String token) { + if (token == null || token.isBlank()) { + throw new NotFoundAuthToken("Token is required"); + } + + if (token.startsWith("Bearer ")) { + token = token.replace("Bearer ", ""); + } + + AuthToken authToken = authTokenRepository.findByToken(token) + .orElseThrow(() -> new NotFoundAuthToken("Token not found")); + authToken.setLastUsedAt(LocalDateTime.now()); + authToken.setExpiresAt(LocalDateTime.now().plusHours(1)); + + authTokenRepository.save(authToken); + + return authToken.getUser(); + } + public AuthToken login(LoginRequest request) { User user = userRepository.findByEmail(request.getEmail()); @@ -161,7 +181,7 @@ public class AuthService { } public AuthToken getAuthToken(String token) { - return authTokenRepository.findByToken(token).get(); + return authTokenRepository.findByToken(token).orElse(null); } private AuthToken genereateAuthToken(User user) { diff --git a/src/main/java/ru/soune/nocopy/service/search/GlobalSearchAsyncProcessor.java b/src/main/java/ru/soune/nocopy/service/search/GlobalSearchAsyncProcessor.java index c155366..0d3d832 100644 --- a/src/main/java/ru/soune/nocopy/service/search/GlobalSearchAsyncProcessor.java +++ b/src/main/java/ru/soune/nocopy/service/search/GlobalSearchAsyncProcessor.java @@ -8,11 +8,14 @@ import org.springframework.transaction.annotation.Transactional; import ru.soune.nocopy.configuration.search.SearchProperties; import ru.soune.nocopy.dto.file.YandexSearchResponse; import ru.soune.nocopy.entity.file.FileEntity; +import ru.soune.nocopy.entity.notification.NotificationType; import ru.soune.nocopy.entity.search.GlobalSearchResult; import ru.soune.nocopy.entity.search.GlobalSearchTask; import ru.soune.nocopy.entity.search.SearchStatus; +import ru.soune.nocopy.repository.FileEntityRepository; import ru.soune.nocopy.repository.GlobalSearchResultRepository; import ru.soune.nocopy.repository.GlobalSearchTaskRepository; +import ru.soune.nocopy.service.notification.NotificationService; import ru.soune.nocopy.service.tariff.TariffConstants; import ru.soune.nocopy.service.tariff.TariffInfoService; import ru.soune.nocopy.service.violation.ViolationService; @@ -41,31 +44,38 @@ public class GlobalSearchAsyncProcessor { private final SearchProperties searchProperties; + private final NotificationService notificationService; + + private final FileEntityRepository fileEntityRepository; + @Async @Transactional - public void processFilesAsync(String taskId, List filesToProcess, Long userId) { + public void processFilesAsync(String taskId, List filesToProcess, Long userId) { + GlobalSearchTask task = globalSearchTaskRepository.findById(taskId).orElseThrow(); + try { for (int i = 0; i < filesToProcess.size(); i++) { - FileEntity file = filesToProcess.get(i); + String uuid = filesToProcess.get(i); + FileEntity file = fileEntityRepository.findById(uuid) + .orElseThrow(() -> new RuntimeException("File not found: " + uuid)); + tariffInfoService.writeOffTokens(userId, TariffConstants.TOKEN_VALUE_FOR_SEARCH); GlobalSearchResult result = processFile(file, taskId, userId); globalSearchResultRepository.save(result); - GlobalSearchTask task = globalSearchTaskRepository.findById(taskId).orElseThrow(); task.setProcessedFiles(i + 1); task.setUpdatedAt(LocalDateTime.now()); globalSearchTaskRepository.save(task); } - GlobalSearchTask task = globalSearchTaskRepository.findById(taskId).orElseThrow(); task.setStatus(SearchStatus.COMPLETED.name()); task.setUpdatedAt(LocalDateTime.now()); globalSearchTaskRepository.save(task); + notificationService.addNotification(NotificationType.SEARCH_RESULT, userId); } catch (Exception e) { log.error("Global search failed for task: {}", taskId, e); - GlobalSearchTask task = globalSearchTaskRepository.findById(taskId).orElseThrow(); task.setStatus(SearchStatus.FAILED.name()); task.setUpdatedAt(LocalDateTime.now()); globalSearchTaskRepository.save(task); diff --git a/src/main/java/ru/soune/nocopy/service/search/GlobalSearchService.java b/src/main/java/ru/soune/nocopy/service/search/GlobalSearchService.java index e5c29a6..95a57e1 100644 --- a/src/main/java/ru/soune/nocopy/service/search/GlobalSearchService.java +++ b/src/main/java/ru/soune/nocopy/service/search/GlobalSearchService.java @@ -46,7 +46,9 @@ public class GlobalSearchService { globalSearchTaskRepository.save(task); - asyncProcessor.processFilesAsync(task.getTaskId(), filesToProcess, userId); + List fileIds = filesToProcess.stream().map(FileEntity::getId).toList(); + + asyncProcessor.processFilesAsync(task.getTaskId(), fileIds, userId); return task.getTaskId(); } diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties new file mode 100644 index 0000000..d776852 --- /dev/null +++ b/src/main/resources/messages.properties @@ -0,0 +1,19 @@ +notification.search.result=Результат поиска готов +notification.monitoring.result=Результат мониторинга доступен +notification.operation.impossible=Операция невозможна +notification.start.failed.now=Запуск не удался +notification.start.failed.next=Запуск не удался +notification.payout.result=Результат выплаты {0} +notification.payment.result=Результат оплаты {0} +notification.referral.deposit=Реферальный депозит +notification.referral.registered=Новый реферал зарегистрирован +notification.referral.activated=Реферал активирован +notification.complaint.status=Статус жалобы изменён: {0} +notification.case.status=Статус дела изменён +notification.incoming.message=Новое сообщение +notification.tariff.expiring=Тариф скоро истекает +notification.token.not.found=Недостаточно токенов для операции: {0} +notification.file.moderation=Файл проходит модерацию +notification.file.added=Файл {0} добавлен в систему +notification.file.search=Поиск файла +notification.search.operation.filed=Поиск завершился непредвиденной ошибкой diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties new file mode 100644 index 0000000..7d94e2d --- /dev/null +++ b/src/main/resources/messages_en.properties @@ -0,0 +1,15 @@ +notification.search.result=Search result is ready +notification.monitoring.result=Monitoring result is available +notification.operation.impossible=Operation impossible +notification.start.failed.now=Start failed +notification.start.failed.next=Start failed +notification.payout.result=Payout result +notification.referral.deposit=Referral deposit +notification.referral.registered=New referral registered +notification.referral.activated=Referral activated +notification.complaint.status=Complaint status changed +notification.case.status=Case status changed +notification.incoming.message=New message +notification.tariff.expiring=Tariff expiring soon +notification.file.moderation=File is being moderated +notification.file.added=File {0} added to the system \ No newline at end of file