GroupsService.java

package sk.iway.iwcm.editor.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.annotation.RequestScope;

import sk.iway.iwcm.Constants;
import sk.iway.iwcm.DB;
import sk.iway.iwcm.Identity;
import sk.iway.iwcm.Tools;
import sk.iway.iwcm.database.SimpleQuery;
import sk.iway.iwcm.doc.DocDB;
import sk.iway.iwcm.doc.DocDetails;
import sk.iway.iwcm.doc.DocHistory;
import sk.iway.iwcm.doc.DocHistoryRepository;
import sk.iway.iwcm.doc.GroupDetails;
import sk.iway.iwcm.doc.GroupsDB;
import sk.iway.iwcm.editor.rest.GroupSchedulerDto;
import sk.iway.iwcm.editor.rest.GroupSchedulerDtoRepository;
import sk.iway.iwcm.i18n.Prop;
import sk.iway.iwcm.system.datatable.NotifyBean;

/**
 * service class for groups operations
 */
@Service
@RequestScope
public class GroupsService extends NotifyService {

    private GroupSchedulerDtoRepository groupSchedulerDtoRepository;
    private Prop prop;

    @Autowired
    public GroupsService(GroupSchedulerDtoRepository groupSchedulerDtoRepository, HttpServletRequest request) {
        this.groupSchedulerDtoRepository = groupSchedulerDtoRepository;
        this.prop = Prop.getInstance(request);
    }

	/**
	 * Recover group from trash.
	 * It will try to find last parent group from history and use it as recover location.
	 * If no history is found, group will be recovered to root.
	 * @param group
	 * @param currentUser
	 * @return
	 */
    public boolean recoverGroupFromTrash(GroupDetails group, Identity currentUser) {

		if (isInTrash(group) == false) return false; //Group is not in trash

		//Get group by id + chec perms
		GroupsDB groupsDB = GroupsDB.getInstance();

		//Check user perms for dest group
		if(GroupsDB.isGroupEditable(currentUser, group.getGroupId())==false) {
			NotifyBean info = new NotifyBean(prop.getText("editor.recover.notify_title.failed_folder"), prop.getText("editor.recover.notify.no_right"), NotifyBean.NotifyType.WARNING, 60000);
			addNotify(info);
			return false;
		}

		int parentGroupId = 0;
		String parentGroupPath = prop.getText("stat_settings.group_id");
		//get last parent_group_id value from history (groups_scheduler table)
		GroupSchedulerDto latestGroupHistory = groupSchedulerDtoRepository.findFirstByGroupIdAndWhenToPublishNullOrderBySaveDateDesc(Long.valueOf(group.getGroupId()));

		//check if parent exists and NOT in trash
		if (latestGroupHistory != null) {
			GroupDetails parentGroup = groupsDB.getGroup(latestGroupHistory.getParentGroupId());
			if (parentGroup != null && isInTrash(parentGroup) == false) {
				parentGroupId = latestGroupHistory.getParentGroupId();
				parentGroupPath = parentGroup.getFullPath();
			}
		}

		//Set folder derent to root
		group.setParentGroupId( parentGroupId );
		(new SimpleQuery()).execute("UPDATE groups SET parent_group_id=? WHERE group_id=?", parentGroupId, group.getGroupId());

		NotifyBean info = new NotifyBean(prop.getText("editor.recover.notify_title.success_folder"), prop.getText("editor.recover.notify_body.success_group", group.getGroupName(), parentGroupPath), NotifyBean.NotifyType.SUCCESS, 60000);
		addNotify(info);

		//Update sub groups
		StringBuilder groups = new StringBuilder();
		List<GroupDetails> subGroups = groupsDB.getGroupsTree(group.getGroupId(), true, true);
		for (GroupDetails g : subGroups) {
			if (groups.length() > 0) groups.append(',').append(g.getGroupId());
			else groups.append(g.getGroupId());
		}

		//Repo
		DocHistoryRepository docHistoryRepository = Tools.getSpringBean("docHistoryRepository", DocHistoryRepository.class);

		//List of doc id's that available should be updated (depend on history)
		List<Integer> docIdsToChange = (new SimpleQuery()).forListInteger("SELECT doc_id FROM documents WHERE group_id IN (" + groups.toString() + ")");

		//History records
		List<DocHistory> historyRecords = docHistoryRepository.findByDocIdInActual(docIdsToChange);

		List<Integer> availableTrue = new ArrayList<>(); //Update availale to true
		List<Integer> availableFalse = new ArrayList<>(); //Update availale to false
		List<Integer> notFound = new ArrayList<>(); //No history found

		//Loops docIdsToChange and match them with historyRecords
		boolean wasFound = false;
		for(Integer docId : docIdsToChange) {
			wasFound = false;
			for(DocHistory history : historyRecords) {
				if(history.getDocId() == docId) {
					wasFound = true;
					if(history.isAvailable()) availableTrue.add(docId);
					else availableFalse.add(docId);
					break;
				}
			}
			if(!wasFound) notFound.add(docId);
		}

		//If history was not found, check last history with ACTUAL=false (maybe only actual is missing)
		for(Integer notFoundId : notFound) {
			Optional<DocHistory> history = docHistoryRepository.findTopByDocIdOrderBySaveDateDesc(notFoundId);
			boolean available = history.isPresent() ? history.get().isAvailable() : true; //If history record is still not found, set available to true
			if(available) availableTrue.add(notFoundId);
			else availableFalse.add(notFoundId);
		}

		//Updatw doc's available status
		if (availableTrue.isEmpty()==false) (new SimpleQuery()).execute("UPDATE documents SET available="+DB.getBooleanSql(true)+", sync_status=1 WHERE doc_id IN (" + StringUtils.join(availableTrue, ",") + ")");
		if (availableFalse.isEmpty()==false) (new SimpleQuery()).execute("UPDATE documents SET available="+DB.getBooleanSql(false)+", sync_status=1 WHERE doc_id IN (" + StringUtils.join(availableFalse, ",") + ")");

		//aktualizuj FT stplce
		DocDB.updateFileNameField(group.getGroupId());

		//Refresh
		DocDB.getInstance(true);
		GroupsDB.getInstance(true);

        return true;
	}

	/**
	 * Check if group is in trash
	 * @param group
	 * @return
	 */
    public static boolean isInTrash(GroupDetails group) {
        GroupDetails trashGroupDetails = getTrashGroupDetails();
        if (group.getFullPath().startsWith(trashGroupDetails.getFullPath())) return true;
        return false;
    }

	/**
     * Vrati adresar Kos
     * @return
     */
    public static GroupDetails getTrashGroupDetails() {
        GroupsDB groupsDB = GroupsDB.getInstance();
        return groupsDB.getTrashGroup();
    }

    /**
     * Vrati adresar System (lokalny)
     * @return
     */
    public static GroupDetails getSystemGroupDetails() {
        GroupsDB groupsDB = GroupsDB.getInstance();
        GroupDetails system = groupsDB.getLocalSystemGroup();

        //ak sa nenaslo, pouzi globalny
        if (system == null) {
            system = groupsDB.getGroupByPath("/System");
        }

        return system;
    }

	/**
	 * Sort list of groups into tree structure (deeper one last)
	 * @param groups
	 * @return
	 */
	public static List<GroupDetails> sortItIntoTree(List<GroupDetails> groups) {
        Collections.sort(groups, (s1, s2) -> { return s1.getFullPath().split("/").length - s2.getFullPath().split("/").length; });

        List<GroupDetails> sorted = new ArrayList<>();

        for(GroupDetails group : groups) {
            int parentIndex = -1;
            for(int i = 0; i < sorted.size(); i++) {
                if(group.getParentGroupId() == sorted.get(i).getGroupId()) {
                    parentIndex = i;
                    break;
                }
            }
            if(parentIndex == -1) sorted.add(0, group);
            else sorted.add(parentIndex + 1, group);
        }

        return sorted;
    }

	/**
	 * Check if title is syncable between group and webpage
	 * @param docId
	 * @param groupId
	 * @return
	 */
	public static boolean canSyncTitle(Integer docId, Integer groupId) {

		if(Constants.getBoolean("syncGroupAndWebpageTitle")==false) return false;

		if(docId == null || docId.intValue() < 1) return true;

		//Is DOC, main DOC for SEVERAL groups ?
		int defaultDocCount = (new SimpleQuery()).forInt("SELECT COUNT(group_id) FROM groups WHERE default_doc_id = ?", docId);
		if(defaultDocCount > 1) return false;

		//
		GroupDetails group = GroupsDB.getInstance().getGroup(groupId.intValue());
		if(group.getDefaultDocId() != docId) return false;

		return true;
	}

	/**
	 * Check if title is syncable between group and webpages
	 * Used before save of groupDetails
	 * @param toSaveGroup
	 * @return
	 */
	public static boolean canSyncTitle(GroupDetails toSaveGroup) {

		if(Constants.getBoolean("syncGroupAndWebpageTitle")==false) return false;

		if(toSaveGroup == null) return false;

		//Is DOC, main DOC for SEVERAL groups ?
		int defaultDocCount = (new SimpleQuery()).forInt("SELECT COUNT(group_id) FROM groups WHERE default_doc_id = ?", toSaveGroup.getDefaultDocId());
		if(defaultDocCount > 1) return false;

		//Is DOC in another group that current changed group ?
		DocDetails docDetails = DocDB.getInstance().getDoc(toSaveGroup.getDefaultDocId());
		if(docDetails.getGroupId() != toSaveGroup.getGroupId()) return false;

		return true;
	}
}