GalleryTreeService.java
package sk.iway.iwcm.components.gallery;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
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.FileTools;
import sk.iway.iwcm.Identity;
import sk.iway.iwcm.Tools;
import sk.iway.iwcm.admin.settings.AdminSettingsService;
import sk.iway.iwcm.common.CloudToolsForCore;
import sk.iway.iwcm.doc.DocDB;
import sk.iway.iwcm.io.IwcmFile;
import sk.iway.iwcm.system.ConfDetails;
import sk.iway.iwcm.system.ConstantsV9;
import sk.iway.iwcm.system.multidomain.MultiDomainFilter;
import sk.iway.iwcm.users.UserDetails;
import sk.iway.iwcm.users.UsersDB;
@Service
@RequestScope
public class GalleryTreeService {
private final GalleryDimensionRepository repository;
private HttpServletRequest request;
private static final String ADMIN_SETTINGS_KEY = "jstreeSettings_gallery";
public GalleryTreeService(GalleryDimensionRepository repository, HttpServletRequest request) {
this.repository = repository;
this.request = request;
}
/**
* Get List of GalleryJsTreeItem for specified URL address (e.g. /images/gallery)
* @param url
* @return
*/
public List<GalleryJsTreeItem> getItems(String url) {
String dir = getRequest().getParameter("dir");
String treeSearchValue = Tools.getStringValue(request.getParameter("treeSearchValue"), null);
Identity user = UsersDB.getCurrentUser(getRequest());
List<IwcmFile> files = new ArrayList<>();
if(Tools.isNotEmpty(treeSearchValue)) {
files.addAll( getAllTreeFiles(url, treeSearchValue) );
} else {
files = getFiles(url);
}
List<GalleryJsTreeItem> items = files.stream().map(f -> new GalleryJsTreeItem(f, dir, repository, user)).toList();
if(Tools.isNotEmpty(treeSearchValue)) {
//Filter items by item.getText
Set<GalleryJsTreeItem> filteredItems = new HashSet<>( filterItems(items, treeSearchValue) );
//Set parent for filtered items
for(GalleryJsTreeItem item : items) {
if(dir.equals(item.getId())) {
//Root item
item.getState().setOpened(false);
item.getState().setSelected(false);
item.setParent("#");
} else {
String parent = item.getVirtualPath().substring(0, item.getVirtualPath().lastIndexOf("/"));
item.setParent(parent);
}
}
//Find parents of filtered items
addParents(filteredItems, items, dir);
//Replace all items with filtered items (+ parents)
items = new ArrayList<>(filteredItems);
}
items = sortFilesBasedOnUserSettings(items, user);
return items;
}
/**
* Loop through filteredItems and add parents to them. Use allItems as source of parents.
* @param filteredItems
* @param allItems
* @param dir
*/
private void addParents(Set<GalleryJsTreeItem> filteredItems, List<GalleryJsTreeItem> allItems, String dir) {
Set<GalleryJsTreeItem> parentsToAdd = new HashSet<>();
//child - entity whos parent we looking for
for(GalleryJsTreeItem child : filteredItems) {
//Loop until we find root (id == dir)
GalleryJsTreeItem parent = child;
while(true) {
//Check if it's root
if(dir.equals(parent.getId())) break;
//No root - find parent
for(GalleryJsTreeItem potencialParent : allItems) {
if(potencialParent.getId().equals(parent.getParent())) {
parentsToAdd.add(potencialParent);
parent = potencialParent;
break;
}
}
}
}
filteredItems.addAll(parentsToAdd);
}
/**
* Filter items by text property. Search is case insensitive and diacritics insensitive.
* @param items
* @param searchText
* @return
*/
private List<GalleryJsTreeItem> filterItems(List<GalleryJsTreeItem> items, String searchText) {
String treeSearchType = Tools.getStringValue(getRequest().getParameter("treeSearchType"), "");
final String wantedValueLC = DB.internationalToEnglish(searchText).toLowerCase();
//Filter by serach value and search type
if("contains".equals(treeSearchType)) {
return items.stream()
.filter(item -> DB.internationalToEnglish(item.getText()).toLowerCase().contains(wantedValueLC))
.toList();
} else if("startwith".equals(treeSearchType)) {
return items.stream()
.filter(item -> DB.internationalToEnglish(item.getText()).toLowerCase().startsWith(wantedValueLC))
.toList();
} else if("endwith".equals(treeSearchType)) {
return items.stream()
.filter(item -> DB.internationalToEnglish(item.getText()).toLowerCase().endsWith(wantedValueLC))
.toList();
} else if("equals".equals(treeSearchType)) {
return items.stream()
.filter(item -> DB.internationalToEnglish(item.getText()).equalsIgnoreCase(wantedValueLC))
.toList();
} else return new ArrayList<>();
}
/**
* Get all files in directory and subdirectories.
* For performance reason, we are
* not searching in file system, we are searching only in database
* @param url - root directory url
* @param treeSearchValue - search value
* @return
*/
private List<IwcmFile> getAllTreeFiles(String url, String treeSearchValue) {
Set<String> paths = new HashSet<>();
List<GalleryDimension> dirs = repository.findByPathLikeAndPathLikeAndDomainId(url+"%", "%"+treeSearchValue+"%", CloudToolsForCore.getDomainId());
dirs.forEach(gallery -> {
if (FileTools.isDirectory(gallery.getPath()) == false) return;
paths.add(gallery.getPath());
//append all parents files starts with url if not allready in map
//eg. for /images/gallery/2021/01/01/1.jpg add /images/gallery/2021/01/01, /images/gallery/2021, /images/gallery
String parent = gallery.getPath();
while(parent.contains("/")) {
parent = parent.substring(0, parent.lastIndexOf("/"));
if(paths.contains(parent) == false && parent.startsWith(url)) paths.add(parent);
}
});
//convert paths into list of string and sort it
List<String> pathsSorted = paths.stream().sorted().collect(Collectors.toList());
//convert paths into IwcmFile list
List<IwcmFile> list = new ArrayList<>();
for(String path : pathsSorted) {
list.add(new IwcmFile(Tools.getRealPath(path)));
}
return list;
}
private List<IwcmFile> getFiles(String url) {
IwcmFile directory = new IwcmFile(Tools.getRealPath(url));
final String urlFinal = url;
if(url == null) return Arrays.asList();
return Arrays.asList(directory.listFiles(file -> {
if (!file.isDirectory()) {
return false;
}
Set<String> blacklistedNames = getBlacklistedNames();
//odstran domenove aliasy z inych domen
if (blacklistedNames.isEmpty() && blacklistedNames.contains(file.getName())) return false;
//toto chceme vzdy
if ("gallery".equals(file.getName())) return true;
if (file.getVirtualPath().contains("gallery")) return true;
//ak ma /images/tento-priecinok podpriecinok gallery tiez ho pridaj (testuje sa len pre prvu uroven)
if ("/images".equals(urlFinal) && FileTools.isDirectory(urlFinal+"/"+file.getName()+"/gallery")) return true;
//ak je nastaveny GalleryDimension povazuj to tiez za galeriu
Optional<GalleryDimension> gallery = repository.findFirstByPathLikeAndDomainId(urlFinal+"/"+file.getName()+"%", CloudToolsForCore.getDomainId());
if (gallery.isPresent()) return true;
return false;
}));
}
private List<GalleryJsTreeItem> sortFilesBasedOnUserSettings(List<GalleryJsTreeItem> files, Identity user) {
String treeSortType = getTreeSortType(user);
boolean treeSortOrderAsc = isTreeSortOrderAsc(user);
Comparator<GalleryJsTreeItem> comparator;
if ("lastModify".equals(treeSortType)) {
comparator = Comparator.comparing(GalleryJsTreeItem::getLastModified);
} else if ("createDate".equals(treeSortType)) {
comparator = Comparator.comparing(GalleryJsTreeItem::getCreateDate);
} else {
//DEFAULT OPTION -> sort by "title"
comparator = Comparator.comparing(GalleryJsTreeItem::getText, String.CASE_INSENSITIVE_ORDER);
}
if (treeSortOrderAsc == false) {
comparator = comparator.reversed();
}
return files.stream()
.sorted(comparator)
.collect(Collectors.toList());
}
private String getTreeSortType(UserDetails user) {
AdminSettingsService ass = new AdminSettingsService(user);
String sortType = ass.getJsonValue(ADMIN_SETTINGS_KEY, "treeSortType");
if(sortType == null || Tools.isEmpty(sortType) == true) return "priority";
else return sortType;
}
private boolean isTreeSortOrderAsc(UserDetails user) {
AdminSettingsService ass = new AdminSettingsService(user);
return ass.getJsonBooleanValue(ADMIN_SETTINGS_KEY, "treeSortOrderAsc");
}
/**
* Black listed names are all domain aliases except current domain alias
* It's to hide other than current domain alias in multidomain setup (without external folders)
* @return
*/
private Set<String> getBlacklistedNames() {
Set<String> blacklistedNames = new HashSet<>();
if (Constants.getBoolean("multiDomainEnabled")) {
String domainAlias = MultiDomainFilter.getDomainAlias(DocDB.getDomain(getRequest()));
if (Tools.isNotEmpty(domainAlias)) {
//blacklistni ostatne aliasy
List<ConfDetails> aliases = ConstantsV9.getValuesStartsWith("multiDomainAlias:");
for (ConfDetails conf : aliases) {
String alias = conf.getValue();
if (Tools.isNotEmpty(alias) && alias.equals(domainAlias)==false) blacklistedNames.add(alias);
}
}
}
return blacklistedNames;
}
private HttpServletRequest getRequest() {
return request;
}
}