package de.is24.infrastructure.gridfs.http.web.controller;
import de.is24.infrastructure.gridfs.http.domain.Container;
import de.is24.infrastructure.gridfs.http.domain.FileInfo;
import de.is24.infrastructure.gridfs.http.domain.FolderInfo;
import de.is24.infrastructure.gridfs.http.domain.RepoEntry;
import de.is24.infrastructure.gridfs.http.domain.SizeProvider;
import de.is24.infrastructure.gridfs.http.domain.SortField;
import de.is24.infrastructure.gridfs.http.domain.SortOrder;
import de.is24.infrastructure.gridfs.http.metadata.YumEntriesHashCalculator;
import de.is24.infrastructure.gridfs.http.repos.RepoService;
import de.is24.infrastructure.gridfs.http.repos.RepositoryInfoProvider;
import de.is24.infrastructure.gridfs.http.web.domain.RepositoryInfo;
import org.joda.time.DateTime;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.Maps.newHashMap;
import static de.is24.infrastructure.gridfs.http.domain.SortOrder.asc;
import static de.is24.infrastructure.gridfs.http.domain.SortOrder.none;
import static java.lang.String.join;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang.WordUtils.capitalize;
import static org.springframework.http.MediaType.*;
import static org.springframework.util.ObjectUtils.nullSafeEquals;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
public abstract class AbstractRepositoryInfoController {
private static final int DEFAULT_OFFSET_STARTING_POINT = 5000;
private static final int DEFAULT_OFFSET_END_POINT = -1;
private static final String MODEL = "model";
public static final String SEARCH_BY = "searchBy";
protected final RepositoryInfoProvider infoProvider;
protected final RepoService repoService;
protected final YumEntriesHashCalculator yumEntriesHashCalculator;
protected final boolean isStatic;
protected AbstractRepositoryInfoController(RepositoryInfoProvider infoProvider, RepoService repoService, YumEntriesHashCalculator yumEntriesHashCalculator,
boolean isStatic) {
this.infoProvider = infoProvider;
this.repoService = repoService;
this.yumEntriesHashCalculator = yumEntriesHashCalculator;
this.isStatic = isStatic;
}
@RequestMapping(method = GET, produces = TEXT_HTML_VALUE)
public ModelAndView getRepositoriesAsHtml(
@RequestParam(value = "search", required = false) String searchBy,
@RequestParam(value = "sortBy", required = false, defaultValue = "name") SortField sortBy,
@RequestParam(value = "order", required = false, defaultValue = "asc") SortOrder sortOrder) {
Map<String, Object> model = new HashMap<>();
model.putAll(sorting(sortBy, sortOrder));
setView(model);
if (isNullOrEmpty(searchBy)) {
Container<FolderInfo> repos = infoProvider.getRepos(sortBy, sortOrder);
repos.setShowInfo(true);
model.put(MODEL, repos);
return new ModelAndView("folderView", model);
} else {
model.put(MODEL, infoProvider.find(searchBy, sortBy, sortOrder));
model.put(SEARCH_BY, searchBy);
return new ModelAndView("searchView", model);
}
}
private void setView(Map<String, Object> model) {
model.put("isStatic", isStatic);
model.put("viewName", isStatic ? "static" : "virtual");
}
@RequestMapping(method = GET, produces = APPLICATION_JSON_VALUE, headers = "Accept=application/json")
@ResponseBody
public Container<? extends SizeProvider> getRepositoriesAsJson(
@RequestParam(value = "sortBy", required = false, defaultValue = "name") SortField sortBy,
@RequestParam(value = "order", required = false, defaultValue = "asc") SortOrder sortOrder,
@RequestParam(value = "search", required = false) String searchBy) {
if (isNullOrEmpty(searchBy)) {
return infoProvider.getRepos(sortBy, sortOrder);
} else {
return infoProvider.find(searchBy, sortBy, sortOrder);
}
}
@RequestMapping(value = "/{repoName}", method = GET, produces = TEXT_HTML_VALUE)
public ModelAndView getArchsAsHtml(
@PathVariable("repoName") String repoName,
@RequestParam(value = "search", required = false) String searchBy,
@RequestParam(value = "sortBy", required = false, defaultValue = "name") SortField sortBy,
@RequestParam(value = "order", required = false, defaultValue = "asc") SortOrder sortOrder) {
Map<String, Object> model = new HashMap<>();
model.putAll(sorting(sortBy, sortOrder));
setView(model);
if (infoProvider.isExternalRepo(repoName)) {
return new ModelAndView("redirect:" + infoProvider.getRedirectUrl(repoName));
}
if (isNullOrEmpty(searchBy)) {
model.put(MODEL, infoProvider.getArchs(repoName, sortBy, sortOrder));
return new ModelAndView("folderView", model);
} else {
model.put(MODEL, infoProvider.find(searchBy, repoName, sortBy, sortOrder));
model.put(SEARCH_BY, searchBy);
return new ModelAndView("searchView", model);
}
}
protected abstract String getRepositoryInfoViewName();
@RequestMapping(value = "/{repoName}/info.html", method = GET, produces = TEXT_HTML_VALUE)
public ModelAndView getRepoInfo(@PathVariable("repoName") String repoName) {
RepoEntry repoEntry = repoService.ensureEntry(repoName, infoProvider.getValidRepoTypes());
return new ModelAndView(getRepositoryInfoViewName(), "repo", repoEntry);
}
@RequestMapping(value = "/{repoName}/info.json", method = GET, produces = APPLICATION_JSON_VALUE)
@ResponseBody
public RepositoryInfo getRepoInfoJson(@PathVariable("repoName") String repoName) {
final RepoEntry repoEntry = repoService.ensureEntry(repoName, infoProvider.getValidRepoTypes());
final boolean needsMetadataUpdate = (!nullSafeEquals(repoEntry.getHashOfEntries(), yumEntriesHashCalculator.hashForRepo(repoName)));
return new RepositoryInfo(repoEntry, needsMetadataUpdate);
}
@RequestMapping(value = "/{repoName}", method = GET, produces = APPLICATION_JSON_VALUE)
@ResponseBody
public Container<? extends SizeProvider> getArchsAsJson(
@PathVariable("repoName") String repoName,
@RequestParam(value = "sortBy", required = false, defaultValue = "name") SortField sortBy,
@RequestParam(value = "order", required = false, defaultValue = "asc") SortOrder sortOrder,
@RequestParam(value = "search", required = false) String searchBy) {
if (isNullOrEmpty(searchBy)) {
return infoProvider.getArchs(repoName, sortBy, sortOrder);
} else {
return infoProvider.find(searchBy, repoName, sortBy, sortOrder);
}
}
@RequestMapping(value = "/{repoName}/{arch}", method = GET, produces = TEXT_HTML_VALUE)
public ModelAndView getFileInfoAsHtml(
@PathVariable("repoName") String repoName,
@PathVariable("arch") String arch,
@RequestParam(value = "search", required = false) String searchBy,
@RequestParam(value = "sortBy", required = false, defaultValue = "name") SortField sortBy,
@RequestParam(value = "order", required = false, defaultValue = "asc") SortOrder sortOrder) {
Map<String, Object> model = new HashMap<>();
model.putAll(sorting(sortBy, sortOrder));
setView(model);
if (infoProvider.isExternalRepo(repoName)) {
return new ModelAndView("redirect:" + infoProvider.getRedirectUrl(repoName, arch));
}
if (isNullOrEmpty(searchBy)) {
model.put(MODEL, infoProvider.getFileInfo(repoName, arch, sortBy, sortOrder));
return new ModelAndView("fileView", model);
} else {
model.put(MODEL, infoProvider.find(searchBy, repoName, arch, sortBy, sortOrder));
model.put(SEARCH_BY, searchBy);
return new ModelAndView("searchView", model);
}
}
@RequestMapping(value = "/{repoName}/{arch}", method = GET, produces = APPLICATION_JSON_VALUE)
@ResponseBody
public Container<FileInfo> getFileInfoAsJson(
@PathVariable("repoName") String repoName,
@PathVariable("arch") String arch,
@RequestParam(value = "sortBy", required = false, defaultValue = "name") SortField sortBy,
@RequestParam(value = "order", required = false, defaultValue = "asc") SortOrder sortOrder) {
return infoProvider.getFileInfo(repoName, arch, sortBy, sortOrder);
}
@RequestMapping(method = GET, produces = TEXT_PLAIN_VALUE)
@ResponseBody
public String getRepoListAsTextPlain(@RequestParam(value = "name", required = false, defaultValue = ".") String name,
@RequestParam(value = "tag", required = false) Set<String> tags,
@RequestParam(value = "notag", required = false) Set<String> notags,
@RequestParam(value = "newer", required = false) Integer newerThanInDays,
@RequestParam(value = "older", required = false) Integer olderThanInDays,
@RequestParam(
value = "showDestination", required = false,
defaultValue = "false"
) boolean showDestination) {
final Set<RepoEntry> repoEntries;
if (isStatic) {
repoEntries = getStaticRepoEntriesForGivenParams(name, tags, notags, newerThanInDays, olderThanInDays);
} else {
repoEntries = getVirtualRepoEntriesForGivenParams(name);
}
if ((repoEntries != null) && (!repoEntries.isEmpty())) {
return handleTargetAndJoinResultString(repoEntries, showDestination);
} else {
return "";
}
}
private Set<RepoEntry> getStaticRepoEntriesForGivenParams(String name, Set<String> tags, Set<String> notags,
Integer newerThanInDays, Integer olderThanInDays) {
Date newerDate = daysToDate(newerThanInDays, DEFAULT_OFFSET_STARTING_POINT);
Date olderDate = daysToDate(olderThanInDays, DEFAULT_OFFSET_END_POINT);
Set<RepoEntry> repoEntries = new HashSet<>();
if (tags != null) {
for (String tag : tags) {
repoEntries.addAll(infoProvider.find(name, tag, newerDate, olderDate));
}
} else {
repoEntries.addAll(infoProvider.find(name, newerDate, olderDate));
}
if (notags != null) {
for (String tag : notags) {
final List<RepoEntry> noTags = infoProvider.find(name, tag, newerDate, olderDate);
repoEntries.removeAll(noTags);
}
}
return repoEntries;
}
private Date daysToDate(Integer minusDaysFromNow, int defaultOffset) {
final DateTime now = DateTime.now();
if (minusDaysFromNow != null) {
return now.minusDays(minusDaysFromNow).toDate();
}
return now.minusDays(defaultOffset).toDate();
}
private Set<RepoEntry> getVirtualRepoEntriesForGivenParams(String name) {
Set<RepoEntry> repoEntries = new HashSet<>();
final List<RepoEntry> repoEntriesList = infoProvider.find(name);
repoEntries.addAll(repoEntriesList);
return repoEntries;
}
private String handleTargetAndJoinResultString(Set<RepoEntry> repoEntries, boolean showDestination) {
if (showDestination) {
return join("\n", repoEntries.stream().map((entry) -> entry.getName() + " : " + entry.getTarget()).collect(toList()));
} else {
return join("\n", repoEntries.stream().map(RepoEntry::getName).collect(toList()));
}
}
protected Map<String, Object> sorting(SortField sortBy, SortOrder sortOrder) {
Map<String, Object> sorting = newHashMap();
for (SortField field : SortField.values()) {
sorting.put("sortOrder" + capitalize(field.name()), asc);
sorting.put("sortOrderDirection" + capitalize(field.name()), none);
}
sorting.put("sortOrder" + capitalize(sortBy.name()), sortOrder.reverse());
sorting.put("sortOrderDirection" + capitalize(sortBy.name()), sortOrder);
return sorting;
}
}