968 lines
33 KiB
Java
968 lines
33 KiB
Java
/*
|
|
* Copyright (C) 2021 LibreCCM Foundation.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301 USA
|
|
*/
|
|
package org.librecms.pages;
|
|
|
|
import com.arsdigita.kernel.KernelConfig;
|
|
|
|
import org.libreccm.categorization.Category;
|
|
import org.libreccm.categorization.CategoryManager;
|
|
import org.libreccm.categorization.CategoryRepository;
|
|
import org.libreccm.configuration.ConfigurationManager;
|
|
import org.libreccm.l10n.GlobalizationHelper;
|
|
import org.libreccm.sites.Site;
|
|
import org.libreccm.sites.SiteRepository;
|
|
import org.libreccm.theming.ThemeInfo;
|
|
import org.libreccm.theming.ThemeVersion;
|
|
import org.libreccm.theming.Themes;
|
|
import org.libreccm.theming.mvc.ThemesMvc;
|
|
import org.librecms.contentsection.ContentItem;
|
|
import org.librecms.contentsection.ContentItemL10NManager;
|
|
import org.librecms.contentsection.ContentItemManager;
|
|
import org.librecms.contentsection.ContentItemVersion;
|
|
import org.librecms.pages.models.CategoryModel;
|
|
import org.librecms.pages.models.ContentItemModel;
|
|
import org.librecms.pages.models.PagePropertiesModel;
|
|
import org.librecms.pages.models.PageUrlModel;
|
|
import org.librecms.pages.models.SiteInfoModel;
|
|
|
|
import java.net.URI;
|
|
import java.util.Collections;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Objects;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
import java.util.function.Predicate;
|
|
import java.util.stream.Collectors;
|
|
|
|
import javax.annotation.PostConstruct;
|
|
import javax.enterprise.context.RequestScoped;
|
|
import javax.inject.Inject;
|
|
import javax.mvc.Controller;
|
|
import javax.transaction.Transactional;
|
|
import javax.ws.rs.DefaultValue;
|
|
import javax.ws.rs.GET;
|
|
import javax.ws.rs.NotFoundException;
|
|
import javax.ws.rs.Path;
|
|
import javax.ws.rs.PathParam;
|
|
import javax.ws.rs.Produces;
|
|
import javax.ws.rs.QueryParam;
|
|
import javax.ws.rs.WebApplicationException;
|
|
import javax.ws.rs.core.Context;
|
|
import javax.ws.rs.core.Response;
|
|
import javax.ws.rs.core.UriInfo;
|
|
|
|
/**
|
|
* Controller for the pages MVC application responsible for initializing the
|
|
* models used by themes for displaying the pages.
|
|
*
|
|
* This controller is the main entry point for the Pages application, which is
|
|
* the primary entry point for most public sites powered by LibreCMS. Based on
|
|
* the provided path it looks up the matching category and initalizes the models
|
|
* used by the themes to create the public pages. The application is ,as most
|
|
* other frontends of LibreCCM/LibreCMS, based on the EE MVC framework.
|
|
*
|
|
* In the following description, <code>{placeholder}</code> stands for a
|
|
* placeholder for a parameter. The placeholder <code>{path}</code> stands for
|
|
* the requested path. The path might be empty, in this case the root category
|
|
* of the category system associated with the instance of the pages application
|
|
* is used.
|
|
*
|
|
* Depending on the provided path in the URL this controller does the following:
|
|
*
|
|
* <ul>
|
|
* <li>
|
|
* If the requested path does <b>not</b> end with <code>.html</code> or
|
|
* <code>.{lang}.html</code>: Determine the language to use, select the most
|
|
* appropriate language. Redirect the request the
|
|
* <code>/@pages/{path}/index.{lang}.de</code>, where lang is the most
|
|
* approbriate language determined (also called <i>negotiated</i> language).
|
|
* </li>
|
|
* <li>
|
|
* If the requested path ends matches <code>/@pages/{path}/index.html</code>
|
|
* (the exact regex pattern can be found in the documentation of the responsible
|
|
* methods) determine the most appropriate of the available languages and
|
|
* redirect the request <code>/@pages/{path}/index.{lang}.html</code>, where
|
|
* <code>{lang}</code> is the negotiated language.
|
|
* </li>
|
|
* <li>
|
|
* If the requested path ends matches
|
|
* <code>/@pages/{path}/{itemname}.html</code> (the exact regex patterns for
|
|
* <code>{path}</code> and <code>itemname</code> can be found in the
|
|
* documentation of the responsible methods) determine the most appropriate of
|
|
* the available languages and redirect the request to
|
|
* <code>/@pages/{path}/{itemname}.{lang}.html</code>, , where
|
|
* <code>{lang}</code> is the negotiated language.
|
|
* </li>
|
|
* <li>
|
|
* If the request path matches <code>/@pages/{path}/index.{lang}.html</code>
|
|
* display the index page of the category together with the index item of the
|
|
* category, if the category has an index item. If the category has an index
|
|
* item and the index item is not available in the language requested by the
|
|
* <code>{lang}</code> parameter in the path, raise a <code>404 Not Found</code>
|
|
* error using a {@link WebApplicationException}.
|
|
* </li>
|
|
* * <li>
|
|
* If the request path matches
|
|
* <code>/@pages/{path}/{itemname}.{lang}.html</code> display the item with the
|
|
* name provided in the <code>{itemname}</code> parameter. If no item with a
|
|
* matching name is assigned to the category raise a <code>404 Not Found</code>
|
|
* using a {@link WebApplicationException}. Also, if there is a matching item,
|
|
* but it is not available in the language requested by the <code>{lang}</code>
|
|
* parameter, raise a <code>404 Not Found Error</code> using a
|
|
* {@link WebApplicationException}.
|
|
* </li>
|
|
* </ul>
|
|
*
|
|
* In the last two cases this controller will initialize the basic models to
|
|
* provide soem data for displaying theme, and delegate to the theme by calling
|
|
* {@link ThemesMvc#getMvcTemplate(javax.ws.rs.core.UriInfo, java.lang.String, java.lang.String)}.
|
|
* {@link ThemesMvc} will determine the theme to use from the requested URL. For
|
|
* details please refer to the documentation of {@link ThemesMvc}.
|
|
*
|
|
* The following models are initialized by this controller:
|
|
* <ul>
|
|
* <li>{@link CategoryModel}</li>
|
|
* <li>{@link ContentItemModel}</li>
|
|
* <li>{@link SiteInfoModel}</li>
|
|
* </ul>
|
|
*
|
|
* The language to use is determined using the following algorithm:
|
|
* <ol type="1">
|
|
* <li>
|
|
* Check if one of the languages sent by the user agent in the
|
|
* <code>Accept-Language</code> header is a supported language (see
|
|
* {@link KernelConfig#supportedLanguages}. If not fall back to the default
|
|
* language (see {@link KernelConfig#defaultLanguage}.
|
|
* </li>
|
|
* <li>
|
|
* Check if the requested item is available in the selected language, or if a
|
|
* category without an index item is requested, if the category is avaiable for
|
|
* the selected language. If yes use the selected language otherwise fallback to
|
|
* the default default configured in {@link KernelConfig#defaultLanguage}.
|
|
* </li>
|
|
* </ol>
|
|
*
|
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
|
*/
|
|
@Controller
|
|
@RequestScoped
|
|
@Path("/")
|
|
public class PagesController {
|
|
|
|
@Inject
|
|
private CategoryManager categoryManager;
|
|
|
|
@Inject
|
|
private CategoryModel categoryModel;
|
|
|
|
@Inject
|
|
private CategoryRepository categoryRepo;
|
|
|
|
@Inject
|
|
private GlobalizationHelper globalizationHelper;
|
|
|
|
@Inject
|
|
private ConfigurationManager confManager;
|
|
|
|
@Inject
|
|
private ContentItemManager contentItemManager;
|
|
|
|
@Inject
|
|
private ContentItemL10NManager contentItemL10NManager;
|
|
|
|
@Inject
|
|
private ContentItemModel contentItemModel;
|
|
|
|
@Inject
|
|
private PageManager pageManager;
|
|
|
|
@Inject
|
|
private PagePropertiesModel pagePropertiesModel;
|
|
|
|
@Inject
|
|
private PageUrlModel pageUrlModel;
|
|
|
|
@Inject
|
|
private PagesRepository pagesRepo;
|
|
|
|
@Inject
|
|
private PagesService pagesService;
|
|
|
|
@Inject
|
|
private SiteInfoModel siteInfoModel;
|
|
|
|
@Inject
|
|
private SiteRepository siteRepo;
|
|
|
|
@Inject
|
|
private Themes themes;
|
|
|
|
@Inject
|
|
private ThemesMvc themesMvc;
|
|
|
|
private Locale defaultLocale;
|
|
|
|
@PostConstruct
|
|
private void init() {
|
|
final KernelConfig kernelConfig = confManager
|
|
.findConfiguration(KernelConfig.class);
|
|
defaultLocale = kernelConfig.getDefaultLocale();
|
|
}
|
|
|
|
@GET
|
|
@Path("/")
|
|
@Transactional(Transactional.TxType.REQUIRED)
|
|
public Response redirectToIndexPage(
|
|
@Context
|
|
final UriInfo uriInfo,
|
|
@QueryParam("theme")
|
|
@DefaultValue(ThemesMvc.DEFAULT_THEME_PARAM)
|
|
final String theme,
|
|
@QueryParam("preview")
|
|
@DefaultValue("")
|
|
final String preview
|
|
) {
|
|
final String domain = uriInfo.getBaseUri().getHost();
|
|
final Pages pages = getPages(domain);
|
|
final Category category = getCategory(domain, pages, "/");
|
|
final Versions versions = generateFromPreviewParam(preview);
|
|
final String language = determineLanguage(category, versions);
|
|
|
|
categoryModel.init(
|
|
pages.getCategoryDomain(),
|
|
category,
|
|
generateFromPreviewParam(preview).getContentItemVersion()
|
|
);
|
|
pageUrlModel.init(uriInfo);
|
|
|
|
final String indexPage = String.format(
|
|
"/index.%s.html%s",
|
|
language,
|
|
buildQueryParamsStr(preview, theme)
|
|
);
|
|
final URI uri = uriInfo.getBaseUriBuilder().path(indexPage).build();
|
|
return Response.temporaryRedirect(uri).build();
|
|
}
|
|
|
|
@GET
|
|
@Path("/{name:[\\w\\-]+}")
|
|
@Transactional(Transactional.TxType.REQUIRED)
|
|
public Response getRootPage(
|
|
@Context
|
|
final UriInfo uriInfo,
|
|
@PathParam("name") final String itemName,
|
|
@QueryParam("theme")
|
|
@DefaultValue(ThemesMvc.DEFAULT_THEME_PARAM)
|
|
final String theme,
|
|
@QueryParam("preview")
|
|
@DefaultValue("")
|
|
final String preview
|
|
) {
|
|
final String domain = uriInfo.getBaseUri().getHost();
|
|
final Pages pages = getPages(domain);
|
|
final Category category = getCategory(domain, pages, "/");
|
|
final Versions versions = generateFromPreviewParam(preview);
|
|
final String language = determineLanguage(category, versions);
|
|
|
|
categoryModel.init(
|
|
pages.getCategoryDomain(),
|
|
category,
|
|
generateFromPreviewParam(preview).getContentItemVersion()
|
|
);
|
|
pageUrlModel.init(uriInfo);
|
|
|
|
final String itemPage = String.format(
|
|
"/%s.%s.html%s",
|
|
itemName,
|
|
language,
|
|
buildQueryParamsStr(preview, theme)
|
|
);
|
|
final URI uri = uriInfo.getBaseUriBuilder().path(itemPage).build();
|
|
return Response.temporaryRedirect(uri).build();
|
|
}
|
|
|
|
@GET
|
|
@Path("/{name:[\\w\\-]+}.html")
|
|
@Transactional(Transactional.TxType.REQUIRED)
|
|
public Response getRootPageAsHtml(
|
|
@Context final UriInfo uriInfo,
|
|
@QueryParam("theme")
|
|
@DefaultValue(ThemesMvc.DEFAULT_THEME_PARAM)
|
|
final String theme,
|
|
@QueryParam("preview")
|
|
@DefaultValue("")
|
|
final String preview,
|
|
@PathParam("name")
|
|
final String itemName
|
|
) {
|
|
final String domain = uriInfo.getBaseUri().getHost();
|
|
final Pages pages = getPages(domain);
|
|
final Category category = getCategory(domain, pages, "/");
|
|
final Versions versions = generateFromPreviewParam(preview);
|
|
final String language = determineLanguage(category, itemName, versions);
|
|
|
|
categoryModel.init(
|
|
pages.getCategoryDomain(),
|
|
category,
|
|
generateFromPreviewParam(preview).getContentItemVersion()
|
|
);
|
|
pageUrlModel.init(uriInfo);
|
|
|
|
final String itemPage = String.format(
|
|
"/%s.%s.html", itemName, language
|
|
);
|
|
final String path = uriInfo
|
|
.getPath()
|
|
.replace(String.format("%s.html", itemName), itemPage);
|
|
|
|
final URI uri = uriInfo.getBaseUriBuilder().path(path).build();
|
|
return Response.temporaryRedirect(uri).build();
|
|
}
|
|
|
|
@GET
|
|
@Path("/{name:[\\w\\-]+}.{lang:\\w+}.html")
|
|
@Produces("text/html")
|
|
@Transactional(Transactional.TxType.REQUIRED)
|
|
public String getRootPageAsHtml(
|
|
@Context
|
|
final UriInfo uriInfo,
|
|
@PathParam("name")
|
|
final String itemName,
|
|
@PathParam("lang")
|
|
final String language,
|
|
@QueryParam("theme")
|
|
@DefaultValue("--DEFAULT--")
|
|
final String theme,
|
|
@QueryParam("preview")
|
|
@DefaultValue("")
|
|
final String preview
|
|
) {
|
|
// final Versions versions = generateFromPreviewParam(preview);
|
|
//
|
|
// globalizationHelper.setSelectedLocale(new Locale(language));
|
|
//
|
|
// contentItemModel.setItemName(itemName);
|
|
// contentItemModel.setItemVersion(versions.getContentItemVersion());
|
|
//
|
|
// final String domain = uriInfo.getBaseUri().getHost();
|
|
// final Pages pages = getPages(domain);
|
|
// final Site site = pages.getSite();
|
|
// siteInfoModel.setAvailableLanguages(
|
|
// confManager
|
|
// .findConfiguration(KernelConfig.class)
|
|
// .getSupportedLanguages()
|
|
// .stream()
|
|
// .sorted()
|
|
// .collect(Collectors.toList())
|
|
// );
|
|
// siteInfoModel.setDomain(site.getDomainOfSite());
|
|
// siteInfoModel.setHost(domain);
|
|
// siteInfoModel.setName(
|
|
// Optional
|
|
// .ofNullable(site.getDisplayName())
|
|
// .orElse("")
|
|
// );
|
|
// final Category category = getCategory(domain, pages, "/");
|
|
// categoryModel.init(pages.getCategoryDomain(), category);
|
|
// final Page page = pageManager.findPageForCategory(category);
|
|
// pagePropertiesModel.setProperties(page.getProperties());
|
|
// return themesMvc.getMvcTemplate(
|
|
// uriInfo, "pages", page.getDisplayName()
|
|
// );
|
|
return getPageAsHtml(
|
|
uriInfo,
|
|
"/",
|
|
itemName,
|
|
language,
|
|
theme,
|
|
preview
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Retrieve the item page for a category and the content item associated
|
|
* with the category and identified by {@code itemName}.
|
|
*
|
|
* Redirects to
|
|
* {@link #getPageAsHtml(javax.ws.rs.core.UriInfo, java.lang.String, java.lang.String)}.
|
|
*
|
|
* @param uriInfo
|
|
* @param page
|
|
* @param itemName
|
|
* @param theme
|
|
* @param preview
|
|
*
|
|
* @return
|
|
*/
|
|
@GET
|
|
@Path("/{page:[\\w\\-/]+}/{name:[\\w\\-]+}")
|
|
@Transactional(Transactional.TxType.REQUIRED)
|
|
public Response getPage(
|
|
@Context final UriInfo uriInfo,
|
|
@PathParam("page") final String page,
|
|
@PathParam("name") final String itemName,
|
|
@QueryParam("theme")
|
|
@DefaultValue("--DEFAULT--")
|
|
final String theme,
|
|
@QueryParam("preview")
|
|
@DefaultValue("")
|
|
final String preview
|
|
) {
|
|
final String domain = uriInfo.getBaseUri().getHost();
|
|
final Pages pages = getPages(domain);
|
|
final Category category = getCategory(domain, pages, page);
|
|
final Versions versions = generateFromPreviewParam(preview);
|
|
final String language = determineLanguage(category, versions);
|
|
|
|
pageUrlModel.init(uriInfo);
|
|
|
|
final String redirectTo;
|
|
if (uriInfo.getPath().endsWith("/")) {
|
|
redirectTo = String.format(
|
|
"%sindex.%s.html", uriInfo.getPath(), language
|
|
);
|
|
} else {
|
|
final String itemPath = String.format(
|
|
"%s.%s.html%s",
|
|
itemName,
|
|
language,
|
|
buildQueryParamsStr(preview, theme)
|
|
);
|
|
redirectTo = uriInfo.getPath().replace(itemName, itemPath);
|
|
}
|
|
|
|
final URI uri = uriInfo.getBaseUriBuilder().path(redirectTo).build();
|
|
return Response.temporaryRedirect(uri).build();
|
|
}
|
|
|
|
/**
|
|
* Retrieve the item page for a category and the content item associated
|
|
* with the category and identified by {@code itemName}. Redirects to
|
|
* {@link #getPageAsHtml(javax.ws.rs.core.UriInfo, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)}.
|
|
*
|
|
* @param uriInfo
|
|
* @param page
|
|
* @param itemName
|
|
* @param theme
|
|
* @param preview
|
|
*
|
|
* @return
|
|
*/
|
|
@GET
|
|
@Path("/{page:[\\w\\-/]+}/{name:[\\w\\-]+}.html")
|
|
@Transactional(Transactional.TxType.REQUIRED)
|
|
public Response getPageAsHtml(
|
|
@Context final UriInfo uriInfo,
|
|
@PathParam("page") final String page,
|
|
@PathParam("name") final String itemName,
|
|
@QueryParam("theme")
|
|
@DefaultValue("--DEFAULT--")
|
|
final String theme,
|
|
@QueryParam("preview")
|
|
@DefaultValue("")
|
|
final String preview
|
|
) {
|
|
//ToDo Check!
|
|
|
|
final String domain = uriInfo.getBaseUri().getHost();
|
|
final Pages pages = getPages(domain);
|
|
final Category category = getCategory(domain, pages, page);
|
|
final Versions versions = generateFromPreviewParam(preview);
|
|
final String language = determineLanguage(category, versions);
|
|
|
|
pageUrlModel.init(uriInfo);
|
|
|
|
final String redirectTo;
|
|
if (uriInfo.getPath().endsWith("/")) {
|
|
redirectTo = String.format(
|
|
"%sindex.%s.html%s",
|
|
uriInfo.getPath(),
|
|
language,
|
|
buildQueryParamsStr(preview, theme)
|
|
);
|
|
} else {
|
|
final String itemPath = String.format(
|
|
"%s.%s.html%s",
|
|
itemName,
|
|
language,
|
|
buildQueryParamsStr(preview, theme)
|
|
);
|
|
redirectTo = uriInfo.getPath().replace(itemName, itemPath);
|
|
}
|
|
|
|
final URI uri = uriInfo.getBaseUriBuilder().path(redirectTo).build();
|
|
return Response.temporaryRedirect(uri).build();
|
|
}
|
|
|
|
/**
|
|
* Retrieve the item page as HTML for a category and the content item
|
|
* associated with the category and identified by {@code itemName}.
|
|
*
|
|
* @param uriInfo
|
|
* @param pagePath
|
|
* @param itemName
|
|
* @param language
|
|
* @param theme
|
|
* @param preview
|
|
*
|
|
* @return
|
|
*/
|
|
@GET
|
|
@Path("/{pagePath:[\\w\\-/]+}/{name:[\\w\\-]+}.{lang:\\w+}.html")
|
|
@Produces("text/html")
|
|
@Transactional(Transactional.TxType.REQUIRED)
|
|
public String getPageAsHtml(
|
|
@Context
|
|
final UriInfo uriInfo,
|
|
@PathParam("pagePath")
|
|
final String pagePath,
|
|
@PathParam("name")
|
|
final String itemName,
|
|
@PathParam("lang")
|
|
final String language,
|
|
@QueryParam("theme")
|
|
@DefaultValue("--DEFAULT--")
|
|
final String theme,
|
|
@QueryParam("preview")
|
|
@DefaultValue("")
|
|
final String preview
|
|
) {
|
|
final Versions versions = generateFromPreviewParam(preview);
|
|
|
|
globalizationHelper.setSelectedLocale(new Locale(language));
|
|
|
|
contentItemModel.setItemName(itemName);
|
|
final ContentItemVersion version = versions.getContentItemVersion();
|
|
contentItemModel.setItemVersion(versions.getContentItemVersion());
|
|
|
|
final String domain = uriInfo.getBaseUri().getHost();
|
|
final Pages pages = getPages(domain);
|
|
final Site site = pages.getSite();
|
|
siteInfoModel.setAvailableLanguages(
|
|
confManager
|
|
.findConfiguration(KernelConfig.class)
|
|
.getSupportedLanguages()
|
|
.stream()
|
|
.sorted()
|
|
.collect(Collectors.toList())
|
|
);
|
|
|
|
siteInfoModel.setDomain(site.getDomainOfSite());
|
|
siteInfoModel.setHost(domain);
|
|
siteInfoModel.setName(
|
|
Optional
|
|
.ofNullable(site.getDisplayName())
|
|
.orElse("")
|
|
);
|
|
|
|
final Category category = getCategory(domain, pages, pagePath);
|
|
categoryModel.init(pages.getCategoryDomain(), category, version);
|
|
|
|
pageUrlModel.init(uriInfo);
|
|
|
|
final Page page = pageManager.findPageForCategory(category);
|
|
pagePropertiesModel.setProperties(page.getProperties());
|
|
if (itemName.equals("index") || itemName.isBlank()) {
|
|
return themesMvc.getMvcTemplate(
|
|
uriInfo, "pages", page.getDisplayName()
|
|
);
|
|
} else {
|
|
return themesMvc.getMvcTemplate(
|
|
uriInfo, "pages", "item-page"
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
private void initSiteInfoModel(
|
|
final Site site, final String host
|
|
) {
|
|
siteInfoModel.setAvailableLanguages(
|
|
confManager
|
|
.findConfiguration(KernelConfig.class)
|
|
.getSupportedLanguages()
|
|
.stream()
|
|
.sorted()
|
|
.collect(Collectors.toList())
|
|
);
|
|
siteInfoModel.setDomain(site.getDomainOfSite());
|
|
siteInfoModel.setHost(host);
|
|
siteInfoModel.setName(
|
|
Optional
|
|
.ofNullable(site.getDisplayName())
|
|
.orElse("")
|
|
);
|
|
}
|
|
|
|
private Site getSite(final UriInfo uriInfo) {
|
|
final String domain = Objects
|
|
.requireNonNull(uriInfo)
|
|
.getBaseUri()
|
|
.getHost();
|
|
|
|
final Site site;
|
|
if (siteRepo.hasSiteForDomain(domain)) {
|
|
site = siteRepo.findByDomain(domain).get();
|
|
} else {
|
|
site = siteRepo
|
|
.findDefaultSite()
|
|
.orElseThrow(
|
|
() -> new NotFoundException(
|
|
"No matching Site and no default Site."
|
|
)
|
|
);
|
|
}
|
|
|
|
return site;
|
|
}
|
|
|
|
private Pages getPages(final String domain) {
|
|
return pagesRepo
|
|
.findPagesForSite(domain)
|
|
.orElseThrow(
|
|
() -> new NotFoundException(
|
|
String.format(
|
|
"No Pages for domain \"%s\" available.",
|
|
domain
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
private Category getCategory(
|
|
final String domain, final Pages pages, final String pagePath
|
|
) {
|
|
return categoryRepo
|
|
.findByPath(pages.getCategoryDomain(), pagePath)
|
|
.orElseThrow(
|
|
() -> new NotFoundException(
|
|
String.format(
|
|
"No Page for path \"%s\" in site \"%s\"",
|
|
pagePath,
|
|
domain
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
private String determineLanguage(
|
|
final Category category, final Versions versions
|
|
) {
|
|
final Locale negoiatedLocale = globalizationHelper
|
|
.getNegotiatedLocale();
|
|
|
|
if (categoryManager.hasIndexObject(category)) {
|
|
final ContentItem indexItem = getIndexObject(category, versions)
|
|
.get();
|
|
if (contentItemL10NManager.hasLanguage(indexItem, negoiatedLocale)) {
|
|
return negoiatedLocale.toString();
|
|
} else {
|
|
return confManager
|
|
.findConfiguration(KernelConfig.class)
|
|
.getDefaultLanguage();
|
|
}
|
|
} else {
|
|
if (category.getTitle().hasValue(negoiatedLocale)) {
|
|
return negoiatedLocale.toString();
|
|
} else {
|
|
return defaultLocale.toString();
|
|
}
|
|
}
|
|
}
|
|
|
|
private String determineLanguage(
|
|
final Category category,
|
|
final String itemName,
|
|
final Versions versions
|
|
) {
|
|
final Locale negoiatedLocale = globalizationHelper
|
|
.getNegotiatedLocale();
|
|
|
|
final ContentItem contentItem = pagesService.findCategorizedItem(
|
|
category, itemName, versions.getContentItemVersion()
|
|
)
|
|
.orElseThrow(
|
|
() -> new NotFoundException(
|
|
String.format(
|
|
"No item %s found in category %s.",
|
|
itemName,
|
|
categoryManager.getCategoryPath(category)
|
|
)
|
|
)
|
|
);
|
|
|
|
final KernelConfig kernelConfig = confManager.findConfiguration(
|
|
KernelConfig.class
|
|
);
|
|
|
|
if (contentItemL10NManager.hasLanguage(contentItem, negoiatedLocale)) {
|
|
return negoiatedLocale.toString();
|
|
} else if (contentItemL10NManager.hasLanguage(contentItem, kernelConfig
|
|
.getDefaultLocale())) {
|
|
return kernelConfig.getDefaultLanguage();
|
|
} else {
|
|
throw new NotFoundException(
|
|
String.format(
|
|
"No item %s found in category %s.",
|
|
itemName,
|
|
categoryManager.getCategoryPath(category)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
private String buildQueryParamsStr(
|
|
final String previewParam, final String themeParam
|
|
) {
|
|
final String queryString = List
|
|
.of(
|
|
Optional
|
|
.of(themeParam)
|
|
.filter(String::isBlank)
|
|
.map(param -> String.format("theme=%s", param))
|
|
.orElse(""),
|
|
Optional
|
|
.of(previewParam)
|
|
.filter(String::isBlank)
|
|
.map(param -> String.format("preview=%s", param))
|
|
.orElse("")
|
|
)
|
|
.stream()
|
|
.filter(String::isBlank)
|
|
.collect(Collectors.joining("&", "?", ""));
|
|
|
|
if (queryString.length() <= 1) {
|
|
return "";
|
|
}
|
|
|
|
return queryString;
|
|
}
|
|
|
|
private ThemeInfo getTheme(
|
|
final Site site, final String theme, final ThemeVersion themeVersion
|
|
) {
|
|
if ("--DEFAULT--".equals(theme)) {
|
|
return themes
|
|
.getTheme(site.getDefaultTheme(), themeVersion)
|
|
.orElseThrow(
|
|
() -> new WebApplicationException(
|
|
String.format(
|
|
"The configured default theme \"%s\" for "
|
|
+ "site \"%s\" is not available.",
|
|
site.getDefaultTheme(),
|
|
site.getDomainOfSite()
|
|
),
|
|
Response.Status.INTERNAL_SERVER_ERROR
|
|
)
|
|
);
|
|
} else {
|
|
return themes.getTheme(theme, themeVersion)
|
|
.orElseThrow(
|
|
() -> new WebApplicationException(
|
|
String.format(
|
|
"The theme \"%s\" is not available.",
|
|
theme
|
|
),
|
|
Response.Status.BAD_REQUEST
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
private Optional<ContentItem> getIndexObject(
|
|
final Category category, final Versions versions
|
|
) {
|
|
final Predicate<ContentItem> filter;
|
|
if (versions.getContentItemVersion() == ContentItemVersion.DRAFT) {
|
|
filter = (ContentItem item) -> !contentItemManager.isLive(item);
|
|
} else {
|
|
filter = (ContentItem item) -> contentItemManager.isLive(item);
|
|
}
|
|
|
|
return categoryManager
|
|
.getIndexObject(category)
|
|
.stream()
|
|
.filter(object -> object instanceof ContentItem)
|
|
.map(object -> (ContentItem) object)
|
|
.filter(filter)
|
|
.findFirst();
|
|
|
|
}
|
|
|
|
/**
|
|
* Parse the value of the {@code preview} query parameter.
|
|
*
|
|
* @param value The value of the {@code preview} query parameter to parse.
|
|
*
|
|
* @return If the provided value is {@code all} a {@link Versions} object
|
|
* with all versions set to the draft versions is created and
|
|
* returned. If the provided value is {@code null} or empty a
|
|
* {@link Versions} object with fields set the the live versions is
|
|
* returned. Otherwise the values is split into tokens (separated by
|
|
* commas). The values of the returned {@link Versions} depend on
|
|
* presence of certain tokens. At the moment to following tokens are
|
|
* recognised:
|
|
* <dl>
|
|
* <dt>{@code content}</dt>
|
|
* <dd>{@link Versions#contentVersion} is set to
|
|
* {@link ContentItemVersion#DRAFT}</dd>
|
|
* <dt>{@code theme}</dt>
|
|
* <dd>{@link Versions#themeVersion} is set to
|
|
* {@link ThemeVersion#DRAFT}.</dd>
|
|
* </dl>
|
|
*
|
|
*/
|
|
private Versions generateFromPreviewParam(final String value) {
|
|
if (value == null || value.isEmpty() || value.matches("\\s*")) {
|
|
return new Versions(ContentItemVersion.LIVE,
|
|
ThemeVersion.LIVE);
|
|
} else if ("all".equals(value.toLowerCase(Locale.ROOT))) {
|
|
return new Versions(ContentItemVersion.DRAFT,
|
|
ThemeVersion.DRAFT);
|
|
} else {
|
|
final Set<String> values = new HashSet<>();
|
|
Collections.addAll(values,
|
|
value.toLowerCase(Locale.ROOT).split(","));
|
|
|
|
final Versions result = new Versions();
|
|
if (values.contains("content")) {
|
|
result.setContentVersion(ContentItemVersion.DRAFT);
|
|
}
|
|
if (values.contains("theme")) {
|
|
result.setThemeVersion(ThemeVersion.DRAFT);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// private void pageUrlModel.init(final UriInfo uriInfo) {
|
|
// pageUrlModel.setBasePath(uriInfo.getBaseUri().toString());
|
|
// pageUrlModel.setBaseUri(uriInfo.getBaseUri());
|
|
// pageUrlModel.setHost(uriInfo.getRequestUri().getHost());
|
|
//
|
|
// final List<PathSegment> pathSegments = uriInfo.getPathSegments();
|
|
// if (pathSegments.isEmpty()) {
|
|
// throw new IllegalArgumentException("No page segements available.");
|
|
// }
|
|
// pageUrlModel.setPath(
|
|
// pathSegments
|
|
// .subList(0, pathSegments.size())
|
|
// .stream()
|
|
// .map(PathSegment::getPath)
|
|
// .collect(Collectors.joining("/"))
|
|
// );
|
|
// final String pageSegment = pathSegments
|
|
// .get(pathSegments.size() - 1)
|
|
// .getPath();
|
|
// final String[] pageTokens = pageSegment.split("\\.");
|
|
// if (pageTokens.length != 3) {
|
|
// throw new IllegalArgumentException(
|
|
// String.format(
|
|
// "Unexpected number of tokens for page segement of path."
|
|
// + "Expected 3 tokens, separated by '.', but got %d "
|
|
// + "tokens.",
|
|
// pageTokens.length
|
|
// )
|
|
// );
|
|
// }
|
|
// final String pageName = pageTokens[0];
|
|
// final String pageLocale = pageTokens[1];
|
|
// final String pageFormat = pageTokens[2];
|
|
//
|
|
// pageUrlModel.setPageName(pageName);
|
|
// pageUrlModel.setPageLocale(pageLocale);
|
|
// pageUrlModel.setPageFormat(pageFormat);
|
|
//
|
|
// pageUrlModel.setPath(uriInfo.getPath());
|
|
// pageUrlModel.setPort(uriInfo.getRequestUri().getPort());
|
|
// pageUrlModel.setProtocol(uriInfo.getRequestUri().getScheme());
|
|
// pageUrlModel.setQueryParameters(
|
|
// uriInfo
|
|
// .getQueryParameters()
|
|
// .entrySet()
|
|
// .stream()
|
|
// .collect(
|
|
// Collectors.toMap(
|
|
// entry -> entry.getKey(),
|
|
// entry -> entry.getValue().get(0)
|
|
// )
|
|
// )
|
|
// );
|
|
// }
|
|
/**
|
|
* Encapsulate the result of converting the value of the {@code preview}
|
|
* query parameter.
|
|
*/
|
|
private class Versions {
|
|
|
|
/**
|
|
* Version of content to use
|
|
*/
|
|
private ContentItemVersion contentVersion;
|
|
|
|
/**
|
|
* Version of theme to use.
|
|
*/
|
|
private ThemeVersion themeVersion;
|
|
|
|
/**
|
|
* Creates a new {@code Versions} object with all fields set to
|
|
* {@code live} versions.
|
|
*/
|
|
public Versions() {
|
|
this.contentVersion = ContentItemVersion.LIVE;
|
|
this.themeVersion = ThemeVersion.LIVE;
|
|
}
|
|
|
|
/**
|
|
* Create a new {@code Versions} object with the provided parameters.
|
|
*
|
|
* @param contentVersion
|
|
* @param themeVersion
|
|
*/
|
|
public Versions(
|
|
final ContentItemVersion contentVersion,
|
|
final ThemeVersion themeVersion
|
|
) {
|
|
this.contentVersion = contentVersion;
|
|
this.themeVersion = themeVersion;
|
|
}
|
|
|
|
public ContentItemVersion getContentItemVersion() {
|
|
return contentVersion;
|
|
}
|
|
|
|
public void setContentVersion(final ContentItemVersion contentVersion) {
|
|
this.contentVersion = contentVersion;
|
|
}
|
|
|
|
public ThemeVersion getThemeVersion() {
|
|
return themeVersion;
|
|
}
|
|
|
|
public void setThemeVersion(final ThemeVersion themeVersion) {
|
|
this.themeVersion = themeVersion;
|
|
}
|
|
|
|
}
|
|
|
|
}
|