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

io.thestencil.iam.spi.integrations.UserActionQueryDefault Maven / Gradle / Ivy

The newest version!
package io.thestencil.iam.spi.integrations;

import java.time.LocalDateTime;
import java.time.OffsetDateTime;

/*-
 * #%L
 * iam-api
 * %%
 * Copyright (C) 2021 - 2022 Copyright 2021 ReSys OÜ
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.eclipse.microprofile.jwt.JsonWebToken;

import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import io.thestencil.iam.api.ImmutableUserAction;
import io.thestencil.iam.api.ImmutableUserMessage;
import io.thestencil.iam.api.UserActionsClient.Attachment;
import io.thestencil.iam.api.UserActionsClient.AttachmentQuery;
import io.thestencil.iam.api.UserActionsClient.UserAction;
import io.thestencil.iam.api.UserActionsClient.UserActionQuery;
import io.thestencil.iam.api.UserActionsClient.UserActionsClientConfig;
import io.thestencil.iam.api.UserActionsClient.UserMessage;
import io.thestencil.iam.spi.support.BuilderTemplate;
import io.thestencil.iam.spi.support.PortalAssert;
import io.vertx.core.http.RequestOptions;
import io.vertx.core.json.JsonObject;
import io.vertx.mutiny.ext.web.client.HttpResponse;
import lombok.extern.slf4j.Slf4j;


@Slf4j
public class UserActionQueryDefault extends BuilderTemplate implements UserActionQuery {
  private final UserActionsClientConfig config;
  private final Supplier messages;
  private final Supplier attachments;
  private final Supplier tasks;
  private String userId;
  private String processId;
  private Integer limit;
  private String userName;
  private String representativeUserName;
  
  public UserActionQueryDefault(
      RequestOptions init, UserActionsClientConfig config, 
      Supplier messages,
      Supplier attachments, 
      Supplier tasks, 
      JsonWebToken idToken) {
    super(config.getWebClient(), init, idToken);
    this.config = config;
    this.messages = messages;
    this.attachments = attachments;
    this.tasks = tasks;
  }
  @Override
  public UserActionQuery userId(String userId) {
    this.userId = userId;
    return this;
  }
  @Override
  public UserActionQuery processId(String processId) {
    this.processId = processId;
    return this;
  }
  @Override
  public UserActionQuery userName(String userName) {
    this.userName = userName;
    return this;
  }
  @Override
  public UserActionQuery limit(Integer limit) {
    this.limit = limit;
    return this;
  }
  @Override
  public Multi list() {
    PortalAssert.notEmpty(userId, () -> "userId must be defined!");
    PortalAssert.notEmpty(userName, () -> "userName must be defined!");
    final var tasks = messages.get().getUnreadTasks(userId);
    
    if(processId != null) {
      final var process = super.get(getUri("/processes/" + processId)).send();
      
      return Uni.combine().all().unis(process, tasks).asTuple()
          .onItem()
          .transformToMulti(tuple -> 
            findOne(tuple.getItem1(), tuple.getItem2(), config.getFillPath(), config.getReviewPath(), config.getMessagesPath())
          )
          .onItem()
          .transformToUni(action -> addAttachments(action))
          .concatenate();
    } else {
      final var processes  = super.get(getUri("/processesSearch"))
          .addQueryParam("unpaged", "true")
          .addQueryParam("size", limit == null ? "300" : limit + "")
          .addQueryParam("userId", userId)
          .send();  
      
      return Uni.combine().all().unis(processes, tasks).asTuple()
          .onItem()
          .transformToMulti(tuple -> 
            findAll(tuple.getItem1(), tuple.getItem2(), config.getFillPath(), config.getReviewPath(), config.getMessagesPath())
          )
          .onItem()
          .transformToUni(action -> addAttachments(action))
          .concatenate();
    }
  }

  private Uni addAttachments(UserAction action) {
    final var processAttachments = attachments.get().processId(action.getId());
    final var taskAttachments = action.getTaskId() == null ? 
        Uni.createFrom().item(new ArrayList()) : 
        attachments.get().taskId(action.getTaskId(), action.getId());
    
    return Uni.combine().all().unis(processAttachments, taskAttachments)
        .asTuple().onItem().transform(tuple -> {
          
          final var attachments = new HashMap<>(tuple.getItem1().stream().collect(Collectors.toMap(e -> e.getName(), e -> e)));
          for(final var item : tuple.getItem2()) {
            if(!attachments.containsKey(item.getName())) {
              attachments.put(item.getName(), item);
            }
          }
          
          return ImmutableUserAction.builder()
          .from(action)
          .addAllAttachments(attachments.values())
          .build();
          
        });
        
  }
  
  private Multi findOne(HttpResponse resp, List unreadTasks, String fillUri, String reviewUri, String replyUri) {
    if (resp.statusCode() != 200) {
      log.error("USER ACTIONS, find one: Can't create response, code: {}, message: {}, headers:{}", resp.statusCode(), resp.statusMessage(), resp.headers());
      return Multi.createFrom().empty();
    }
    
    final JsonObject data = resp.bodyAsJsonObject();
    if(data == null) {
      return Multi.createFrom().empty();
    }
    return Multi.createFrom()
        .items(mapToUserAction(data, fillUri, reviewUri, replyUri))
        .onItem().transformToUniAndMerge(action -> createAction(action, unreadTasks));
  }
  
  private Multi findAll(HttpResponse resp, List unreadTasks, String fillUri, String reviewUri, String replyUri) {
    if (resp.statusCode() != 200) {
      log.error("USER ACTIONS, find all: code: {}, message: {}, headers:{} ", resp.statusCode(), resp.statusMessage(), resp.headers());
      return Multi.createFrom().empty();
    }
    
    final JsonObject paged = resp.bodyAsJsonObject();
    final var content = paged.getJsonObject("_embedded");
    if(content == null) {
      return Multi.createFrom().empty();
    }
    
    final var datalist = content.getJsonArray("processDataList");
    if(datalist == null) {
      return Multi.createFrom().empty();
    }
    return Multi.createFrom()
        .items(datalist.stream().map(e -> mapToUserAction((JsonObject) e, fillUri, reviewUri, replyUri)))
        .onItem().transformToUniAndMerge(action -> createAction(action, unreadTasks));
  }
  
  private Uni createAction(UserAction action, List unreadTasks) {
    if(action.getTaskId() != null) {

      return Uni.combine().all()
          .unis(
              messages.get().getTask(action.getTaskId()),
              tasks.get().getTask(action.getTaskId())
          ).asTuple()
          .onItem().transform(tuple -> {
            
            final var src = tuple.getItem1();
            final var task = tuple.getItem2();
            
            var lastUpdate = action.getUpdated();
            final var userMessages = new ArrayList();
            for(final var msg : src) {

              final var userMsg = ImmutableUserMessage.builder()
                  .from(msg)
                  .userName(getMessageUserName(msg))
                  .build();
              userMessages.add(userMsg);
              
              final var msgCreated = OffsetDateTime.parse(msg.getCreated()).toLocalDateTime();
              if(lastUpdate.isBefore(msgCreated)) {
                lastUpdate = msgCreated;
              }
            }
            
            return ImmutableUserAction.builder()
              .from(action)
              .taskStatus(task.getStatus())
              .taskCreated(task.getCreated())
              .taskUpdated(task.getUpdated())
              .taskRef(task.getTaskRef())
              .updated(lastUpdate)
              .addAllMessages(userMessages)
              .viewed(userMessages.isEmpty() || !unreadTasks.contains(action.getTaskId()))
              .build();
          });
    }
    return Uni.createFrom().item(action);    
  }
  
  private String getMessageUserName(UserMessage msg) {
    final var start = msg.getUserName();
    if(start.equals(userName)) {
      return msg.getUserName();
    }
    if(start.equals(representativeUserName)) {
      return msg.getUserName();
    } 
    return "";
  }

  public static UserAction mapToUserAction(JsonObject entity, String fillUri, String reviewUri, String replyUri) {
    final var status = entity.getString("status");
    final var formInProgress = "ANSWERING".equalsIgnoreCase(status) || "CREATED".equalsIgnoreCase(status);
    final var formId = entity.getString("questionnaire");
    return ImmutableUserAction.builder()
        .id(entity.getLong("id") + "")
        .status(status)
        .created(LocalDateTime.parse(entity.getString("created")))
        .updated(LocalDateTime.parse(entity.getString("updated")))
        .name(entity.getString("workflowName"))
        .taskId(entity.getString("task"))
        .messagesUri(replyUri)
        .reviewUri(reviewUri)
        .formUri(fillUri)
        .formId(formId)
        .viewed(true)
        .inputContextId(entity.getString("inputContextId"))
        .inputParentContextId(entity.getString("inputParentContextId"))
        .formInProgress(formInProgress)
        .build();
  }
  @Override
  public UserActionQuery representativeUserName(String representativeUserName) {
    this.representativeUserName = representativeUserName;
    return this;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy