DmailService.java

package sk.iway.iwcm.dmail.rest;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import sk.iway.iwcm.Identity;
import sk.iway.iwcm.Tools;
import sk.iway.iwcm.common.CloudToolsForCore;
import sk.iway.iwcm.components.users.userdetail.UserDetailsController;
import sk.iway.iwcm.components.users.userdetail.UserDetailsRepository;
import sk.iway.iwcm.components.users.userdetail.UserDetailsService;
import sk.iway.iwcm.dmail.DmailUtil;
import sk.iway.iwcm.dmail.jpa.CampaingsEntity;
import sk.iway.iwcm.dmail.jpa.EmailsEntity;
import sk.iway.iwcm.dmail.jpa.EmailsRepository;
import sk.iway.iwcm.users.UserDetails;
import sk.iway.iwcm.users.UsersDB;

public class DmailService {

    // Private constructor to hide the implicit public one
    private DmailService() {}
    
    /**
     * Returns ID of campaign. If campaign is not saved yet, returns -ID of current user used as temporary ID for nested tables
     * @param entity
     * @param user
     * @return
     */
    public static final Long getCampaignId(CampaingsEntity campaing, UserDetails user) {
        if (campaing != null && campaing.getId() != null && campaing.getId().longValue()>0) return campaing.getId();
        if (user == null) return 0L;
        return Long.valueOf(-user.getUserId());
    }

    //Add emails which belongs to certain user group and campain
    public static void addEmails(List<Integer> groupsAdded, CampaingsEntity campaing, EmailsRepository emailsRepository, UserDetailsRepository userDetailsRepository, HttpServletRequest request) {
        Identity user = UsersDB.getCurrentUser(request);

        //Now get all emails under campain actualy in DB - we need it to prevent duplicity
        Map<String, Integer> emailsTable = new Hashtable<>();
        for (String email : emailsRepository.getAllCampainEmails( DmailService.getCampaignId(campaing, user), CloudToolsForCore.getDomainId()) ) {
            emailsTable.put(email.toLowerCase(), emailsTable.size() + 1);
        }

        //Get all emails under selected user groups
        List<String> recpientEmails = UserDetailsController.getUserEmailsByUserGroupsIds(userDetailsRepository, groupsAdded);

        //Get all unsubscribed emails
        Set<String> unsubscribedEmails = DmailUtil.getUnsubscribedEmails();

        for(String recipientEmail : recpientEmails) {
            //Unsubcribed check
            if(unsubscribedEmails.contains(recipientEmail.toLowerCase()) == true) continue;

            //Check duplicity (if this emial alreadry belongs to campain)
            if(emailsTable.get(recipientEmail.toLowerCase()) != null) continue;
            else emailsTable.put(recipientEmail.toLowerCase(), emailsTable.size() + 1);

            //Check validity then continue
            if (Tools.isEmail(recipientEmail) == true) {
                //Prepare and save email
                EmailsEntity emailToAdd = new EmailsEntity(recipientEmail);
                boolean prepareSuccess = prepareEmailForInsert(campaing, user == null ? 0 : user.getUserId(), emailToAdd);
                if(prepareSuccess == false) continue; //Email is not valid

                //Save record in DB
                emailsRepository.save(emailToAdd);
            } else {
                return;
            }
        }
    }

    //Add and/or remove emails which belongs to campain by ceratin user group
    public static void handleEmails(int[] selectedGroups, int[] originalGroups, CampaingsEntity campaing, EmailsRepository emailsRepository, UserDetailsRepository userDetailsRepository, HttpServletRequest request) {
        /* We need compare saved groups ids and now selected group ids
            so we can add/delete emails mapped on current domain, where reciver belongs to one of that groups*/
        List<Integer> groupsRemoved = new ArrayList<>();
        List<Integer> groupsAdded = new ArrayList<>();
        List<Integer> selectedGroupsList = Arrays.stream(selectedGroups).boxed().toList();

        //Fn handleEmails is called only if selectedGroups != originalGroups
        if(selectedGroups == null || selectedGroups.length == 0) {
            groupsRemoved = Arrays.stream(originalGroups).boxed().collect(Collectors.toList());

        } else if(originalGroups == null || originalGroups.length == 0) {
            groupsAdded = Arrays.stream(selectedGroups).boxed().collect(Collectors.toList());
        } else {
            //Find of groups witch ids were removed from selected
            for(int originalId : originalGroups) {
                boolean find = false;
                for(int selectedId : selectedGroups) {
                    if(originalId == selectedId) {
                        find = true;
                        break;
                    }
                }
                if(!find) groupsRemoved.add(originalId);
            }

            //Find of groups witch ids were added to selected
            for(int selectedId : selectedGroups) {
                boolean find = false;
                for(int originalId : originalGroups) {
                    if(selectedId == originalId) {
                        find = true;
                        break;
                    }
                }
                if(!find) groupsAdded.add(selectedId);
            }
        }

        //toto je zoznam userId ktore musia zostat zachovane
        //jeden user moze byt vo viacerych user skupinach, ked odoberieme, musi zostat ak je v inej
        Set<Integer> mustContainUserId = new HashSet<>();
        List<Integer> userIds = UserDetailsController.getUserIdsByUserGroupsIds(userDetailsRepository, selectedGroupsList);
        for (Integer uid : userIds) {
            mustContainUserId.add(uid);
        }

        if(groupsRemoved.isEmpty()==false) removeEmails(groupsRemoved, mustContainUserId, campaing.getId(), emailsRepository, userDetailsRepository);
        if(groupsAdded.isEmpty()==false) addEmails(groupsAdded, campaing, emailsRepository, userDetailsRepository, request);
    }

    /**
     * Odstrani pouzivatelov v skupine groupsRemoved, zachova ale pouzivatelov v mustContainUserId
     * (user moze byt vo viacerych skupinach, takze moze byt v tej co musi zostat zachovane)
     * @param groupsRemoved
     * @param mustContainUserId
     * @param campainId
     */
    private static void removeEmails(List<Integer> groupsRemoved, Set<Integer> mustContainUserId, Long campainId, EmailsRepository emailsRepository, UserDetailsRepository userDetailsRepository) {

        List<Integer> userIds = UserDetailsController.getUserIdsByUserGroupsIds(userDetailsRepository, groupsRemoved);
        List<Integer> filteredUserIds = new ArrayList<>();

        for (Integer uid : userIds) {
            if (mustContainUserId.contains(uid)) continue;
            filteredUserIds.add(uid);
        }

        //Delete all emails under removed user group
        emailsRepository.deleteCampainEmail(campainId, filteredUserIds, CloudToolsForCore.getDomainId());
    }

    /**
     * Pripravi entity na vlozenie do DB, nastavi udaje podla campaign a podla emailu dohlada userId v databaze pouzivatelov
     * @param campaign
     * @param loggedUserId
     * @param entity
     */
    public static boolean prepareEmailForInsert(CampaingsEntity campaign, int loggedUserId, EmailsEntity email) {

        //trimni email adresu
        if (email.getRecipientEmail()!=null) email.setRecipientEmail(email.getRecipientEmail().trim());

        //sprav lower case
        if (email.getRecipientEmail()!=null) email.setRecipientEmail(email.getRecipientEmail().toLowerCase());

        //Get email recipient(user) using email
        UserDetails recipient = UsersDB.getUserByEmail(email.getRecipientEmail(), 600);
        if(recipient == null) {
            email.setRecipientUserId(-1);
            if(Tools.isEmpty(email.getRecipientName())) email.setRecipientName("- -");
        }
        else {
            //Check if user is valid
            if(UserDetailsService.isUserDisabled(recipient) == true) return false;

            email.setRecipientUserId(recipient.getUserId());
            if(Tools.isEmpty(email.getRecipientName())) email.setRecipientName(recipient.getFullName());
        }

        //Set create values
        if (campaign == null || campaign.getId()==null || campaign.getId().longValue()<1) {
            email.setCampainId((long)-loggedUserId);
            email.setUrl("");
            email.setSubject("");
            email.setSenderName("");
            email.setSenderEmail("");
            email.setCreatedByUserId(loggedUserId);
        } else {
            email.setCampainId(campaign.getId());
            email.setUrl(campaign.getUrl());
            email.setSubject(campaign.getSubject());
            email.setSenderName(campaign.getSenderName());
            email.setSenderEmail(campaign.getSenderEmail());
            email.setCreatedByUserId(loggedUserId);
        }

        email.setCreateDate(new Date());
        email.setRetry(0);

        //Set domainId
        email.setDomainId( CloudToolsForCore.getDomainId() );

        if (email.getId()==null || email.getId().longValue()<1) {
            email.setDisabled(true);
        }

        return true;
    }
}