All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.obj.nc.controllers.DeliveryInfoRestController Maven / Gradle / Ivy

/*
 *   Copyright (C) 2021 the original author or authors.
 *
 *   This file is part of Notiflow
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this program.  If not, see .
 */

package com.obj.nc.controllers;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.obj.nc.config.NcAppConfigProperties;
import com.obj.nc.config.PagingConfigProperties;
import com.obj.nc.domain.content.MessageContent;
import com.obj.nc.domain.dto.content.MessageContentDto;
import com.obj.nc.domain.dto.endpoint.ReceivingEndpointDto;
import com.obj.nc.domain.endpoints.ReceivingEndpoint;
import com.obj.nc.domain.event.GenericEvent;
import com.obj.nc.domain.message.Message;
import com.obj.nc.domain.message.MessagePersistentState;
import com.obj.nc.domain.pagination.ResultPage;
import com.obj.nc.flows.deliveryInfo.DeliveryInfoFlow;
import com.obj.nc.functions.processors.deliveryInfo.domain.DeliveryInfo;
import com.obj.nc.functions.processors.deliveryInfo.domain.DeliveryInfo.DELIVERY_STATUS;
import com.obj.nc.repositories.DeliveryInfoRepository;
import com.obj.nc.repositories.EndpointsRepository;
import com.obj.nc.repositories.GenericEventRepository;
import com.obj.nc.repositories.MessageRepository;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Transient;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriComponentsBuilder;

import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

import static com.obj.nc.utils.PagingUtils.createPageRequest;

@Slf4j
@Validated
@RestController
@RequestMapping("/delivery-info")
public class DeliveryInfoRestController {

	@Autowired private DeliveryInfoRepository deliveryRepo;
	@Autowired private EndpointsRepository endpointRepo;
	@Autowired private GenericEventRepository eventRepo;
    @Autowired private MessageRepository messageRepo;
	@Autowired private DeliveryInfoFlow deliveryInfoFlow;
	@Autowired private NcAppConfigProperties ncAppConfigProperties;
	@Autowired private PagingConfigProperties pagingConfigProperties;

	@GetMapping(value = "/events/{eventId}", produces="application/json")
	public ResultPage findDeliveryInfosByEventId(
			@PathVariable (value = "eventId", required = true) String eventId,
			@RequestParam(value = "endpointId", required = false) String endpointId,
			@RequestParam("page") int page,
			@RequestParam("size") int size
	) {
		Pageable pageable = createPageRequest(page, size, pagingConfigProperties);

		UUID endpointUUID = endpointId == null ? null : UUID.fromString(endpointId);

		long total = deliveryRepo.countByEventIdAndEndpointId(UUID.fromString(eventId), endpointUUID);
		List deliveries = deliveryRepo.findByEventIdAndEndpointIdOrderByProcessedOn(
				UUID.fromString(eventId), endpointUUID, pageable.getPageSize(), pageable.getOffset());

		if (deliveries.isEmpty()) {
			log.warn("Failed to map event {} to delivery info. This indicate problem with data - probably no message exists for event.", eventId);
			return new ResultPage<>(Collections.emptyList());
		}

		UUID[] endpointIds = deliveries.stream().map(DeliveryInfo::getEndpointId).toArray(UUID[]::new);
		List messageIds = deliveries.stream().map(DeliveryInfo::getMessageId).collect(Collectors.toList());

		List endpoints = endpointRepo.findByIds(endpointIds);
		List messages = messageRepo.findByIdIn(messageIds);

		List result = deliveries.stream()
				.map(delivery -> {
					UUID epId = delivery.getEndpointId();
					UUID msgId = delivery.getMessageId();

					Optional ep = endpoints.stream().filter(it -> it.getId().equals(epId)).findFirst();
					Optional msg = messages.stream().filter(it -> it.getId().equals(msgId)).findFirst();

					return EndpointDeliveryInfoDto.builder()
							.endpoint(ep.map(ReceivingEndpoint::toDto).orElse(null))
							.message(msg.map(MessagePersistentState::getBody).map(MessageContent::toDto).orElse(null))
							.currentStatus(delivery.getStatus())
							.statusReachedAt(delivery.getProcessedOn())
							.additionalInformation(delivery.getAdditionalInformation())
							.build();
				})
				.collect(Collectors.toList());

		return new ResultPage<>(result, pageable, total);
	}

	@GetMapping(value = "/events/ext/{extEventId}", produces="application/json")
	public ResultPage findDeliveryInfosByExtId(
			@PathVariable (value = "extEventId", required = true) String extEventId,
			@RequestParam(value = "endpointId", required = false) String endpointId,
			@RequestParam("page") int page,
			@RequestParam("size") int size
	) {

		GenericEvent event = eventRepo.findByExternalId(extEventId);
		if (event == null) {
			throw new IllegalArgumentException("Event with " +  extEventId +" external ID not found");
		}

		return findDeliveryInfosByEventId(event.getId().toString(), endpointId, page, size);
	}

	@GetMapping(value = "/messages/{messageId}/mark-as-read")
	public ResponseEntity trackMessageRead(@PathVariable(value = "messageId", required = true) String messageId) {
		ResponseEntity trackingPixelImageRedirectionResponse = ResponseEntity
				.status(HttpStatus.FOUND)
				.location(
						UriComponentsBuilder
								.fromPath(ncAppConfigProperties.getContextPath())
								.path("/resources/images/px.png")
								.build()
								.toUri())
				.build();

		if (deliveryRepo.countByMessageIdAndStatus(UUID.fromString(messageId), DELIVERY_STATUS.READ) > 0) {
			return trackingPixelImageRedirectionResponse;
		}

        MessagePersistentState msgInDb = messageRepo.findById(UUID.fromString(messageId)).get();
        Message msg = msgInDb.toMessage();
        deliveryInfoFlow.createAndPersistReadDeliveryInfo(msg);
        
		return trackingPixelImageRedirectionResponse;
	}

	@GetMapping(value = "/messages/{messageId}", produces="application/json")
	public List findDeliveryInfosByMessageId(
			@PathVariable (value = "messageId", required = true) String messageId) {

		List deliveryInfos = deliveryRepo.findByMessageIdOrderByProcessedOn(UUID.fromString(messageId));

		List infoDtos =  EndpointDeliveryInfoDto.createFrom(deliveryInfos);

		List endpointIds = infoDtos
            .stream()
            .map(i -> i.getEndpointId())
            .collect(Collectors.toList());
		List endpoints = endpointRepo.findByIds(endpointIds.toArray(new UUID[0]));

		Map endpointsById = infoDtos
            .stream()
            .collect(Collectors.toMap(EndpointDeliveryInfoDto::getEndpointId, info->info));

		endpoints.forEach(re-> endpointsById.get(re.getId()).setEndpoint(re.toDto()));

		return infoDtos;
	}

	@Data
	@Builder
	public static class EndpointDeliveryInfoDto {

		@JsonIgnore
		@Transient
		UUID endpointId;

		MessageContentDto message;
		ReceivingEndpointDto endpoint;
		DELIVERY_STATUS currentStatus;
		String additionalInformation;
		Instant statusReachedAt;

		public static List createFrom(List deliveryInfos) {
			List result = new ArrayList<>();

			Map> ep2Infos = deliveryInfos.stream().collect(
					Collectors.groupingBy(
							DeliveryInfo::getEndpointId,
							HashMap::new,
							Collectors.mapping(info->info, Collectors.toList()
					)
				)
			);

			for (UUID endpointId: ep2Infos.keySet()) {
				List infos = ep2Infos.get(endpointId);
				orderByProcessedTimeDescStatus(infos);
				DeliveryInfo lastInfo = infos.get(infos.size()-1);

				EndpointDeliveryInfoDto dto = EndpointDeliveryInfoDto.builder()
					.currentStatus(lastInfo.getStatus())
					.endpointId(endpointId)
					.statusReachedAt(lastInfo.getProcessedOn())
					.additionalInformation(lastInfo.getAdditionalInformation())
					.build();

				result.add(dto);
			}

			return result;
		}

		private static void orderByProcessedTimeDescStatus(List infos) {
			Collections.sort(infos, (i1,i2) -> {
				int timeBased = i1.getProcessedOn().compareTo(i2.getProcessedOn());
				int statusBased = i1.getStatus().compareTo(i2.getStatus()) *1;
				return timeBased == 0 ?  statusBased: timeBased;
			});
		}
	}


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy