librecms-default-theme #20
|
|
@ -107,7 +107,11 @@
|
||||||
<Logger name="org.libreccm.ui.admin.applications.ApplicationsPage"
|
<Logger name="org.libreccm.ui.admin.applications.ApplicationsPage"
|
||||||
level="debug">
|
level="debug">
|
||||||
</Logger>
|
</Logger>
|
||||||
<Logger name="org.librecms.ui.ContentSectionController" level="debug">
|
<Logger name="org.librecms.ui.ContentSectionController"
|
||||||
|
level="debug">
|
||||||
|
</Logger>
|
||||||
|
<Logger name="org.libreccm.categorization.CategoryManager"
|
||||||
|
level="debug">
|
||||||
</Logger>
|
</Logger>
|
||||||
</Loggers>
|
</Loggers>
|
||||||
</Configuration>
|
</Configuration>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
"build": "npm-run-all build:*",
|
"build": "npm-run-all build:*",
|
||||||
"build:mkdir": "shx mkdir -p target/generated-resources/themes/librecms",
|
"build:mkdir": "shx mkdir -p target/generated-resources/themes/librecms",
|
||||||
"build:theme": "shx cp -r src/main/resources/themes/librecms/* target/generated-resources/themes/librecms",
|
"build:theme": "shx cp -r src/main/resources/themes/librecms/* target/generated-resources/themes/librecms",
|
||||||
|
"build:icons": "shx cp node_modules/bootstrap-icons/bootstrap-icons.svg target/generated-resources/themes/librecms/images/",
|
||||||
"build:js": "webpack",
|
"build:js": "webpack",
|
||||||
"build:css": "npm-run-all build:css:*",
|
"build:css": "npm-run-all build:css:*",
|
||||||
"build:css:librecms": "sass src/main/scss/librecms.scss target/generated-resources/themes/librecms/styles/librecms.css",
|
"build:css:librecms": "sass src/main/scss/librecms.scss target/generated-resources/themes/librecms/styles/librecms.css",
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 175 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 174 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 180 KiB |
|
|
@ -0,0 +1,63 @@
|
||||||
|
<#macro "org.librecms.assets.AudioAsset" asset>
|
||||||
|
<figure>
|
||||||
|
<audio controls
|
||||||
|
src="/content-sections/${asset.contentSection}/audiomedia${asset.assetPath}"
|
||||||
|
width="240"></audio>
|
||||||
|
<figcaption>${asset.description}</figcaption>
|
||||||
|
</figure>
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
<#macro "org.librecms.assets.ExternalAudioAsset" asset>
|
||||||
|
<figure>
|
||||||
|
<audio controls src="${asset.url}" width="240"></audio>
|
||||||
|
<figcaption>${asset.description}</figcaption>
|
||||||
|
</figure>
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
<#macro "org.librecms.assets.ExternalVideoAsset" asset>
|
||||||
|
<figure>
|
||||||
|
<video controls src="${asset.url}" width="240"></video>
|
||||||
|
<figcaption>${asset.description}</figcaption>
|
||||||
|
</figure>
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
<#macro "org.librecms.assets.FileAsset" asset>
|
||||||
|
<h3><a href="/content-sections/${asset.contentSection}/files${asset.assetPath}">${asset.title}</a></h3>
|
||||||
|
<p>${asset.description}</p>
|
||||||
|
<small>${asset.mimeType} ${asset.size} Bytes</small>
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
<#macro "org.librecms.assets.Image" asset>
|
||||||
|
<figure>
|
||||||
|
<img src="/content-sections/${asset.contentSection}/images${asset.assetPath}"
|
||||||
|
width="240" />
|
||||||
|
<figcaption>${asset.description}</figcaption>
|
||||||
|
</figure>
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
|
||||||
|
<#macro "org.librecms.assets.RelatedLink" asset>
|
||||||
|
<#if asset.externalLink>
|
||||||
|
<div>
|
||||||
|
<a href="${asset.targetUrl}">${asset.title}</a>
|
||||||
|
<svg class="bi"
|
||||||
|
fill="current-color"
|
||||||
|
height="1em"
|
||||||
|
width="1em">
|
||||||
|
<use xlink:href="${themeUrl}/images/bootstrap-icons.svg#globe" />
|
||||||
|
</svg>
|
||||||
|
<span class="visually-hidden">External link</span>
|
||||||
|
</div>
|
||||||
|
<#else>
|
||||||
|
<a href="${asset.targetItemPath}">${asset.title}</a>
|
||||||
|
</#if>
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
<#macro "org.librecms.assets.VideoAsset" asset>
|
||||||
|
<figure>
|
||||||
|
<video controls
|
||||||
|
src="/content-sections/${asset.contentSection}/videos${asset.assetPath}"
|
||||||
|
width="240"></video>
|
||||||
|
<figcaption>${asset.description}</figcaption>
|
||||||
|
</figure>
|
||||||
|
</#macro>
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
<#import "./main.html.ftl" as main>
|
||||||
|
<#import "./assets.html.ftl" as assets>
|
||||||
|
|
||||||
|
<@main.librecms>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row align-items-start justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<#if CmsPagesContentItemTypeModel.itemClass != "">
|
||||||
|
<#assign itemTemplate = .getOptionalTemplate("./contentitems/${CmsPagesContentItemTypeModel.itemClass}.html.ftl")>
|
||||||
|
<#if itemTemplate.exists>
|
||||||
|
<#import "./contentitems/${CmsPagesContentItemTypeModel.itemClass}.html.ftl" as contentitem>
|
||||||
|
<#else>
|
||||||
|
<#import "./contentitems/default.html.ftl" as contentitem>
|
||||||
|
</#if>
|
||||||
|
<@contentitem.details />
|
||||||
|
</#if>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-4">
|
||||||
|
<#list CmsPagesCategorizedItemModel.attachmentLists as attachmentList>
|
||||||
|
<h2>${attachmentList.title}</h2>
|
||||||
|
<p class="item-description">${attachmentList.description}</p>
|
||||||
|
<#list attachmentList.attachments>
|
||||||
|
<ul class="list-group">
|
||||||
|
<#items as attachment>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<@.vars["assets"][attachment.asset.type] attachment.asset />
|
||||||
|
</li>
|
||||||
|
</#items>
|
||||||
|
</ul>
|
||||||
|
</#list>
|
||||||
|
</#list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<#list CmsPagesItemListModel.getItems()>
|
||||||
|
<div class="row align-items-start">
|
||||||
|
<div class="col-12">
|
||||||
|
<ul class="list-group">
|
||||||
|
<#items as item>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<h2>
|
||||||
|
<a href="/pages/${CmsPagesCategoryModel.category.path}${item.name}.${negotiatedLocale}.html${CmsPagesPageUrlModel.queryString}">${item.title}</a>
|
||||||
|
</h2>
|
||||||
|
<p class="item-description">${item.description}</p>
|
||||||
|
</li>
|
||||||
|
</#items>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</#list>
|
||||||
|
</@main.librecms>
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<#macro details>
|
||||||
|
<h1>${CmsPagesCategorizedItemModel.title}</h1>
|
||||||
|
<p class="item-description">${CmsPagesCategorizedItemModel.description}</p>
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
No template for ${CmsPagesContentItemTypeModel.itemClass} available
|
||||||
|
</div>
|
||||||
|
</#macro>
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
<#import "../assets.html.ftl" as assets>
|
||||||
|
|
||||||
|
<#macro details>
|
||||||
|
<h1>${CmsPagesCategorizedItemModel.title}</h1>
|
||||||
|
<p class="item-description">${CmsPagesCategorizedItemModel.description}</p>
|
||||||
|
|
||||||
|
<div class="float-end">
|
||||||
|
<#list CmsPagesCategorizedItemModel.mediaLists as mediaList>
|
||||||
|
<#list mediaList.attachments as media>
|
||||||
|
<@.vars["assets"][media.asset.type] media.asset />
|
||||||
|
</#list>
|
||||||
|
</#list>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
${CmsPagesArticleModel.text}
|
||||||
|
</div>
|
||||||
|
</#macro>
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<#macro details>
|
||||||
|
<div class="d-flex">
|
||||||
|
<h1>
|
||||||
|
${CmsPagesCategorizedItemModel.title}
|
||||||
|
<span class="badge bg-secondary rounded-pill">
|
||||||
|
${CmsPagesEventModel.getStartDateTime('yyyy-MM-dd')}
|
||||||
|
<#if CmsPagesEventModel.getEndDateTime()??>
|
||||||
|
- ${CmsPagesEventModel.getEndDateTime('yyyy-MM-dd')}
|
||||||
|
</#if>
|
||||||
|
</span>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<p class="item-description">${CmsPagesCategorizedItemModel.description}</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
${CmsPagesEventModel.text}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<#if CmsPagesEventModel.location??>
|
||||||
|
<h2>Location</h2>
|
||||||
|
<div>
|
||||||
|
${CmsPagesEventModel.location}
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
</#macro>
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
<#macro details>
|
||||||
|
<h1>${CmsPagesCategorizedItemModel.title}</h1>
|
||||||
|
<p class="item-description">${CmsPagesCategorizedItemModel.description}</p>
|
||||||
|
|
||||||
|
<h2>${CmsPagesMultiPartArticleModel.currentSectionTitle}</h2>
|
||||||
|
<div>
|
||||||
|
<nav>
|
||||||
|
<ul class="flex-column float-end nav">
|
||||||
|
<#list CmsPagesMultiPartArticleModel.sectionTitles as section>
|
||||||
|
<li class="nav-item">
|
||||||
|
<#if section?index == CmsPagesMultiPartArticleModel.currentSection>
|
||||||
|
<a aria-current="page"
|
||||||
|
class="active nav-link"
|
||||||
|
href="${CmsPagesMultiPartArticleModel.sectionLinks[section?index]}">
|
||||||
|
${section}
|
||||||
|
</a>
|
||||||
|
<#else>
|
||||||
|
<a class="nav-link"
|
||||||
|
href="${CmsPagesMultiPartArticleModel.sectionLinks[section?index]}">
|
||||||
|
${section}
|
||||||
|
</a>
|
||||||
|
</#if>
|
||||||
|
</li>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
${CmsPagesMultiPartArticleModel.currentSectionText}
|
||||||
|
<nav>
|
||||||
|
<ul class="pagination">
|
||||||
|
<#if CmsPagesMultiPartArticleModel.prevSectionLink != "">
|
||||||
|
<li class="list-item">
|
||||||
|
<a class="page-link"
|
||||||
|
href="${CmsPagesMultiPartArticleModel.prevSectionLink}">
|
||||||
|
<svg class="bi"
|
||||||
|
fill="current-color"
|
||||||
|
height="1em"
|
||||||
|
width="1em">
|
||||||
|
<use xlink:href="${themeUrl}/images/bootstrap-icons.svg#caret-left-fill" />
|
||||||
|
</svg>
|
||||||
|
<span class="visually-hidden">Previous</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</#if>
|
||||||
|
<#if CmsPagesMultiPartArticleModel.nextSectionLink != "">
|
||||||
|
<li class="list-item">
|
||||||
|
<a class="page-link"
|
||||||
|
href="${CmsPagesMultiPartArticleModel.nextSectionLink}">
|
||||||
|
<svg class="bi"
|
||||||
|
fill="current-color"
|
||||||
|
height="1em"
|
||||||
|
width="1em">
|
||||||
|
<use xlink:href="${themeUrl}/images/bootstrap-icons.svg#caret-right-fill" />
|
||||||
|
</svg>
|
||||||
|
<span class="visually-hidden">Next</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</#if>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</#macro>
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<#macro details>
|
||||||
|
<div class="d-flex">
|
||||||
|
<h1>
|
||||||
|
${CmsPagesCategorizedItemModel.title}
|
||||||
|
<span class="badge bg-secondary rounded-pill">
|
||||||
|
${CmsPagesNewsModel.getReleaseDate('yyyy-MM-dd')}
|
||||||
|
</span>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<p class="item-description">${CmsPagesCategorizedItemModel.description}</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
${CmsPagesNewsModel.text}
|
||||||
|
</div>
|
||||||
|
</#macro>
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link href="${themeUrl}/styles/librecms.css" rel="stylesheet" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Default Template</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<p>This theme works.</p>
|
||||||
|
<dl>
|
||||||
|
<dt>application</dt>
|
||||||
|
<dd>${application}</dd>
|
||||||
|
<dt>themeUrl</dt>
|
||||||
|
<dd>${themeUrl}</dd>
|
||||||
|
<dt>view</dt>
|
||||||
|
<dd>${view!""}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -1,21 +1,48 @@
|
||||||
<!DOCTYPE html>
|
<#import "./main.html.ftl" as main>
|
||||||
<html>
|
<#-- <#import "./contentitems/${CmsPagesContentItemTypeModel.itemClass}.html.ftl" as contentitem> -->
|
||||||
<head>
|
|
||||||
<link href="${themeUrl}/styles/librecms.css" rel="stylesheet" />
|
<@main.librecms>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>Default Template</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>This theme works.</p>
|
<div class="row align-items-start justify-content-center">
|
||||||
<dl>
|
<div class="col-lg-8">
|
||||||
<dt>application</dt>
|
<#if CmsPagesContentItemTypeModel.itemClass != "">
|
||||||
<dd>${application}</dd>
|
<#assign itemTemplate = .getOptionalTemplate("./contentitems/${CmsPagesContentItemTypeModel.itemClass}.html.ftl")>
|
||||||
<dt>themeUrl</dt>
|
<#if itemTemplate.exists>
|
||||||
<dd>${themeUrl}</dd>
|
<#import "./contentitems/${CmsPagesContentItemTypeModel.itemClass}.html.ftl" as contentitem>
|
||||||
<dt>view</dt>
|
<#else>
|
||||||
<dd>${view!""}</dd>
|
<#import "./contentitems/default.html.ftl" as contentitem>
|
||||||
</dl>
|
</#if>
|
||||||
|
<@contentitem.details />
|
||||||
|
</#if>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
<div class="col-lg-4">
|
||||||
</html>
|
<!-- Attachments -->
|
||||||
|
<h2>Notes</h2>
|
||||||
|
<ul class="list-group mb-4">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p>
|
||||||
|
A side note with some text
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Occaecat sit eu ipsum irure. Enim consectetur aute anim proident sint dolor sint ea ex eu adipisicing et. Veniam laborum mollit velit incididunt aliquip do esse officia eu ea nostrud nulla.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h2>More information</h2>
|
||||||
|
<p>
|
||||||
|
Consequat occaecat eu ullamco amet id tempor.
|
||||||
|
</p>
|
||||||
|
<ul class="list-group mb-4">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p>Anim ex ut reprehenderit in enim id proident duis pariatur est anim do.</p>
|
||||||
|
<a href="https://example.com">A related link</a>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p>Quis minim deserunt incididunt ea voluptate laboris fugiat elit nulla.</p>
|
||||||
|
<a href="https://example.com">Some download link</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</@main.librecms>
|
||||||
|
|
@ -1,13 +1,44 @@
|
||||||
<!DOCTYPE html>
|
<#import "./main.html.ftl" as main>
|
||||||
<html>
|
|
||||||
<head>
|
<@main.librecms>
|
||||||
<link href="${themeUrl}/styles/librecms.css" rel="stylesheet" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>Default Template</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Index page</h1>
|
<div class="row align-items-center">
|
||||||
|
<div class="col">
|
||||||
|
<div class="bg-light mb-4 rounded-3">
|
||||||
|
<div class="container-fluid py-5">
|
||||||
|
<#if CmsPagesCategorizedItemModel.itemAvailable>
|
||||||
|
<h1 class="display-5 fw-bold">
|
||||||
|
${CmsPagesCategorizedItemModel.title}
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
${CmsPagesCategorizedItemModel.description}
|
||||||
|
</p>
|
||||||
|
<a class="btn btn-primary btn-lg"
|
||||||
|
href="#">
|
||||||
|
Find out more
|
||||||
|
</a>
|
||||||
|
<#else>
|
||||||
|
<h1 class="display-5 fw-bold">
|
||||||
|
LibreCMS
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
No index item has been defined.
|
||||||
|
</p>
|
||||||
|
<a class="btn btn-primary btn-lg"
|
||||||
|
href="https://www.libreccm.org">
|
||||||
|
Find out more
|
||||||
|
</a>
|
||||||
|
</#if>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<#-- <#if CmsPagesCategorizedItemModel.itemAvailable>
|
||||||
|
Category has an index item
|
||||||
|
<#else>
|
||||||
|
Category has no index item
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<h2>Index page</h2>
|
||||||
<p>This theme works.</p>
|
<p>This theme works.</p>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>application</dt>
|
<dt>application</dt>
|
||||||
|
|
@ -17,6 +48,126 @@
|
||||||
<dt>view</dt>
|
<dt>view</dt>
|
||||||
<dd>${view!""}</dd>
|
<dd>${view!""}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
|
<h2>From <code>ArticleModel</code></h2>
|
||||||
|
<dl>
|
||||||
|
<dt>Title</dt>
|
||||||
|
<dd>${CmsPagesArticleModel.title}</dd>
|
||||||
|
<dt>Description</dt>
|
||||||
|
<dd>${CmsPagesArticleModel.description}</dd>
|
||||||
|
<dt>Text</dt>
|
||||||
|
<dd>${CmsPagesArticleModel.text}</dd>
|
||||||
|
</dl>
|
||||||
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</body>
|
|
||||||
</html>
|
<div class="row align-items-start justify-content-center">
|
||||||
|
<#list CmsPagesItemListModel.getItems("newslist")>
|
||||||
|
<div class="col">
|
||||||
|
<h2>News</h2>
|
||||||
|
<ul class="list-group">
|
||||||
|
<#items as news>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<h3 class="d-flex w-100 justify-content-between">
|
||||||
|
<div>
|
||||||
|
<a href="/pages${CmsPagesCategoryModel.category.path}${news.name}.${negotiatedLocale}.html${CmsPagesPageUrlModel.queryString}">${news.title}</a>
|
||||||
|
</div>
|
||||||
|
<#-- <div>${news.getReleaseDate('yyyy-MM-dd')}</div> -->
|
||||||
|
<div>${news.getReleaseDate('dd. MMM yyyy')}</div>
|
||||||
|
</h3>
|
||||||
|
<p class="item-description">${news.description}</p>
|
||||||
|
</li>
|
||||||
|
</#items>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</#list>
|
||||||
|
<#list CmsPagesItemListModel.getItems("eventlist")>
|
||||||
|
<div class="col">
|
||||||
|
<h2>Upcoming events</h2>
|
||||||
|
<ul class="list-group">
|
||||||
|
<#items as event>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<h3 class="d-flex w-100 justify-content-between">
|
||||||
|
<div>
|
||||||
|
<a href="/pages${CmsPagesCategoryModel.category.path}${event.name}.${negotiatedLocale}.html${CmsPagesPageUrlModel.queryString}">${event.title}</a>
|
||||||
|
</div>
|
||||||
|
<div>${event.getStartDate('dd. MMM yyyy HH:mm')}</div>
|
||||||
|
</h3>
|
||||||
|
<p class="item-description">${event.description}</p>
|
||||||
|
</li>
|
||||||
|
</#items>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</#list>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<#-- <h2>Item List</h2>
|
||||||
|
<p>Item List size: ${CmsPagesItemListModel.listSize}</p>
|
||||||
|
<dl>
|
||||||
|
<dt>Item List size:</dt>
|
||||||
|
<dd>${CmsPagesItemListModel.listSize}</dd>
|
||||||
|
<dt>Page size</dt>
|
||||||
|
<dd>${CmsPagesItemListModel.pageSize}</dd>
|
||||||
|
<dt>Page</dt>
|
||||||
|
<dd>${CmsPagesItemListModel.page}</dd>
|
||||||
|
<dt>Offset</dt>
|
||||||
|
<dd>${CmsPagesItemListModel.offset}</dd>
|
||||||
|
</dl>
|
||||||
|
<ul>
|
||||||
|
<#list CmsPagesItemListModel.items as item>
|
||||||
|
<li>
|
||||||
|
<dl>
|
||||||
|
<dt>UUID</dt>
|
||||||
|
<dd>${item.uuid}</dd>
|
||||||
|
<dt>displayName</dt>
|
||||||
|
<dd>${item.displayName}</dd>
|
||||||
|
<dt>Name</dt>
|
||||||
|
<dd>${item.name}</dd>
|
||||||
|
<dt>Title</dt>
|
||||||
|
<dd>${item.title}</dd>
|
||||||
|
<dt>description</dt>
|
||||||
|
<dd>${item.description}</dd>
|
||||||
|
<dt>Type</dt>
|
||||||
|
<dd>${item.type}</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>News List</h2>
|
||||||
|
<p>News List size: ${CmsPagesItemListModel.getListSize("newslist")}</p>
|
||||||
|
<dl>
|
||||||
|
<dt>Item List size:</dt>
|
||||||
|
<dd>${CmsPagesItemListModel.getListSize("newslist")}</dd>
|
||||||
|
<dt>Page size</dt>
|
||||||
|
<dd>${CmsPagesItemListModel.getPageSize("newslist")}</dd>
|
||||||
|
<dt>Page</dt>
|
||||||
|
<dd>${CmsPagesItemListModel.getPage("newslist")}</dd>
|
||||||
|
<dt>Offset</dt>
|
||||||
|
<dd>${CmsPagesItemListModel.getOffset("newslist")}</dd>
|
||||||
|
</dl>
|
||||||
|
<ul>
|
||||||
|
<#list CmsPagesItemListModel.getItems("newslist") as item>
|
||||||
|
<li>
|
||||||
|
<dl>
|
||||||
|
<dt>UUID</dt>
|
||||||
|
<dd>${item.uuid}</dd>
|
||||||
|
<dt>displayName</dt>
|
||||||
|
<dd>${item.displayName}</dd>
|
||||||
|
<dt>Name</dt>
|
||||||
|
<dd>${item.name}</dd>
|
||||||
|
<dt>Title</dt>
|
||||||
|
<dd>${item.title}</dd>
|
||||||
|
<dt>description</dt>
|
||||||
|
<dd>${item.description}</dd>
|
||||||
|
<dt>Type</dt>
|
||||||
|
<dd>${item.type}</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
</@main.librecms>
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<#macro librecms scripts=[]>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link href="${themeUrl}/styles/librecms.css" rel="stylesheet" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Default Template</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-expand navbar-light bg-light">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand"
|
||||||
|
href="/pages">
|
||||||
|
<img class="theme-logo img-fluid"
|
||||||
|
src="${themeUrl}/images/librecms.svg" />
|
||||||
|
</a>
|
||||||
|
<button aria-controls="navbarSupportedContent"
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-label="Toggle navigation"
|
||||||
|
class="navbar-toggler"
|
||||||
|
data-bs-toggle="collapse"
|
||||||
|
data-bs-target="#navbar-items"
|
||||||
|
type="button">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse"
|
||||||
|
id="navbar-items">
|
||||||
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
|
<#list CmsPagesCategoryModel.categoryTree.subCategories as category>
|
||||||
|
<li ${category.selected?then("aria-selected=\"page\"","")}
|
||||||
|
class="nav-item ${category.selected?then( "active","")}">
|
||||||
|
<a class="nav-link"
|
||||||
|
href="/pages${category.categoryPath}/index.${negotiatedLocale}.html${CmsPagesPageUrlModel.queryString}">
|
||||||
|
${category.title}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<#nested>
|
||||||
|
</main>
|
||||||
|
<script src="${themeUrl}/scripts/librecms.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</#macro>
|
||||||
|
|
@ -32,6 +32,30 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
"mvc-templates": {
|
"mvc-templates": {
|
||||||
|
"category-page": {
|
||||||
|
"description": {
|
||||||
|
"values": {
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"lang": "en",
|
||||||
|
"value": "Template for category pages."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Category Page Template",
|
||||||
|
"path": "templates/category-page.html.ftl",
|
||||||
|
"title": {
|
||||||
|
"values": {
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"lang": "en",
|
||||||
|
"value": "Category Page Template"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"default": {
|
"default": {
|
||||||
"description": {
|
"description": {
|
||||||
"values": {
|
"values": {
|
||||||
|
|
@ -88,6 +112,7 @@
|
||||||
"@default": "default"
|
"@default": "default"
|
||||||
},
|
},
|
||||||
"pages": {
|
"pages": {
|
||||||
|
"category-page": "category-page",
|
||||||
"index": "index-page",
|
"index": "index-page",
|
||||||
"default": "default",
|
"default": "default",
|
||||||
"@default": "default"
|
"@default": "default"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
$primary: #0A9793;
|
||||||
|
|
||||||
|
a.navbar-brand {
|
||||||
|
max-width: 15%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.imgbox-button {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-description {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
@ -61,6 +61,8 @@ public class CmsConstants {
|
||||||
|
|
||||||
public static final String FORM_ENCTYPE_MULTIPART = "multipart/form-data";
|
public static final String FORM_ENCTYPE_MULTIPART = "multipart/form-data";
|
||||||
|
|
||||||
|
public static final String MEDIA_LIST_PREFIX = ".media-";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constant string used as key for creating service package as a legacy
|
* Constant string used as key for creating service package as a legacy
|
||||||
* application.
|
* application.
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
@ -509,15 +510,29 @@ public class FolderManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.reverse(tokens);
|
Collections.reverse(tokens);
|
||||||
final String path = String.join("/", tokens);
|
final String path = tokens
|
||||||
|
.stream()
|
||||||
|
.filter(token -> !"/".equals(token))
|
||||||
|
.collect(
|
||||||
|
Collectors.joining("/")
|
||||||
|
);
|
||||||
|
//final String path = String.join("/", tokens);
|
||||||
|
|
||||||
if (withContentSection) {
|
if (withContentSection) {
|
||||||
final String sectionName = folder.getSection().getDisplayName();
|
final String sectionName = folder.getSection().getDisplayName();
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
return String.format("%s:/", sectionName);
|
||||||
|
} else {
|
||||||
return String.format("%s:/%s/", sectionName, path);
|
return String.format("%s:/%s/", sectionName, path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
return "/";
|
||||||
} else {
|
} else {
|
||||||
return String.format("/%s/", path);
|
return String.format("/%s/", path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates list with a parent folders of the provided folder.
|
* Creates list with a parent folders of the provided folder.
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,6 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.contentsection.rs;
|
package org.librecms.contentsection.rs;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.librecms.assets.BinaryAssetDataService;
|
|
||||||
import org.librecms.assets.AudioAsset;
|
|
||||||
import org.librecms.contentsection.Asset;
|
|
||||||
import org.librecms.contentsection.AssetRepository;
|
|
||||||
import org.librecms.contentsection.ContentSection;
|
|
||||||
import org.librecms.contentsection.ContentSectionRepository;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -40,6 +31,15 @@ import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.StreamingOutput;
|
import javax.ws.rs.core.StreamingOutput;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.librecms.assets.AudioAsset;
|
||||||
|
import org.librecms.assets.BinaryAssetDataService;
|
||||||
|
import org.librecms.contentsection.Asset;
|
||||||
|
import org.librecms.contentsection.AssetRepository;
|
||||||
|
import org.librecms.contentsection.ContentSection;
|
||||||
|
import org.librecms.contentsection.ContentSectionRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
|
@ -84,7 +84,7 @@ public class AudioMedia {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/{path:^(?!uuid).+$}")
|
@Path("/{path:.+}")
|
||||||
public Response getAudio(
|
public Response getAudio(
|
||||||
@PathParam("content-section") final String sectionName,
|
@PathParam("content-section") final String sectionName,
|
||||||
@PathParam("path") final String path
|
@PathParam("path") final String path
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import java.util.Optional;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import javax.transaction.Transactional;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
|
|
@ -44,7 +45,7 @@ import javax.ws.rs.core.StreamingOutput;
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
*/
|
*/
|
||||||
@RequestScoped
|
@RequestScoped
|
||||||
@Path("/{content-section}/files")
|
@Path("/{content-section}/files/")
|
||||||
public class Files {
|
public class Files {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(Files.class);
|
private static final Logger LOGGER = LogManager.getLogger(Files.class);
|
||||||
|
|
@ -60,6 +61,7 @@ public class Files {
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/uuid-{uuid}")
|
@Path("/uuid-{uuid}")
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Response getFileByUuid(
|
public Response getFileByUuid(
|
||||||
@PathParam("content-section") final String sectionName,
|
@PathParam("content-section") final String sectionName,
|
||||||
@PathParam("uuid") final String uuid
|
@PathParam("uuid") final String uuid
|
||||||
|
|
@ -82,7 +84,9 @@ public class Files {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/{path:^(?!uuid).+$}")
|
//@Path("/{path:^(?!uuid).+$}")
|
||||||
|
@Path("/{path:.+}")
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Response getFile(
|
public Response getFile(
|
||||||
@PathParam("content-section") final String sectionName,
|
@PathParam("content-section") final String sectionName,
|
||||||
@PathParam("path") final String path
|
@PathParam("path") final String path
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,6 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.contentsection.rs;
|
package org.librecms.contentsection.rs;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.librecms.assets.Image;
|
|
||||||
import org.librecms.contentsection.Asset;
|
|
||||||
import org.librecms.contentsection.AssetRepository;
|
|
||||||
import org.librecms.contentsection.ContentSection;
|
|
||||||
import org.librecms.contentsection.ContentSectionRepository;
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -45,6 +37,14 @@ import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.QueryParam;
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.librecms.assets.Image;
|
||||||
|
import org.librecms.contentsection.Asset;
|
||||||
|
import org.librecms.contentsection.AssetRepository;
|
||||||
|
import org.librecms.contentsection.ContentSection;
|
||||||
|
import org.librecms.contentsection.ContentSectionRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
|
@ -139,7 +139,7 @@ public class Images {
|
||||||
* @return A {@link Response} containing the scaled image or an error value.
|
* @return A {@link Response} containing the scaled image or an error value.
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Path("/{path:^(?!uuid).+$}")
|
@Path("/{path:.+}")
|
||||||
public Response getImage(
|
public Response getImage(
|
||||||
@PathParam("content-section") final String sectionName,
|
@PathParam("content-section") final String sectionName,
|
||||||
@PathParam("path") final String path,
|
@PathParam("path") final String path,
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,6 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.contentsection.rs;
|
package org.librecms.contentsection.rs;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.librecms.assets.BinaryAssetDataService;
|
|
||||||
import org.librecms.assets.VideoAsset;
|
|
||||||
import org.librecms.contentsection.Asset;
|
|
||||||
import org.librecms.contentsection.AssetRepository;
|
|
||||||
import org.librecms.contentsection.ContentSection;
|
|
||||||
import org.librecms.contentsection.ContentSectionRepository;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -40,6 +31,15 @@ import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.StreamingOutput;
|
import javax.ws.rs.core.StreamingOutput;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.librecms.assets.BinaryAssetDataService;
|
||||||
|
import org.librecms.assets.VideoAsset;
|
||||||
|
import org.librecms.contentsection.Asset;
|
||||||
|
import org.librecms.contentsection.AssetRepository;
|
||||||
|
import org.librecms.contentsection.ContentSection;
|
||||||
|
import org.librecms.contentsection.ContentSectionRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
|
@ -84,7 +84,7 @@ public class Videos {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/{path:^(?!uuid).+$}")
|
@Path("/{path:.+}")
|
||||||
public Response getVideo(
|
public Response getVideo(
|
||||||
@PathParam("content-section") final String sectionName,
|
@PathParam("content-section") final String sectionName,
|
||||||
@PathParam("path") final String path
|
@PathParam("path") final String path
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import org.librecms.contentsection.ContentItemVersion;
|
||||||
import org.librecms.pages.models.CategoryModel;
|
import org.librecms.pages.models.CategoryModel;
|
||||||
import org.librecms.pages.models.ContentItemModel;
|
import org.librecms.pages.models.ContentItemModel;
|
||||||
import org.librecms.pages.models.PagePropertiesModel;
|
import org.librecms.pages.models.PagePropertiesModel;
|
||||||
|
import org.librecms.pages.models.PageUrlModel;
|
||||||
import org.librecms.pages.models.SiteInfoModel;
|
import org.librecms.pages.models.SiteInfoModel;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
@ -196,6 +197,9 @@ public class PagesController {
|
||||||
@Inject
|
@Inject
|
||||||
private PagePropertiesModel pagePropertiesModel;
|
private PagePropertiesModel pagePropertiesModel;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PageUrlModel pageUrlModel;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PagesRepository pagesRepo;
|
private PagesRepository pagesRepo;
|
||||||
|
|
||||||
|
|
@ -242,6 +246,8 @@ public class PagesController {
|
||||||
final Versions versions = generateFromPreviewParam(preview);
|
final Versions versions = generateFromPreviewParam(preview);
|
||||||
final String language = determineLanguage(category, versions);
|
final String language = determineLanguage(category, versions);
|
||||||
|
|
||||||
|
initPageUrlModel(uriInfo);
|
||||||
|
|
||||||
final String indexPage = String.format(
|
final String indexPage = String.format(
|
||||||
"/index.%s.html%s",
|
"/index.%s.html%s",
|
||||||
language,
|
language,
|
||||||
|
|
@ -271,6 +277,8 @@ public class PagesController {
|
||||||
final Versions versions = generateFromPreviewParam(preview);
|
final Versions versions = generateFromPreviewParam(preview);
|
||||||
final String language = determineLanguage(category, versions);
|
final String language = determineLanguage(category, versions);
|
||||||
|
|
||||||
|
initPageUrlModel(uriInfo);
|
||||||
|
|
||||||
final String itemPage = String.format(
|
final String itemPage = String.format(
|
||||||
"/%s.%s.html%s",
|
"/%s.%s.html%s",
|
||||||
itemName,
|
itemName,
|
||||||
|
|
@ -301,6 +309,8 @@ public class PagesController {
|
||||||
final Versions versions = generateFromPreviewParam(preview);
|
final Versions versions = generateFromPreviewParam(preview);
|
||||||
final String language = determineLanguage(category, itemName, versions);
|
final String language = determineLanguage(category, itemName, versions);
|
||||||
|
|
||||||
|
initPageUrlModel(uriInfo);
|
||||||
|
|
||||||
final String itemPage = String.format(
|
final String itemPage = String.format(
|
||||||
"/%s.%s.html", itemName, language
|
"/%s.%s.html", itemName, language
|
||||||
);
|
);
|
||||||
|
|
@ -407,6 +417,8 @@ public class PagesController {
|
||||||
final Versions versions = generateFromPreviewParam(preview);
|
final Versions versions = generateFromPreviewParam(preview);
|
||||||
final String language = determineLanguage(category, versions);
|
final String language = determineLanguage(category, versions);
|
||||||
|
|
||||||
|
initPageUrlModel(uriInfo);
|
||||||
|
|
||||||
final String redirectTo;
|
final String redirectTo;
|
||||||
if (uriInfo.getPath().endsWith("/")) {
|
if (uriInfo.getPath().endsWith("/")) {
|
||||||
redirectTo = String.format(
|
redirectTo = String.format(
|
||||||
|
|
@ -461,6 +473,8 @@ public class PagesController {
|
||||||
final Versions versions = generateFromPreviewParam(preview);
|
final Versions versions = generateFromPreviewParam(preview);
|
||||||
final String language = determineLanguage(category, versions);
|
final String language = determineLanguage(category, versions);
|
||||||
|
|
||||||
|
initPageUrlModel(uriInfo);
|
||||||
|
|
||||||
final String redirectTo;
|
final String redirectTo;
|
||||||
if (uriInfo.getPath().endsWith("/")) {
|
if (uriInfo.getPath().endsWith("/")) {
|
||||||
redirectTo = String.format(
|
redirectTo = String.format(
|
||||||
|
|
@ -535,6 +549,7 @@ public class PagesController {
|
||||||
.sorted()
|
.sorted()
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
);
|
);
|
||||||
|
initPageUrlModel(uriInfo);
|
||||||
siteInfoModel.setDomain(site.getDomainOfSite());
|
siteInfoModel.setDomain(site.getDomainOfSite());
|
||||||
siteInfoModel.setHost(domain);
|
siteInfoModel.setHost(domain);
|
||||||
siteInfoModel.setName(
|
siteInfoModel.setName(
|
||||||
|
|
@ -546,9 +561,16 @@ public class PagesController {
|
||||||
categoryModel.init(pages.getCategoryDomain(), category, version);
|
categoryModel.init(pages.getCategoryDomain(), category, version);
|
||||||
final Page page = pageManager.findPageForCategory(category);
|
final Page page = pageManager.findPageForCategory(category);
|
||||||
pagePropertiesModel.setProperties(page.getProperties());
|
pagePropertiesModel.setProperties(page.getProperties());
|
||||||
|
if (itemName.equals("index") || itemName.isBlank()) {
|
||||||
return themesMvc.getMvcTemplate(
|
return themesMvc.getMvcTemplate(
|
||||||
uriInfo, "pages", page.getDisplayName()
|
uriInfo, "pages", page.getDisplayName()
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return themesMvc.getMvcTemplate(
|
||||||
|
uriInfo, "pages", "item-page"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initSiteInfoModel(
|
private void initSiteInfoModel(
|
||||||
|
|
@ -806,6 +828,25 @@ public class PagesController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initPageUrlModel(final UriInfo uriInfo) {
|
||||||
|
pageUrlModel.setHost(uriInfo.getRequestUri().getHost());
|
||||||
|
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}
|
* Encapsulate the result of converting the value of the {@code preview}
|
||||||
* query parameter.
|
* query parameter.
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,16 @@ implements AssetModelBuilder<T, M> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public M buildAssetModel(final T asset) {
|
public M buildAssetModel(final Asset asset) {
|
||||||
|
if (!asset.getClass().isAssignableFrom(buildsAssetModelFor())) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"This builder can only process Assets of type %s.",
|
||||||
|
buildsAssetModelFor().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final M model = buildModel();
|
final M model = buildModel();
|
||||||
model.setDisplayName(asset.getDisplayName());
|
model.setDisplayName(asset.getDisplayName());
|
||||||
model.setTitle(
|
model.setTitle(
|
||||||
|
|
@ -45,7 +54,7 @@ implements AssetModelBuilder<T, M> {
|
||||||
);
|
);
|
||||||
model.setUuid(asset.getUuid());
|
model.setUuid(asset.getUuid());
|
||||||
|
|
||||||
addProperties(asset, model);
|
addProperties((T) asset, model);
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ package org.librecms.pages.models;
|
||||||
import org.libreccm.l10n.GlobalizationHelper;
|
import org.libreccm.l10n.GlobalizationHelper;
|
||||||
import org.librecms.assets.BinaryAsset;
|
import org.librecms.assets.BinaryAsset;
|
||||||
import org.librecms.contentsection.AssetManager;
|
import org.librecms.contentsection.AssetManager;
|
||||||
|
import org.librecms.contentsection.Folder;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.transaction.Transactional;
|
import javax.transaction.Transactional;
|
||||||
|
|
||||||
|
|
@ -32,7 +32,6 @@ import javax.transaction.Transactional;
|
||||||
* @param <T>
|
* @param <T>
|
||||||
* @param <M>
|
* @param <M>
|
||||||
*/
|
*/
|
||||||
@RequestScoped
|
|
||||||
public abstract class AbstractBinaryAssetModelBuilder<T extends BinaryAsset, M extends BinaryAssetModel>
|
public abstract class AbstractBinaryAssetModelBuilder<T extends BinaryAsset, M extends BinaryAssetModel>
|
||||||
extends AbstractAssetModelBuilder<T, M> {
|
extends AbstractAssetModelBuilder<T, M> {
|
||||||
|
|
||||||
|
|
@ -48,6 +47,12 @@ public abstract class AbstractBinaryAssetModelBuilder<T extends BinaryAsset, M e
|
||||||
super.addProperties(asset, model);
|
super.addProperties(asset, model);
|
||||||
model.setAssetPath(assetManager.getAssetPath(asset));
|
model.setAssetPath(assetManager.getAssetPath(asset));
|
||||||
model.setBinaryAssetUuid(asset.getUuid());
|
model.setBinaryAssetUuid(asset.getUuid());
|
||||||
|
model.setContentSection(
|
||||||
|
assetManager
|
||||||
|
.getAssetFolder(asset)
|
||||||
|
.map(folder -> folder.getSection().getDisplayName())
|
||||||
|
.orElse("")
|
||||||
|
);
|
||||||
model.setDescription(
|
model.setDescription(
|
||||||
globalizationHelper.getValueFromLocalizedString(
|
globalizationHelper.getValueFromLocalizedString(
|
||||||
asset.getDescription()
|
asset.getDescription()
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.pages.models;
|
package org.librecms.pages.models;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simplified representation of a content item for use in a list of content
|
* A simplified representation of a content item for use in a list of content
|
||||||
* items.Base class for other more specific models.
|
* items.Base class for other more specific models.
|
||||||
|
|
@ -26,6 +28,12 @@ package org.librecms.pages.models;
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractContentItemListItemModel {
|
public abstract class AbstractContentItemListItemModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The locale negotiated with the user agent. Useful for example for
|
||||||
|
* formatting date. Only for internal use.
|
||||||
|
*/
|
||||||
|
private Locale locale;
|
||||||
|
|
||||||
private String uuid;
|
private String uuid;
|
||||||
|
|
||||||
private String displayName;
|
private String displayName;
|
||||||
|
|
@ -36,6 +44,14 @@ public abstract class AbstractContentItemListItemModel {
|
||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
protected Locale getLocale() {
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setLocale(final Locale locale) {
|
||||||
|
this.locale = locale;
|
||||||
|
}
|
||||||
|
|
||||||
public String getUuid() {
|
public String getUuid() {
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
@ -76,6 +92,10 @@ public abstract class AbstractContentItemListItemModel {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getLang() {
|
||||||
|
return locale.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the type of the content item. In most cases implementations
|
* Returns the type of the content item. In most cases implementations
|
||||||
* should return the fully qualified name of the content item class here.
|
* should return the fully qualified name of the content item class here.
|
||||||
|
|
|
||||||
|
|
@ -39,16 +39,14 @@ public abstract class AbstractContentItemListItemModelBuilder<T extends ContentI
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public M buildListItemModel(final ContentItem contentItem) {
|
public M buildListItemModel(final ContentItem contentItem) {
|
||||||
final M model = buildModel();
|
final M model = buildModel();
|
||||||
|
model.setLocale(globalizationHelper.getNegotiatedLocale());
|
||||||
|
|
||||||
model.setDescription(
|
model.setDescription(
|
||||||
globalizationHelper.getValueFromLocalizedString(
|
globalizationHelper.getValueFromLocalizedString(
|
||||||
contentItem.getDescription()
|
contentItem.getDescription()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
model.setName(
|
model.setName(contentItem.getDisplayName());
|
||||||
globalizationHelper.getValueFromLocalizedString(
|
|
||||||
contentItem.getName()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
model.setDisplayName(contentItem.getDisplayName());
|
model.setDisplayName(contentItem.getDisplayName());
|
||||||
model.setTitle(
|
model.setTitle(
|
||||||
globalizationHelper.getValueFromLocalizedString(
|
globalizationHelper.getValueFromLocalizedString(
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,12 @@ import org.libreccm.l10n.GlobalizationHelper;
|
||||||
import org.librecms.contentsection.ContentItem;
|
import org.librecms.contentsection.ContentItem;
|
||||||
import org.librecms.contenttypes.Article;
|
import org.librecms.contenttypes.Article;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.transaction.Transactional;
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for getting the special properties of an {@link Article}. For general
|
* Model for getting the special properties of an {@link Article}. For general
|
||||||
|
|
@ -36,7 +37,7 @@ import javax.ws.rs.core.Response;
|
||||||
*/
|
*/
|
||||||
@RequestScoped
|
@RequestScoped
|
||||||
@Named("CmsPagesArticleModel")
|
@Named("CmsPagesArticleModel")
|
||||||
public class ArticleModel {
|
public class ArticleModel implements ProcessesContentItem {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ContentItemModel contentItemModel;
|
private ContentItemModel contentItemModel;
|
||||||
|
|
@ -44,34 +45,63 @@ public class ArticleModel {
|
||||||
@Inject
|
@Inject
|
||||||
private GlobalizationHelper globalizationHelper;
|
private GlobalizationHelper globalizationHelper;
|
||||||
|
|
||||||
|
private boolean initialized;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
public ArticleModel() {
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return globalizationHelper
|
contentItemModel.init();
|
||||||
.getValueFromLocalizedString(getArticle().getTitle());
|
|
||||||
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return globalizationHelper
|
contentItemModel.init();
|
||||||
.getValueFromLocalizedString(getArticle().getDescription());
|
|
||||||
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return globalizationHelper
|
contentItemModel.init();
|
||||||
.getValueFromLocalizedString(getArticle().getText());
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
@Override
|
||||||
|
public void init(final ContentItem contentItem) {
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Article getArticle() {
|
|
||||||
final ContentItem contentItem = contentItemModel.getContentItem();
|
|
||||||
if (contentItem instanceof Article) {
|
if (contentItem instanceof Article) {
|
||||||
return (Article) contentItem;
|
final Article article = (Article) contentItem;
|
||||||
} else {
|
|
||||||
throw new WebApplicationException(
|
title = Optional
|
||||||
"Current content item is not an article.",
|
.ofNullable(article.getText())
|
||||||
Response
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
.status(Response.Status.INTERNAL_SERVER_ERROR)
|
.orElse("");
|
||||||
.entity("Current content item is not an article.")
|
description = Optional
|
||||||
.build()
|
.ofNullable(article.getDescription())
|
||||||
);
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
|
.orElse("");
|
||||||
|
text = Optional
|
||||||
|
.ofNullable(article.getText())
|
||||||
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import org.librecms.contentsection.Asset;
|
||||||
*/
|
*/
|
||||||
public interface AssetModelBuilder<T extends Asset, M extends AbstractAssetModel> {
|
public interface AssetModelBuilder<T extends Asset, M extends AbstractAssetModel> {
|
||||||
|
|
||||||
M buildAssetModel(T asset);
|
M buildAssetModel(Asset asset);
|
||||||
|
|
||||||
Class<T> buildsAssetModelFor();
|
Class<T> buildsAssetModelFor();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.models;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
public class AttachmentListModel implements Comparable<AttachmentListModel>{
|
||||||
|
|
||||||
|
private long listId;
|
||||||
|
|
||||||
|
private String uuid;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private long listOrder;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private List<AttachmentModel> attachments;
|
||||||
|
|
||||||
|
public long getListId() {
|
||||||
|
return listId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setListId(final long listId) {
|
||||||
|
this.listId = listId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuid(final String uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getListOrder() {
|
||||||
|
return listOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setListOrder(final long listOrder) {
|
||||||
|
this.listOrder = listOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(final String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(final String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AttachmentModel> getAttachments() {
|
||||||
|
return Collections.unmodifiableList(attachments);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttachments(final List<AttachmentModel> attachments) {
|
||||||
|
this.attachments = new ArrayList<>(attachments);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(final AttachmentListModel other) {
|
||||||
|
return Comparator
|
||||||
|
.comparing(AttachmentListModel::getListOrder)
|
||||||
|
.thenComparing(
|
||||||
|
AttachmentListModel::getName, String::compareToIgnoreCase
|
||||||
|
)
|
||||||
|
.compare(this, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.models;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
public class AttachmentModel implements Comparable<AttachmentModel>{
|
||||||
|
|
||||||
|
private long attachmentId;
|
||||||
|
|
||||||
|
private String uuid;
|
||||||
|
|
||||||
|
private long sortKey;
|
||||||
|
|
||||||
|
private AbstractAssetModel asset;
|
||||||
|
|
||||||
|
public long getAttachmentId() {
|
||||||
|
return attachmentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttachmentId(final long attachmentId) {
|
||||||
|
this.attachmentId = attachmentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuid(final String uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSortKey() {
|
||||||
|
return sortKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortKey(final long sortKey) {
|
||||||
|
this.sortKey = sortKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractAssetModel getAsset() {
|
||||||
|
return asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAsset(final AbstractAssetModel asset) {
|
||||||
|
this.asset = asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(final AttachmentModel other) {
|
||||||
|
return Comparator
|
||||||
|
.comparing(AttachmentModel::getSortKey)
|
||||||
|
.thenComparing(AttachmentModel::getAttachmentId)
|
||||||
|
.compare(this, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -36,6 +36,8 @@ public class BinaryAssetModel extends AbstractAssetModel {
|
||||||
|
|
||||||
private String binaryAssetUuid;
|
private String binaryAssetUuid;
|
||||||
|
|
||||||
|
private String contentSection;
|
||||||
|
|
||||||
private String assetPath;
|
private String assetPath;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -83,6 +85,14 @@ public class BinaryAssetModel extends AbstractAssetModel {
|
||||||
this.binaryAssetUuid = binaryAssetUuid;
|
this.binaryAssetUuid = binaryAssetUuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getContentSection() {
|
||||||
|
return contentSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentSection(final String contentSection) {
|
||||||
|
this.contentSection = contentSection;
|
||||||
|
}
|
||||||
|
|
||||||
public String getAssetPath() {
|
public String getAssetPath() {
|
||||||
return assetPath;
|
return assetPath;
|
||||||
}
|
}
|
||||||
|
|
@ -91,8 +101,4 @@ public class BinaryAssetModel extends AbstractAssetModel {
|
||||||
this.assetPath = assetPath;
|
this.assetPath = assetPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,28 +18,35 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.pages.models;
|
package org.librecms.pages.models;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.libreccm.categorization.CategoryManager;
|
|
||||||
import org.libreccm.categorization.CategoryRepository;
|
import org.libreccm.categorization.CategoryRepository;
|
||||||
|
import org.libreccm.core.CcmObject;
|
||||||
import org.libreccm.l10n.GlobalizationHelper;
|
import org.libreccm.l10n.GlobalizationHelper;
|
||||||
|
import org.librecms.CmsConstants;
|
||||||
|
import org.librecms.contentsection.Asset;
|
||||||
import org.librecms.contentsection.AttachmentList;
|
import org.librecms.contentsection.AttachmentList;
|
||||||
import org.librecms.contentsection.ContentItem;
|
import org.librecms.contentsection.ContentItem;
|
||||||
import org.librecms.contentsection.ContentItemVersion;
|
import org.librecms.contentsection.ContentItemVersion;
|
||||||
|
import org.librecms.contentsection.ItemAttachment;
|
||||||
|
import org.librecms.pages.PagesController;
|
||||||
|
import org.librecms.pages.PagesRouter;
|
||||||
import org.librecms.pages.PagesService;
|
import org.librecms.pages.PagesService;
|
||||||
|
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Date;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
|
import javax.enterprise.inject.Instance;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.persistence.EntityManager;
|
import javax.transaction.Transactional;
|
||||||
import javax.ws.rs.NotFoundException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a categorized content item for the current category. To work, the
|
* Retrieves a categorized content item for the current category. To work, the
|
||||||
|
|
@ -53,173 +60,373 @@ import javax.ws.rs.NotFoundException;
|
||||||
@Named("CmsPagesCategorizedItemModel")
|
@Named("CmsPagesCategorizedItemModel")
|
||||||
public class ContentItemModel {
|
public class ContentItemModel {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(
|
/**
|
||||||
ContentItemModel.class
|
* Provides access to the builders for asset models.
|
||||||
);
|
*/
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private CategoryManager categoryManager;
|
private AssetModelBuilders assetModelBuilders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Category repository used to retrieve the current category.
|
||||||
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
private CategoryRepository categoryRepository;
|
private CategoryRepository categoryRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Category model used to get the curretn category.
|
||||||
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
private CategoryModel categoryModel;
|
private CategoryModel categoryModel;
|
||||||
|
|
||||||
@Inject
|
/**
|
||||||
private EntityManager entityManager;
|
* Utility for globalization stuff.
|
||||||
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
private GlobalizationHelper globalizationHelper;
|
private GlobalizationHelper globalizationHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides some utility methods.
|
||||||
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
private PagesService pagesService;
|
private PagesService pagesService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All instances of implementations of the {@link ProcessesContentItem}
|
||||||
|
* interface.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private Instance<ProcessesContentItem> contentItemProcessingModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link DateTimeFormatter} instance for converting dates and times to an
|
||||||
|
* ISO 8601 date/time string.
|
||||||
|
*/
|
||||||
private final DateTimeFormatter dateTimeFormatter
|
private final DateTimeFormatter dateTimeFormatter
|
||||||
= DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.systemDefault());
|
= DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.systemDefault());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the item to be shown.
|
||||||
|
*/
|
||||||
private String itemName;
|
private String itemName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The version of the item to be shown.
|
||||||
|
*/
|
||||||
private ContentItemVersion itemVersion;
|
private ContentItemVersion itemVersion;
|
||||||
|
|
||||||
private Optional<ContentItem> contentItem;
|
/**
|
||||||
|
* Data of the current content item, already prepared for retrieving the
|
||||||
|
* data from a MVC template. If no item with the {@link #itemName} provided
|
||||||
|
* by the {@link PagesController} is present in the category, the
|
||||||
|
* {@link Optional} will be empty.
|
||||||
|
*/
|
||||||
|
private Optional<ContentItemModelData> contentItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the item name provided by the {@link PagesController}.
|
||||||
|
*
|
||||||
|
* @return The item name provided by the {@link PagesController}.
|
||||||
|
*/
|
||||||
public String getItemName() {
|
public String getItemName() {
|
||||||
return itemName;
|
return itemName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by the {@link PagesController} to set the name of the requested
|
||||||
|
* content item. May be used by other controllers.
|
||||||
|
*
|
||||||
|
* @param itemName The name of the requested content item.
|
||||||
|
*/
|
||||||
public void setItemName(final String itemName) {
|
public void setItemName(final String itemName) {
|
||||||
this.itemName = itemName;
|
this.itemName = itemName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The requested version of the content item.
|
||||||
|
*
|
||||||
|
* @return The requested version of the content item.
|
||||||
|
*/
|
||||||
public ContentItemVersion getItemVersion() {
|
public ContentItemVersion getItemVersion() {
|
||||||
return itemVersion;
|
return itemVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by controllers, for example the {@link PagesController} to set the
|
||||||
|
* requested version of the content item.
|
||||||
|
*
|
||||||
|
* @param itemVersion The requested version of the content item.
|
||||||
|
*/
|
||||||
public void setItemVersion(final ContentItemVersion itemVersion) {
|
public void setItemVersion(final ContentItemVersion itemVersion) {
|
||||||
this.itemVersion = itemVersion;
|
this.itemVersion = itemVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the current content item. Depending if {@link #itemName} has
|
* A convient getter for checking if a content item is available from a
|
||||||
* been initalized with a value either the index item of the current
|
* template.
|
||||||
* category or the item in the category identified by {@link #itemName} will
|
|
||||||
* be retrieved. The item is only received once per request. The method will
|
|
||||||
* retrieve the item on the first call and store the result in
|
|
||||||
* {@link #contentItem}. Subsequent calls will return the value of
|
|
||||||
* {@link #contentItem}. If {@link #itemName} is not {@code null} and there
|
|
||||||
* is no content item with the requested name in the category this method
|
|
||||||
* throws a {@link NotFoundException}.
|
|
||||||
*
|
*
|
||||||
* @return The requested categorized item. If {@link #itemName} is
|
* @return {@code true} if an item is available, {@code false} if not.
|
||||||
* {@code null}, and the current category has not index item, the
|
|
||||||
* method will return {@code null}.
|
|
||||||
*
|
|
||||||
* @throws NotFoundException If there is no item identified by the name in
|
|
||||||
* {@link #itemName}.
|
|
||||||
*/
|
*/
|
||||||
public ContentItem getContentItem() {
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
return getOrRetrieveContentItem().orElse(null);
|
public boolean isItemAvailable() {
|
||||||
|
init();
|
||||||
|
return contentItem.isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@code objectId)} (see {@link CcmObject#objectId} of the current
|
||||||
|
* item.
|
||||||
|
*
|
||||||
|
* @return The {@code objectId} of the current item if there is an item or
|
||||||
|
* {@code -1L} if there is no item.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public long getObjectId() {
|
public long getObjectId() {
|
||||||
return getOrRetrieveContentItem()
|
init();
|
||||||
.map(ContentItem::getObjectId)
|
return contentItem
|
||||||
.orElse(0L);
|
.map(ContentItemModelData::getObjectId)
|
||||||
|
.orElse(-1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the UUID of the current item (see {@link CcmObject#uuid}.
|
||||||
|
*
|
||||||
|
* @return The UUID of the current item if there is an item, an empty string
|
||||||
|
* if there is not item.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getUuid() {
|
public String getUuid() {
|
||||||
return getOrRetrieveContentItem()
|
init();
|
||||||
.map(ContentItem::getUuid)
|
return contentItem
|
||||||
|
.map(ContentItemModelData::getUuid)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the display name of the current item (see
|
||||||
|
* {@link CcmObject#displayName}.
|
||||||
|
*
|
||||||
|
* @return The display name of the current item, or an empty string if there
|
||||||
|
* is not current item.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
return getOrRetrieveContentItem()
|
init();
|
||||||
.map(ContentItem::getDisplayName)
|
return contentItem
|
||||||
|
.map(ContentItemModelData::getDisplayName)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the item UUID of the current item (see {@link ContentItem#itemUuid}.
|
||||||
|
*
|
||||||
|
* @return The item UUID of the current item, or an empty string if the is
|
||||||
|
* no current item.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getItemUuid() {
|
public String getItemUuid() {
|
||||||
return getOrRetrieveContentItem()
|
init();
|
||||||
.map(ContentItem::getItemUuid)
|
return contentItem
|
||||||
|
.map(ContentItemModelData::getItemUuid)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the current item {@link ContentItem#name}) for the
|
||||||
|
* current language (see {@link GlobalizationHelper#getNegotiatedLocale()}).
|
||||||
|
*
|
||||||
|
* @return The name of the the current item for the current language, or an
|
||||||
|
* empty string if there is no item.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return getOrRetrieveContentItem()
|
init();
|
||||||
.map(ContentItem::getName)
|
return contentItem
|
||||||
.map(globalizationHelper::getValueFromLocalizedString)
|
.map(ContentItemModelData::getName)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the title of the current item (see {@link ContentItem#title} for the
|
||||||
|
* current language (see {@link GlobalizationHelper#getNegotiatedLocale()}).
|
||||||
|
*
|
||||||
|
* @return The title of the current item for the current language, or an
|
||||||
|
* empty string if there is no item.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return getOrRetrieveContentItem()
|
init();
|
||||||
.map(ContentItem::getTitle)
|
return contentItem
|
||||||
.map(globalizationHelper::getValueFromLocalizedString)
|
.map(ContentItemModelData::getTitle)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description of the current item (see
|
||||||
|
* {@link ContentItem#description} for the current language (see
|
||||||
|
* {@link GlobalizationHelper#getNegotiatedLocale()}).
|
||||||
|
*
|
||||||
|
* @return The description of the current item for the current language, or
|
||||||
|
* an empty string if there is no item.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return getOrRetrieveContentItem()
|
init();
|
||||||
.map(ContentItem::getDescription)
|
return contentItem
|
||||||
.map(globalizationHelper::getValueFromLocalizedString)
|
.map(ContentItemModelData::getDescription)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public List<AttachmentListModel> getAttachmentLists() {
|
||||||
|
init();
|
||||||
|
return contentItem
|
||||||
|
.map(ContentItemModelData::getAttachmentLists)
|
||||||
|
.orElse(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public List<AttachmentListModel> getMediaLists() {
|
||||||
|
init();
|
||||||
|
return contentItem
|
||||||
|
.map(ContentItemModelData::getMediaLists)
|
||||||
|
.orElse(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the version of the current item (see {@link ContentItem#version}.
|
||||||
|
*
|
||||||
|
* @return The version of the current version as a string, or an empty
|
||||||
|
* string if there is not current item.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getVersion() {
|
public String getVersion() {
|
||||||
return getOrRetrieveContentItem()
|
init();
|
||||||
.map(ContentItem::getVersion)
|
return contentItem
|
||||||
.map(ContentItemVersion::toString)
|
.map(ContentItemModelData::getVersion)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the creation date/time of the current item (see
|
||||||
|
* {@link ContentItem#creationDate}.
|
||||||
|
*
|
||||||
|
* @return The creation date/time of the current item as ISO 8601 date/time
|
||||||
|
* string, or an empty string if there is no item.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getCreationDate() {
|
public String getCreationDate() {
|
||||||
return getOrRetrieveContentItem()
|
init();
|
||||||
.map(ContentItem::getCreationDate)
|
return contentItem
|
||||||
.map(Date::toInstant)
|
.map(ContentItemModelData::getCreationDate)
|
||||||
.map(instant -> instant.atZone(ZoneId.systemDefault()))
|
|
||||||
.map(ZonedDateTime::toLocalDateTime)
|
|
||||||
.map(dateTimeFormatter::format)
|
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the date/time of the last modification of the current item (see
|
||||||
|
* {@link ContentItem#lastModified}.
|
||||||
|
*
|
||||||
|
* @return The date/time of the modification of the current item as ISO 8601
|
||||||
|
* date/time string, or an empty string of there is not current
|
||||||
|
* item.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getLastModified() {
|
public String getLastModified() {
|
||||||
return getOrRetrieveContentItem()
|
init();
|
||||||
.map(ContentItem::getLastModified)
|
return contentItem
|
||||||
.map(Date::toInstant)
|
.map(ContentItemModelData::getLastModified)
|
||||||
.map(instant -> instant.atZone(ZoneId.systemDefault()))
|
|
||||||
.map(ZonedDateTime::toLocalDateTime)
|
|
||||||
.map(dateTimeFormatter::format)
|
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the user name of the user that created the item.
|
||||||
|
*
|
||||||
|
* @return The user name of the user that created the item.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getCreationUser() {
|
public String getCreationUser() {
|
||||||
return getOrRetrieveContentItem()
|
init();
|
||||||
.map(ContentItem::getCreationUserName)
|
return contentItem
|
||||||
|
.map(ContentItemModelData::getCreationUser)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the user name of the user that did the last modifications on the
|
||||||
|
* item.
|
||||||
|
*
|
||||||
|
* @return The user name of the user that did the last modifications on the
|
||||||
|
* item.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getLastModifyingUserName() {
|
public String getLastModifyingUserName() {
|
||||||
return getOrRetrieveContentItem()
|
init();
|
||||||
.map(ContentItem::getLastModifyingUserName)
|
return contentItem
|
||||||
|
.map(ContentItemModelData::getLastModifyingUserName)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AttachmentList> getAttachments() {
|
/**
|
||||||
return getContentItem().getAttachments();
|
* Initialize the this model and all models implementing
|
||||||
|
* {@link ProcessesContentItem#}.
|
||||||
|
*
|
||||||
|
* If this model has not been initalizied already this method retrieves the
|
||||||
|
* current content item using {@link #retrieveContentItem()}, and
|
||||||
|
* initializes {@link #contentItem} with an instance of
|
||||||
|
* {@link ContentItemModelData} build from the item using
|
||||||
|
* {@link #buildModelData(org.librecms.contentsection.ContentItem)}.
|
||||||
|
*
|
||||||
|
* After that, the method will invoke the implementation of
|
||||||
|
* {@link ProcessesContentItem#init(org.librecms.contentsection.ContentItem)}
|
||||||
|
* for all available implemetentations of {@link ProcessesContentItem} (see
|
||||||
|
* {@link #contentItemProcessingModels}).
|
||||||
|
*
|
||||||
|
* Models implementing SHOULD call this method in their getters before
|
||||||
|
* returning a value. There is not need to wrap the invocation of this
|
||||||
|
* method in an {@code if} statement, the method will only run its logic if
|
||||||
|
* the item has not been initialized.
|
||||||
|
*
|
||||||
|
* If there is no current item, the method will do nothing.
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public void init() {
|
||||||
|
if (contentItem != null) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<ContentItem> getOrRetrieveContentItem() {
|
final Optional<ContentItem> item = retrieveContentItem();
|
||||||
if (contentItem == null) {
|
contentItem = item.map(this::buildModelData);
|
||||||
retrieveContentItem();
|
|
||||||
|
final Iterator<ProcessesContentItem> iterator
|
||||||
|
= contentItemProcessingModels.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
final ProcessesContentItem model = iterator.next();
|
||||||
|
model.init(item.orElse(null));
|
||||||
}
|
}
|
||||||
return contentItem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void retrieveContentItem() {
|
/**
|
||||||
if (itemName == null) {
|
* Helper method for retrieving the current content item. If
|
||||||
contentItem = pagesService.findIndexItem(
|
* {@link #itemName} is {@code null} or {@code index} the method will return
|
||||||
|
* if the index item of the current category. If the category has not index
|
||||||
|
* item, an empty {@link Optional} is returned.
|
||||||
|
*
|
||||||
|
* If {@link #itemName} is <b>not</b> {@code null} or {@code index}, the
|
||||||
|
* method will try to find a content item associated to the category where
|
||||||
|
* {@link ContentItem#name} matches {@link #itemName}.
|
||||||
|
*
|
||||||
|
* @return The current content item if any, or an empyty {@link Optional}.
|
||||||
|
*
|
||||||
|
* @see PagesService#findIndexItem(org.libreccm.categorization.Category,
|
||||||
|
* org.librecms.contentsection.ContentItemVersion)
|
||||||
|
* @see
|
||||||
|
* PagesService#findCategorizedItem(org.libreccm.categorization.Category,
|
||||||
|
* java.lang.String, org.librecms.contentsection.ContentItemVersion)
|
||||||
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
private Optional<ContentItem> retrieveContentItem() {
|
||||||
|
final Optional<ContentItem> item;
|
||||||
|
if (itemName == null || "index".equals(itemName)) {
|
||||||
|
item = pagesService.findIndexItem(
|
||||||
categoryRepository
|
categoryRepository
|
||||||
.findById(categoryModel.getCategory().getCategoryId())
|
.findById(categoryModel.getCategory().getCategoryId())
|
||||||
.orElseThrow(
|
.orElseThrow(
|
||||||
|
|
@ -235,7 +442,7 @@ public class ContentItemModel {
|
||||||
itemVersion
|
itemVersion
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
contentItem = pagesService.findCategorizedItem(
|
item = pagesService.findCategorizedItem(
|
||||||
categoryRepository
|
categoryRepository
|
||||||
.findById(categoryModel.getCategory().getCategoryId())
|
.findById(categoryModel.getCategory().getCategoryId())
|
||||||
.orElseThrow(
|
.orElseThrow(
|
||||||
|
|
@ -252,5 +459,305 @@ public class ContentItemModel {
|
||||||
itemVersion
|
itemVersion
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for building an instance {@link ContentItemModelData} for a
|
||||||
|
* {@link ContentItem}.
|
||||||
|
*
|
||||||
|
* @param item The source content item.
|
||||||
|
*
|
||||||
|
* @return An instance of {@link ContentItemModelData} for the provided
|
||||||
|
* content item.
|
||||||
|
*/
|
||||||
|
private ContentItemModelData buildModelData(final ContentItem item) {
|
||||||
|
final ContentItemModelData data = new ContentItemModelData();
|
||||||
|
data.setObjectId(item.getObjectId());
|
||||||
|
data.setUuid(item.getUuid());
|
||||||
|
data.setDisplayName(item.getDisplayName());
|
||||||
|
data.setItemUuid(item.getItemUuid());
|
||||||
|
data.setName(
|
||||||
|
globalizationHelper.getValueFromLocalizedString(
|
||||||
|
item.getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
data.setTitle(
|
||||||
|
globalizationHelper.getValueFromLocalizedString(
|
||||||
|
item.getTitle()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
data.setDescription(
|
||||||
|
globalizationHelper.getValueFromLocalizedString(
|
||||||
|
item.getDescription()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
data.setVersion(item.getVersion().toString());
|
||||||
|
data.setCreationDate(
|
||||||
|
dateTimeFormatter.format(
|
||||||
|
item
|
||||||
|
.getCreationDate()
|
||||||
|
.toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDateTime()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
data.setLastModified(
|
||||||
|
dateTimeFormatter.format(
|
||||||
|
item
|
||||||
|
.getLastModified()
|
||||||
|
.toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDateTime()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
data.setCreationUser(item.getCreationUserName());
|
||||||
|
data.setLastModifyingUserName(item.getLastModifyingUserName());
|
||||||
|
|
||||||
|
data.setAttachmentLists(
|
||||||
|
item
|
||||||
|
.getAttachments()
|
||||||
|
.stream()
|
||||||
|
.filter(
|
||||||
|
list -> !list.getName().startsWith(
|
||||||
|
CmsConstants.MEDIA_LIST_PREFIX
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map(this::buildAttachmentListModel)
|
||||||
|
.sorted()
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
);
|
||||||
|
data.setMediaLists(
|
||||||
|
item
|
||||||
|
.getAttachments()
|
||||||
|
.stream()
|
||||||
|
.filter(
|
||||||
|
list -> list.getName().startsWith(
|
||||||
|
CmsConstants.MEDIA_LIST_PREFIX
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map(this::buildAttachmentListModel)
|
||||||
|
.sorted()
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AttachmentListModel buildAttachmentListModel(
|
||||||
|
final AttachmentList attachmentList
|
||||||
|
) {
|
||||||
|
final AttachmentListModel model = new AttachmentListModel();
|
||||||
|
model.setAttachments(
|
||||||
|
attachmentList
|
||||||
|
.getAttachments()
|
||||||
|
.stream()
|
||||||
|
.map(this::buildAttachmentModel)
|
||||||
|
.sorted()
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
);
|
||||||
|
model.setDescription(
|
||||||
|
globalizationHelper.getValueFromLocalizedString(
|
||||||
|
attachmentList.getDescription()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
model.setListId(attachmentList.getListId());
|
||||||
|
model.setListOrder(attachmentList.getListOrder());
|
||||||
|
model.setName(attachmentList.getName());
|
||||||
|
model.setTitle(
|
||||||
|
globalizationHelper.getValueFromLocalizedString(
|
||||||
|
attachmentList.getTitle()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
model.setUuid(attachmentList.getUuid());
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AttachmentModel buildAttachmentModel(
|
||||||
|
final ItemAttachment<?> attachment
|
||||||
|
) {
|
||||||
|
final AttachmentModel model = new AttachmentModel();
|
||||||
|
final Asset asset = attachment.getAsset();
|
||||||
|
final AssetModelBuilder<?, ?> assetModelBuilder
|
||||||
|
= assetModelBuilders
|
||||||
|
.getModelBuilderFor(asset.getClass())
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new WebApplicationException(
|
||||||
|
Response
|
||||||
|
.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||||
|
.entity(
|
||||||
|
String.format(
|
||||||
|
"Unknown asset type %s.",
|
||||||
|
asset.getClass().getName()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
model.setAsset(
|
||||||
|
assetModelBuilder.buildAssetModel(attachment.getAsset())
|
||||||
|
);
|
||||||
|
model.setAttachmentId(attachment.getAttachmentId());
|
||||||
|
model.setSortKey(attachment.getSortKey());
|
||||||
|
model.setUuid(attachment.getUuid());
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates the data of content item provided by this model. To avoid to
|
||||||
|
* have to many fields in this model class we use an internal class to
|
||||||
|
* encapsulate the data. The getters of the model class return the values
|
||||||
|
* from an instance of this class.
|
||||||
|
*/
|
||||||
|
private class ContentItemModelData {
|
||||||
|
|
||||||
|
private long objectId;
|
||||||
|
|
||||||
|
private String uuid;
|
||||||
|
|
||||||
|
private String displayName;
|
||||||
|
|
||||||
|
private String itemUuid;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
private String creationDate;
|
||||||
|
|
||||||
|
private String lastModified;
|
||||||
|
|
||||||
|
private String creationUser;
|
||||||
|
|
||||||
|
private String lastModifyingUserName;
|
||||||
|
|
||||||
|
private List<AttachmentListModel> attachmentLists;
|
||||||
|
|
||||||
|
private List<AttachmentListModel> mediaLists;
|
||||||
|
|
||||||
|
public long getObjectId() {
|
||||||
|
return objectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setObjectId(final long objectId) {
|
||||||
|
this.objectId = objectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuid(final String uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisplayName(final String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getItemUuid() {
|
||||||
|
return itemUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItemUuid(final String itemUuid) {
|
||||||
|
this.itemUuid = itemUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(final String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(final String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersion(final String version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreationDate() {
|
||||||
|
return creationDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreationDate(final String creationDate) {
|
||||||
|
this.creationDate = creationDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastModified() {
|
||||||
|
return lastModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastModified(final String lastModified) {
|
||||||
|
this.lastModified = lastModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreationUser() {
|
||||||
|
return creationUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreationUser(final String creationUser) {
|
||||||
|
this.creationUser = creationUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastModifyingUserName() {
|
||||||
|
return lastModifyingUserName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastModifyingUserName(
|
||||||
|
final String lastModifyingUserName
|
||||||
|
) {
|
||||||
|
this.lastModifyingUserName = lastModifyingUserName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AttachmentListModel> getAttachmentLists() {
|
||||||
|
return Collections.unmodifiableList(attachmentLists);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttachmentLists(
|
||||||
|
final List<AttachmentListModel> attachmentLists
|
||||||
|
) {
|
||||||
|
this.attachmentLists = new ArrayList<>(attachmentLists);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AttachmentListModel> getMediaLists() {
|
||||||
|
return Collections.unmodifiableList(mediaLists);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMediaLists(final List<AttachmentListModel> mediaLists) {
|
||||||
|
this.mediaLists = new ArrayList<>(mediaLists);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,16 +18,16 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.pages.models;
|
package org.librecms.pages.models;
|
||||||
|
|
||||||
import org.libreccm.l10n.GlobalizationHelper;
|
|
||||||
import org.librecms.contentsection.ContentItem;
|
|
||||||
import org.librecms.contentsection.ContentType;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.swing.text.AbstractDocument.Content;
|
import javax.transaction.Transactional;
|
||||||
|
|
||||||
|
import org.libreccm.l10n.GlobalizationHelper;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
import org.librecms.contentsection.ContentType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MVC model for retrieving information about the content type of the current
|
* MVC model for retrieving information about the content type of the current
|
||||||
|
|
@ -43,7 +43,7 @@ import javax.swing.text.AbstractDocument.Content;
|
||||||
*/
|
*/
|
||||||
@RequestScoped
|
@RequestScoped
|
||||||
@Named("CmsPagesContentItemTypeModel")
|
@Named("CmsPagesContentItemTypeModel")
|
||||||
public class ContentItemTypeModel {
|
public class ContentItemTypeModel implements ProcessesContentItem {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ContentItemModel contentItemModel;
|
private ContentItemModel contentItemModel;
|
||||||
|
|
@ -51,55 +51,150 @@ public class ContentItemTypeModel {
|
||||||
@Inject
|
@Inject
|
||||||
private GlobalizationHelper globalizationHelper;
|
private GlobalizationHelper globalizationHelper;
|
||||||
|
|
||||||
private Optional<ContentType> contentType;
|
private Optional<ContentItemTypeModelData> contentType;
|
||||||
|
|
||||||
public ContentType getContentType() {
|
|
||||||
return getOrRetrieveContentType().orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getContentTypeId() {
|
public long getContentTypeId() {
|
||||||
return getOrRetrieveContentType()
|
contentItemModel.init();
|
||||||
.map(ContentType::getObjectId)
|
|
||||||
|
return contentType
|
||||||
|
.map(ContentItemTypeModelData::getTypeId)
|
||||||
.orElse(0L);
|
.orElse(0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUuid() {
|
public String getUuid() {
|
||||||
return getOrRetrieveContentType()
|
contentItemModel.init();
|
||||||
.map(ContentType::getUuid)
|
|
||||||
|
return contentType
|
||||||
|
.map(ContentItemTypeModelData::getUuid)
|
||||||
|
.orElse("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getItemClass() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return contentType
|
||||||
|
.map(ContentItemTypeModelData::getItemClass)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
return getOrRetrieveContentType()
|
contentItemModel.init();
|
||||||
.map(ContentType::getDisplayName)
|
|
||||||
|
return contentType
|
||||||
|
.map(ContentItemTypeModelData::getDisplayName)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return getOrRetrieveContentType()
|
contentItemModel.init();
|
||||||
.map(ContentType::getLabel)
|
|
||||||
.map(globalizationHelper::getValueFromLocalizedString)
|
return contentType
|
||||||
|
.map(ContentItemTypeModelData::getLabel)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return getOrRetrieveContentType()
|
contentItemModel.init();
|
||||||
.map(ContentType::getDescription)
|
|
||||||
.map(globalizationHelper::getValueFromLocalizedString)
|
return contentType
|
||||||
|
.map(ContentItemTypeModelData::getDescription)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<ContentType> getOrRetrieveContentType() {
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
if (contentType == null) {
|
public void init(final ContentItem contentItem) {
|
||||||
retrieveContentType();
|
if (contentType != null) {
|
||||||
}
|
return;
|
||||||
return contentType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void retrieveContentType() {
|
|
||||||
contentType = Optional
|
contentType = Optional
|
||||||
.ofNullable(contentItemModel.getContentItem())
|
.ofNullable(contentItem)
|
||||||
.map(ContentItem::getContentType);
|
.map(ContentItem::getContentType)
|
||||||
|
.map(this::buildModelData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
private ContentItemTypeModelData buildModelData(final ContentType type) {
|
||||||
|
final ContentItemTypeModelData data = new ContentItemTypeModelData();
|
||||||
|
data.setDescription(
|
||||||
|
globalizationHelper.getValueFromLocalizedString(
|
||||||
|
type.getDescription()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
data.setDisplayName(type.getDisplayName());
|
||||||
|
data.setItemClass(type.getContentItemClass());
|
||||||
|
data.setLabel(
|
||||||
|
globalizationHelper.getValueFromLocalizedString(
|
||||||
|
type.getLabel()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
data.setTypeId(type.getObjectId());
|
||||||
|
data.setUuid(type.getUuid());
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ContentItemTypeModelData {
|
||||||
|
|
||||||
|
private long typeId;
|
||||||
|
|
||||||
|
private String uuid;
|
||||||
|
|
||||||
|
private String itemClass;
|
||||||
|
|
||||||
|
private String displayName;
|
||||||
|
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
public long getTypeId() {
|
||||||
|
return typeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeId(final long typeId) {
|
||||||
|
this.typeId = typeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuid(final String uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getItemClass() {
|
||||||
|
return itemClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItemClass(final String itemClass) {
|
||||||
|
this.itemClass = itemClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisplayName(final String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(final String label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(final String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ package org.librecms.pages.models;
|
||||||
import org.librecms.contenttypes.Event;
|
import org.librecms.contenttypes.Event;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
@ -43,6 +45,13 @@ public class EventListItemModel extends AbstractContentItemListItemModel {
|
||||||
return startDate;
|
return startDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getStartDate(final String pattern) {
|
||||||
|
return DateTimeFormatter
|
||||||
|
.ofPattern(pattern)
|
||||||
|
.withZone(ZoneId.systemDefault())
|
||||||
|
.format(startDate);
|
||||||
|
}
|
||||||
|
|
||||||
public void setStartDate(final LocalDateTime startDate) {
|
public void setStartDate(final LocalDateTime startDate) {
|
||||||
this.startDate = startDate;
|
this.startDate = startDate;
|
||||||
}
|
}
|
||||||
|
|
@ -51,6 +60,13 @@ public class EventListItemModel extends AbstractContentItemListItemModel {
|
||||||
return endDate;
|
return endDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getEndDate(final String pattern) {
|
||||||
|
return DateTimeFormatter
|
||||||
|
.ofPattern(pattern)
|
||||||
|
.withZone(ZoneId.systemDefault())
|
||||||
|
.format(endDate);
|
||||||
|
}
|
||||||
|
|
||||||
public void setEndDate(final LocalDateTime endDate) {
|
public void setEndDate(final LocalDateTime endDate) {
|
||||||
this.endDate = endDate;
|
this.endDate = endDate;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import org.libreccm.l10n.GlobalizationHelper;
|
||||||
import org.librecms.contenttypes.Event;
|
import org.librecms.contenttypes.Event;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
|
@ -50,13 +51,21 @@ public class EventListItemModelBuilder
|
||||||
final Event event, final EventListItemModel model
|
final Event event, final EventListItemModel model
|
||||||
) {
|
) {
|
||||||
super.addProperties(event, model);
|
super.addProperties(event, model);
|
||||||
model.setEndDate(LocalDateTime.from(event.getEndDate().toInstant()));
|
model.setEndDate(
|
||||||
|
LocalDateTime.from(
|
||||||
|
event.getEndDate().toInstant().atZone(ZoneId.systemDefault())
|
||||||
|
)
|
||||||
|
);
|
||||||
model.setLocation(
|
model.setLocation(
|
||||||
globalizationHelper.getValueFromLocalizedString(
|
globalizationHelper.getValueFromLocalizedString(
|
||||||
event.getLocation()
|
event.getLocation()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
model.setStartDate(LocalDateTime.from(event.getStartDate().toInstant()));
|
model.setStartDate(
|
||||||
|
LocalDateTime.from(
|
||||||
|
event.getStartDate().toInstant().atZone(ZoneId.systemDefault())
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,18 +18,19 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.pages.models;
|
package org.librecms.pages.models;
|
||||||
|
|
||||||
import org.libreccm.l10n.GlobalizationHelper;
|
import java.time.LocalDateTime;
|
||||||
import org.librecms.contentsection.ContentItem;
|
|
||||||
import org.librecms.contenttypes.Event;
|
|
||||||
|
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.transaction.Transactional;
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
|
import org.libreccm.l10n.GlobalizationHelper;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
import org.librecms.contenttypes.Event;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
@ -37,7 +38,7 @@ import javax.ws.rs.core.Response;
|
||||||
*/
|
*/
|
||||||
@RequestScoped
|
@RequestScoped
|
||||||
@Named("CmsPagesEventModel")
|
@Named("CmsPagesEventModel")
|
||||||
public class EventModel {
|
public class EventModel implements ProcessesContentItem {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ContentItemModel contentItemModel;
|
private ContentItemModel contentItemModel;
|
||||||
|
|
@ -45,55 +46,202 @@ public class EventModel {
|
||||||
@Inject
|
@Inject
|
||||||
private GlobalizationHelper globalizationHelper;
|
private GlobalizationHelper globalizationHelper;
|
||||||
|
|
||||||
|
private boolean initialized;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
private LocalDateTime startDateTime;
|
||||||
|
|
||||||
|
private LocalDateTime endDateTime;
|
||||||
|
|
||||||
|
private String eventDate;
|
||||||
|
|
||||||
|
private String location;
|
||||||
|
|
||||||
|
private String eventType;
|
||||||
|
|
||||||
|
public EventModel() {
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return globalizationHelper.getValueFromLocalizedString(
|
contentItemModel.init();
|
||||||
getEvent().getTitle()
|
|
||||||
);
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return globalizationHelper.getValueFromLocalizedString(
|
contentItemModel.init();
|
||||||
getEvent().getText()
|
|
||||||
);
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStartDateTime() {
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
return DateTimeFormatter.ISO_DATE_TIME
|
public LocalDateTime getStartDateTime() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return startDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the start date of the event represented by this model formatted
|
||||||
|
* using the provided pattern. The pattern MUST be a valid pattern for
|
||||||
|
* {@link DateTimeFormatter#ofPattern(java.lang.String) }.
|
||||||
|
*
|
||||||
|
* @param pattern The pattern to use for formatting the release date.
|
||||||
|
*
|
||||||
|
* @return The formatted release date.
|
||||||
|
*/
|
||||||
|
public String getStartDateTime(final String pattern) {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return Optional
|
||||||
|
.ofNullable(startDateTime)
|
||||||
|
.map(
|
||||||
|
dateTime -> DateTimeFormatter
|
||||||
|
.ofPattern(
|
||||||
|
pattern,
|
||||||
|
globalizationHelper.getNegotiatedLocale()
|
||||||
|
)
|
||||||
.withZone(ZoneId.systemDefault())
|
.withZone(ZoneId.systemDefault())
|
||||||
.format(getEvent().getStartDate().toInstant());
|
.format(dateTime)
|
||||||
|
)
|
||||||
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEndDateTime() {
|
public String getStartDateTimeAsString() {
|
||||||
return DateTimeFormatter.ISO_DATE_TIME
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return Optional
|
||||||
|
.ofNullable(endDateTime)
|
||||||
|
.map(
|
||||||
|
dateTime -> DateTimeFormatter.ISO_DATE_TIME
|
||||||
.withZone(ZoneId.systemDefault())
|
.withZone(ZoneId.systemDefault())
|
||||||
.format(getEvent().getEndDate().toInstant());
|
.format(dateTime)
|
||||||
|
)
|
||||||
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public LocalDateTime getEndDateTime() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return endDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the end date of the event represented by this model formatted
|
||||||
|
* using the provided pattern. The pattern MUST be a valid pattern for
|
||||||
|
* {@link DateTimeFormatter#ofPattern(java.lang.String) }.
|
||||||
|
*
|
||||||
|
* @param pattern The pattern to use for formatting the release date.
|
||||||
|
*
|
||||||
|
* @return The formatted release date.
|
||||||
|
*/
|
||||||
|
public String getEndDateTime(final String pattern) {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return Optional
|
||||||
|
.ofNullable(endDateTime)
|
||||||
|
.map(
|
||||||
|
dateTime -> DateTimeFormatter
|
||||||
|
.ofPattern(
|
||||||
|
pattern,
|
||||||
|
globalizationHelper.getNegotiatedLocale()
|
||||||
|
)
|
||||||
|
.withZone(ZoneId.systemDefault())
|
||||||
|
.format(dateTime)
|
||||||
|
)
|
||||||
|
.orElse("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEndDateTimeAsString() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return Optional
|
||||||
|
.ofNullable(endDateTime)
|
||||||
|
.map(
|
||||||
|
dateTime -> DateTimeFormatter.ISO_DATE_TIME
|
||||||
|
.withZone(ZoneId.systemDefault())
|
||||||
|
.format(dateTime)
|
||||||
|
)
|
||||||
|
.orElse("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getEventDate() {
|
public String getEventDate() {
|
||||||
return globalizationHelper.getValueFromLocalizedString(
|
contentItemModel.init();
|
||||||
getEvent().getEventDate()
|
|
||||||
);
|
return eventDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getLocation() {
|
public String getLocation() {
|
||||||
return globalizationHelper.getValueFromLocalizedString(
|
contentItemModel.init();
|
||||||
getEvent().getLocation()
|
|
||||||
);
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public String getEventType() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return eventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public void init(final ContentItem contentItem) {
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Event getEvent() {
|
|
||||||
final ContentItem contentItem = contentItemModel.getContentItem();
|
|
||||||
if (contentItem instanceof Event) {
|
if (contentItem instanceof Event) {
|
||||||
return (Event) contentItem;
|
final Event event = (Event) contentItem;
|
||||||
} else {
|
|
||||||
throw new WebApplicationException(
|
title = Optional
|
||||||
"Current content item is not an event",
|
.ofNullable(event.getTitle())
|
||||||
Response
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
.status(Response.Status.INTERNAL_SERVER_ERROR)
|
.orElse("");
|
||||||
.entity("Current content item is not an event.")
|
text = Optional
|
||||||
.build()
|
.ofNullable(event.getText())
|
||||||
);
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
|
.orElse("");
|
||||||
|
startDateTime = Optional
|
||||||
|
.ofNullable(event.getStartDate())
|
||||||
|
.map(
|
||||||
|
startDate -> LocalDateTime.from(
|
||||||
|
startDate.toInstant().atZone(ZoneId.systemDefault())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.orElse(null);
|
||||||
|
endDateTime = Optional
|
||||||
|
.ofNullable(event.getEndDate())
|
||||||
|
.map(
|
||||||
|
endDate -> LocalDateTime.from(
|
||||||
|
endDate.toInstant().atZone(ZoneId.systemDefault())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.orElse(null);
|
||||||
|
eventDate = Optional
|
||||||
|
.ofNullable(event.getEventDate())
|
||||||
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
|
.orElse("");
|
||||||
|
location = Optional
|
||||||
|
.ofNullable(event.getLocation())
|
||||||
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
|
.orElse("");
|
||||||
|
eventType = Optional
|
||||||
|
.ofNullable(event.getEventType())
|
||||||
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,12 @@ public class ImageModelBuilder
|
||||||
protected void addProperties(final Image image, final ImageModel model) {
|
protected void addProperties(final Image image, final ImageModel model) {
|
||||||
super.addProperties(image, model);
|
super.addProperties(image, model);
|
||||||
model.setHeight(image.getHeight());
|
model.setHeight(image.getHeight());
|
||||||
|
if (image.getLegalMetadata() != null) {
|
||||||
model.setLegalMetadata(
|
model.setLegalMetadata(
|
||||||
legalMetadataModelBuilder.buildAssetModel(image.getLegalMetadata())
|
legalMetadataModelBuilder.buildAssetModel(
|
||||||
|
image.getLegalMetadata())
|
||||||
);
|
);
|
||||||
|
}
|
||||||
model.setWidth(image.getWidth());
|
model.setWidth(image.getWidth());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,26 +18,6 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.pages.models;
|
package org.librecms.pages.models;
|
||||||
|
|
||||||
import com.arsdigita.kernel.KernelConfig;
|
|
||||||
|
|
||||||
import org.libreccm.categorization.Categorization;
|
|
||||||
import org.libreccm.categorization.Category;
|
|
||||||
import org.libreccm.categorization.CategoryRepository;
|
|
||||||
import org.libreccm.configuration.ConfigurationManager;
|
|
||||||
import org.libreccm.core.UnexpectedErrorException;
|
|
||||||
import org.libreccm.l10n.GlobalizationHelper;
|
|
||||||
import org.libreccm.security.Permission;
|
|
||||||
import org.libreccm.security.PermissionChecker;
|
|
||||||
import org.libreccm.security.Role;
|
|
||||||
import org.libreccm.security.RoleManager;
|
|
||||||
import org.libreccm.security.Shiro;
|
|
||||||
import org.libreccm.security.User;
|
|
||||||
import org.libreccm.security.UserRepository;
|
|
||||||
import org.librecms.contentsection.ContentItem;
|
|
||||||
import org.librecms.contentsection.ContentItemL10NManager;
|
|
||||||
import org.librecms.contentsection.ContentItemVersion;
|
|
||||||
import org.librecms.contentsection.privileges.ItemPrivileges;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -59,6 +39,29 @@ import javax.transaction.Transactional;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.libreccm.categorization.Categorization;
|
||||||
|
import org.libreccm.categorization.Category;
|
||||||
|
import org.libreccm.categorization.CategoryRepository;
|
||||||
|
import org.libreccm.configuration.ConfigurationManager;
|
||||||
|
import org.libreccm.core.UnexpectedErrorException;
|
||||||
|
import org.libreccm.l10n.GlobalizationHelper;
|
||||||
|
import org.libreccm.security.Permission;
|
||||||
|
import org.libreccm.security.PermissionChecker;
|
||||||
|
import org.libreccm.security.Role;
|
||||||
|
import org.libreccm.security.RoleManager;
|
||||||
|
import org.libreccm.security.Shiro;
|
||||||
|
import org.libreccm.security.User;
|
||||||
|
import org.libreccm.security.UserRepository;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
import org.librecms.contentsection.ContentItemL10NManager;
|
||||||
|
import org.librecms.contentsection.ContentItemVersion;
|
||||||
|
import org.librecms.contentsection.privileges.ItemPrivileges;
|
||||||
|
|
||||||
|
import com.arsdigita.kernel.KernelConfig;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
|
@ -67,6 +70,26 @@ import javax.ws.rs.core.Response;
|
||||||
@Named("CmsPagesItemListModel")
|
@Named("CmsPagesItemListModel")
|
||||||
public class ItemListModel {
|
public class ItemListModel {
|
||||||
|
|
||||||
|
private static final String ITEM_LIST_SETTINGS_PREFIX = "itemlist";
|
||||||
|
|
||||||
|
private static final String LIMIT_TO_TYPE_SETTING = "limitToType";
|
||||||
|
|
||||||
|
private static final String LIST_ORDER_SETTING = "listOrder";
|
||||||
|
|
||||||
|
private static final String PAGE_SIZE_SETTING = "pageSize";
|
||||||
|
|
||||||
|
private static final boolean DESCENDING_DEFAULT = false;
|
||||||
|
|
||||||
|
private static final String LIMIT_TO_TYPE_DEFAULT = ContentItem.class
|
||||||
|
.getName();
|
||||||
|
|
||||||
|
private static final List<String> LIST_ORDER_DEFAULT = List
|
||||||
|
.of("displayName");
|
||||||
|
|
||||||
|
private static final int PAGE_SIZE_DEFAULT = 20;
|
||||||
|
|
||||||
|
private static final String PAGE_PARAM_NAME = "page";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private CategoryModel categoryModel;
|
private CategoryModel categoryModel;
|
||||||
|
|
||||||
|
|
@ -100,71 +123,73 @@ public class ItemListModel {
|
||||||
@Inject
|
@Inject
|
||||||
private Shiro shiro;
|
private Shiro shiro;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PagePropertiesModel pagePropertiesModel;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PageUrlModel pageUrlModel;
|
private PageUrlModel pageUrlModel;
|
||||||
|
|
||||||
private boolean descending;
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public int getListSize() {
|
||||||
private String limitToType;
|
return getListSize("");
|
||||||
|
|
||||||
private List<String> listOrder;
|
|
||||||
|
|
||||||
private int pageSize;
|
|
||||||
|
|
||||||
private List<? extends AbstractContentItemListItemModel> itemList;
|
|
||||||
|
|
||||||
public ItemListModel() {
|
|
||||||
descending = false;
|
|
||||||
limitToType = ContentItem.class.getName();
|
|
||||||
listOrder = List.of("displayName");
|
|
||||||
pageSize = 20;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDescending() {
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
return descending;
|
public int getListSize(final String listName) {
|
||||||
}
|
return getItems(listName).size();
|
||||||
|
|
||||||
public void setDescending(final boolean descending) {
|
|
||||||
this.descending = descending;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLimitToType() {
|
|
||||||
return limitToType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLimitToType(final String limitToType) {
|
|
||||||
this.limitToType = limitToType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getListOrder() {
|
|
||||||
return Collections.unmodifiableList(listOrder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setListOrder(final List<String> listOrder) {
|
|
||||||
this.listOrder = new ArrayList<>(listOrder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPageSize() {
|
public int getPageSize() {
|
||||||
return pageSize;
|
return getPageSize("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPageSize(final int pageSize) {
|
public int getPageSize(final String listName) {
|
||||||
this.pageSize = pageSize;
|
return getPageSizeSetting(listName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFirstItem() {
|
public int getOffset() {
|
||||||
return getOffset(pageSize);
|
return getOffset("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getListSize() {
|
public int getOffset(final String listName) {
|
||||||
return getItems().size();
|
return getOffset(listName, getPageSize(listName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPage() {
|
||||||
|
return getPage("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPage(final String listName) {
|
||||||
|
final String pageParamName = Stream
|
||||||
|
.of(listName, PAGE_PARAM_NAME)
|
||||||
|
.filter(token -> token != null && !token.isBlank())
|
||||||
|
.collect(
|
||||||
|
Collectors.joining(".")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pageUrlModel.getQueryParameters().containsKey(pageParamName)) {
|
||||||
|
return parsePageParam(pageParamName);
|
||||||
|
} else if (pageUrlModel.getQueryParameters()
|
||||||
|
.containsKey(PAGE_PARAM_NAME)) {
|
||||||
|
return parsePageParam(pageParamName);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public List<? extends AbstractContentItemListItemModel> getItems() {
|
public List<? extends AbstractContentItemListItemModel> getItems() {
|
||||||
// if (itemList == null) {
|
return getItems("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public List<? extends AbstractContentItemListItemModel> getItems(
|
||||||
|
final String listName
|
||||||
|
) {
|
||||||
|
final List<? extends AbstractContentItemListItemModel> items
|
||||||
|
= Collections.unmodifiableList(
|
||||||
buildList(
|
buildList(
|
||||||
buildLimitToType(limitToType),
|
buildLimitToType(getLimitToTypeSetting(listName)),
|
||||||
collectCategories(
|
collectCategories(
|
||||||
categoryRepository
|
categoryRepository
|
||||||
.findById(categoryModel.getCategory().getCategoryId())
|
.findById(categoryModel.getCategory().getCategoryId())
|
||||||
|
|
@ -179,19 +204,21 @@ public class ItemListModel {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
listOrder,
|
getListOrderSetting(listName),
|
||||||
pageSize
|
getPageSizeSetting(listName),
|
||||||
|
getOffset(listName, getPageSizeSetting(listName))
|
||||||
|
)
|
||||||
);
|
);
|
||||||
// }
|
|
||||||
|
|
||||||
return Collections.unmodifiableList(itemList);
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildList(
|
private List<? extends AbstractContentItemListItemModel> buildList(
|
||||||
final Class<? extends ContentItem> limitToType,
|
final Class<? extends ContentItem> limitToType,
|
||||||
final List<Category> categories,
|
final List<Category> categories,
|
||||||
final List<String> listOrder,
|
final List<String> listOrder,
|
||||||
final int pageSize
|
final int pageSize,
|
||||||
|
final int offset
|
||||||
) {
|
) {
|
||||||
final CriteriaBuilder criteriaBuilder = entityManager
|
final CriteriaBuilder criteriaBuilder = entityManager
|
||||||
.getCriteriaBuilder();
|
.getCriteriaBuilder();
|
||||||
|
|
@ -209,7 +236,7 @@ public class ItemListModel {
|
||||||
.where(
|
.where(
|
||||||
criteriaBuilder.and(
|
criteriaBuilder.and(
|
||||||
catJoin.get("category").in(categories),
|
catJoin.get("category").in(categories),
|
||||||
criteriaBuilder.equal(catJoin.get("indexObject"), false),
|
criteriaBuilder.isFalse(catJoin.get("indexObject")),
|
||||||
criteriaBuilder.isNull(catJoin.get("type")),
|
criteriaBuilder.isNull(catJoin.get("type")),
|
||||||
criteriaBuilder.equal(
|
criteriaBuilder.equal(
|
||||||
from.get("version"), ContentItemVersion.LIVE
|
from.get("version"), ContentItemVersion.LIVE
|
||||||
|
|
@ -227,7 +254,7 @@ public class ItemListModel {
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
);
|
);
|
||||||
|
|
||||||
itemList = entityManager
|
return entityManager
|
||||||
.createQuery(criteriaQuery)
|
.createQuery(criteriaQuery)
|
||||||
.getResultList()
|
.getResultList()
|
||||||
.stream()
|
.stream()
|
||||||
|
|
@ -236,7 +263,7 @@ public class ItemListModel {
|
||||||
item, globalizationHelper.getNegotiatedLocale()
|
item, globalizationHelper.getNegotiatedLocale()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.skip(getOffset(pageSize))
|
.skip(offset)
|
||||||
.limit(pageSize)
|
.limit(pageSize)
|
||||||
.map(this::buildListItemModel)
|
.map(this::buildListItemModel)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
@ -386,19 +413,90 @@ public class ItemListModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getOffset(final int pageSize) {
|
private int getOffset(final String listName, final int pageSize) {
|
||||||
if (pageUrlModel.getQueryParameters().containsKey("page")) {
|
return getPage(listName) * pageSize;
|
||||||
final String value = pageUrlModel.getQueryParameters().get("page");
|
}
|
||||||
if (value.matches("\\d*")) {
|
|
||||||
final int page = Integer.valueOf(value);
|
|
||||||
|
|
||||||
return page * pageSize;
|
private int parsePageParam(final String pageParamName) {
|
||||||
|
final String value = pageUrlModel
|
||||||
|
.getQueryParameters()
|
||||||
|
.get(pageParamName);
|
||||||
|
if (value.matches("\\d+")) {
|
||||||
|
return Integer.parseUnsignedInt(value);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getLimitToTypeSetting(final String listName) {
|
||||||
|
return Optional
|
||||||
|
.ofNullable(
|
||||||
|
pagePropertiesModel
|
||||||
|
.getProperties()
|
||||||
|
.get(
|
||||||
|
buildSettingKey(
|
||||||
|
listName,
|
||||||
|
LIMIT_TO_TYPE_SETTING
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.orElse(LIMIT_TO_TYPE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getListOrderSetting(final String listName) {
|
||||||
|
return Optional
|
||||||
|
.ofNullable(
|
||||||
|
pagePropertiesModel
|
||||||
|
.getProperties()
|
||||||
|
.get(
|
||||||
|
buildSettingKey(
|
||||||
|
listName,
|
||||||
|
LIST_ORDER_SETTING
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map(value -> value.split(","))
|
||||||
|
.map(
|
||||||
|
values -> Arrays
|
||||||
|
.asList(values)
|
||||||
|
.stream()
|
||||||
|
.map(String::strip)
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
)
|
||||||
|
.orElse(LIST_ORDER_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getPageSizeSetting(final String listName) {
|
||||||
|
return Optional
|
||||||
|
.ofNullable(
|
||||||
|
pagePropertiesModel
|
||||||
|
.getProperties()
|
||||||
|
.get(
|
||||||
|
buildSettingKey(
|
||||||
|
listName,
|
||||||
|
PAGE_SIZE_SETTING
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.filter(value -> value.matches("\\d+"))
|
||||||
|
.map(value -> Integer.parseUnsignedInt(value))
|
||||||
|
.orElse(PAGE_SIZE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildSettingKey(
|
||||||
|
final String listName,
|
||||||
|
final String settingKey
|
||||||
|
) {
|
||||||
|
return Stream
|
||||||
|
.of(
|
||||||
|
ITEM_LIST_SETTINGS_PREFIX,
|
||||||
|
listName,
|
||||||
|
settingKey
|
||||||
|
)
|
||||||
|
.filter(token -> token != null && !token.isBlank())
|
||||||
|
.collect(
|
||||||
|
Collectors.joining(".")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractContentItemListItemModel buildListItemModel(
|
private AbstractContentItemListItemModel buildListItemModel(
|
||||||
|
|
|
||||||
|
|
@ -18,27 +18,33 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.pages.models;
|
package org.librecms.pages.models;
|
||||||
|
|
||||||
import org.libreccm.l10n.GlobalizationHelper;
|
import java.util.ArrayList;
|
||||||
import org.librecms.contentsection.ContentItem;
|
import java.util.Collections;
|
||||||
import org.librecms.contenttypes.MultiPartArticle;
|
|
||||||
import org.librecms.contenttypes.MultiPartArticleSection;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
import javax.transaction.Transactional;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.libreccm.l10n.GlobalizationHelper;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
import org.librecms.contenttypes.MultiPartArticle;
|
||||||
|
import org.librecms.contenttypes.MultiPartArticleSection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
*/
|
*/
|
||||||
@RequestScoped
|
@RequestScoped
|
||||||
@Named("CmsPagesMultiPartArticleModel")
|
@Named("CmsPagesMultiPartArticleModel")
|
||||||
public class MultiPartArticleModel {
|
public class MultiPartArticleModel implements ProcessesContentItem {
|
||||||
|
|
||||||
|
private static final String MPA_SECTION_QUERY_PARAM = "mpa_section";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ContentItemModel contentItemModel;
|
private ContentItemModel contentItemModel;
|
||||||
|
|
@ -46,40 +52,145 @@ public class MultiPartArticleModel {
|
||||||
@Inject
|
@Inject
|
||||||
private GlobalizationHelper globalizationHelper;
|
private GlobalizationHelper globalizationHelper;
|
||||||
|
|
||||||
|
private boolean initialized;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PageUrlModel pageUrlModel;
|
private PageUrlModel pageUrlModel;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String summary;
|
||||||
|
|
||||||
|
private List<String> sectionTitles;
|
||||||
|
|
||||||
|
private List<String> sectionLinks;
|
||||||
|
|
||||||
|
private String prevSectionLink;
|
||||||
|
|
||||||
|
private String nextSectionLink;
|
||||||
|
|
||||||
|
private int currentSection;
|
||||||
|
|
||||||
|
private String currentSectionTitle;
|
||||||
|
|
||||||
|
private String currentSectionText;
|
||||||
|
|
||||||
|
private List<MultiPartArticleSectionModel> sections;
|
||||||
|
|
||||||
|
public MultiPartArticleModel() {
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return globalizationHelper.getValueFromLocalizedString(
|
contentItemModel.init();
|
||||||
getMultiPartArticle().getTitle()
|
|
||||||
);
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getSummary() {
|
public String getSummary() {
|
||||||
return globalizationHelper.getValueFromLocalizedString(
|
contentItemModel.init();
|
||||||
getMultiPartArticle().getSummary()
|
|
||||||
);
|
return summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public List<String> getSectionTitles() {
|
public List<String> getSectionTitles() {
|
||||||
return getMultiPartArticle()
|
contentItemModel.init();
|
||||||
.getSections()
|
|
||||||
|
return Collections.unmodifiableList(sectionTitles);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public List<String> getSectionLinks() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(sectionLinks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public String getPrevSectionLink() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return prevSectionLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public String getNextSectionLink() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return nextSectionLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public int getCurrentSection() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return currentSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public String getCurrentSectionTitle() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return currentSectionTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public String getCurrentSectionText() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return currentSectionText;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public List<MultiPartArticleSectionModel> getSections() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(sections);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public void init(final ContentItem contentItem) {
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentItem instanceof MultiPartArticle) {
|
||||||
|
final MultiPartArticle mpa = (MultiPartArticle) contentItem;
|
||||||
|
|
||||||
|
title = Optional
|
||||||
|
.ofNullable(mpa.getTitle())
|
||||||
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
|
.orElse("");
|
||||||
|
summary = Optional
|
||||||
|
.ofNullable(mpa.getSummary())
|
||||||
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
sectionTitles = Optional
|
||||||
|
.ofNullable(mpa.getSections())
|
||||||
|
.map(
|
||||||
|
mpaSections -> mpaSections
|
||||||
.stream()
|
.stream()
|
||||||
.map(MultiPartArticleSection::getTitle)
|
.map(MultiPartArticleSection::getTitle)
|
||||||
.map(globalizationHelper::getValueFromLocalizedString)
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList())
|
||||||
}
|
)
|
||||||
|
.orElse(Collections.emptyList());
|
||||||
|
|
||||||
public String getCurrentSectionTitle() {
|
currentSection = readCurrentSection();
|
||||||
final int currentSection = readCurrentSection();
|
|
||||||
if (getMultiPartArticle().getSections().size() > currentSection) {
|
if (mpa.getSections().size() < currentSection) {
|
||||||
throw new WebApplicationException(
|
throw new WebApplicationException(
|
||||||
Response
|
Response
|
||||||
.status(Response.Status.NOT_FOUND)
|
.status(Response.Status.NOT_FOUND)
|
||||||
.entity(
|
.entity(
|
||||||
String.format(
|
String.format(
|
||||||
"MultiPartArticle %s has not section %d.",
|
"MultiPartArticle %s has not section %d.",
|
||||||
getMultiPartArticle().getDisplayName(),
|
mpa.getDisplayName(),
|
||||||
currentSection
|
currentSection
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -87,65 +198,45 @@ public class MultiPartArticleModel {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return globalizationHelper.getValueFromLocalizedString(
|
if (mpa.getSections().isEmpty()) {
|
||||||
getMultiPartArticle().getSections().get(currentSection).getTitle()
|
currentSectionTitle = "";
|
||||||
);
|
currentSectionText = "";
|
||||||
|
} else {
|
||||||
|
currentSectionTitle = Optional
|
||||||
|
.ofNullable(mpa.getSections().get(currentSection).getTitle())
|
||||||
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
|
.orElse("");
|
||||||
|
|
||||||
|
currentSectionText = Optional
|
||||||
|
.ofNullable(mpa.getSections().get(currentSection).getText())
|
||||||
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCurrentSectionText() {
|
sectionLinks = buildSectionLinks();
|
||||||
final int currentSection = readCurrentSection();
|
sections = mpa
|
||||||
if (getMultiPartArticle().getSections().size() > currentSection) {
|
|
||||||
throw new WebApplicationException(
|
|
||||||
Response
|
|
||||||
.status(Response.Status.NOT_FOUND)
|
|
||||||
.entity(
|
|
||||||
String.format(
|
|
||||||
"MultiPartArticle %s has not section %d.",
|
|
||||||
getMultiPartArticle().getDisplayName(),
|
|
||||||
currentSection
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return globalizationHelper.getValueFromLocalizedString(
|
|
||||||
getMultiPartArticle().getSections().get(currentSection).getText()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<MultiPartArticleSectionModel> getSections() {
|
|
||||||
return getMultiPartArticle()
|
|
||||||
.getSections()
|
.getSections()
|
||||||
.stream()
|
.stream()
|
||||||
.map(this::buildSectionModel)
|
.map(this::buildSectionModel)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MultiPartArticle getMultiPartArticle() {
|
initialized = true;
|
||||||
final ContentItem contentItem = contentItemModel.getContentItem();
|
|
||||||
if (contentItem instanceof MultiPartArticle) {
|
|
||||||
return (MultiPartArticle) contentItem;
|
|
||||||
} else {
|
|
||||||
throw new WebApplicationException(
|
|
||||||
"Current content item is not an MultiPartArticle",
|
|
||||||
Response
|
|
||||||
.status(Response.Status.INTERNAL_SERVER_ERROR)
|
|
||||||
.entity("Current content item is not an MultiPartArticle.")
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readCurrentSection() {
|
private int readCurrentSection() {
|
||||||
if (pageUrlModel.getPath().matches(".*/@sections/[0-9]*$")) {
|
return Optional
|
||||||
final String[] tokens = pageUrlModel.getPath().split("/");
|
.ofNullable(
|
||||||
return Integer.valueOf(tokens[tokens.length - 1]) - 1;
|
pageUrlModel.getQueryParameters().get(
|
||||||
} else {
|
MPA_SECTION_QUERY_PARAM
|
||||||
return 0;
|
)
|
||||||
}
|
)
|
||||||
|
.filter(value -> value.matches("\\d*"))
|
||||||
|
.map(value -> Integer.parseInt(value))
|
||||||
|
.orElse(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
private MultiPartArticleSectionModel buildSectionModel(
|
private MultiPartArticleSectionModel buildSectionModel(
|
||||||
final MultiPartArticleSection fromSection
|
final MultiPartArticleSection fromSection
|
||||||
) {
|
) {
|
||||||
|
|
@ -165,4 +256,52 @@ public class MultiPartArticleModel {
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
private List<String> buildSectionLinks() {
|
||||||
|
final int size = sectionTitles.size();
|
||||||
|
final List<String> sectionLinksList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
sectionLinksList.add(buildSectionLink(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSection == 0) {
|
||||||
|
prevSectionLink = "";
|
||||||
|
} else {
|
||||||
|
prevSectionLink = buildSectionLink(currentSection - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSection < sectionLinksList.size() - 1) {
|
||||||
|
nextSectionLink = buildSectionLink(currentSection + 1);
|
||||||
|
} else {
|
||||||
|
nextSectionLink = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return sectionLinksList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildSectionLink(final int section) {
|
||||||
|
return String.format(
|
||||||
|
"?%s&%s=%d",
|
||||||
|
pageUrlModel
|
||||||
|
.getQueryParameters()
|
||||||
|
.entrySet()
|
||||||
|
.stream()
|
||||||
|
.filter(
|
||||||
|
entry
|
||||||
|
-> !MPA_SECTION_QUERY_PARAM
|
||||||
|
.equals(
|
||||||
|
entry.getKey()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map(
|
||||||
|
entry -> String.format(
|
||||||
|
"%s=%s", entry.getKey(), entry.getValue()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.collect(Collectors.joining("&")),
|
||||||
|
MPA_SECTION_QUERY_PARAM,
|
||||||
|
section
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,22 @@ public class NewsListItemModel extends AbstractContentItemListItemModel {
|
||||||
return releaseDate;
|
return releaseDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the release date of the news represeted by this model formatted
|
||||||
|
* using the provided pattern. The pattern MUST be a valid pattern for
|
||||||
|
* {@link DateTimeFormatter#ofPattern(java.lang.String) }.
|
||||||
|
*
|
||||||
|
* @param pattern The pattern to use for formatting the release date.
|
||||||
|
*
|
||||||
|
* @return The formatted release date.
|
||||||
|
*/
|
||||||
|
public String getReleaseDate(final String pattern) {
|
||||||
|
return DateTimeFormatter
|
||||||
|
.ofPattern(pattern, getLocale())
|
||||||
|
.withZone(ZoneId.systemDefault())
|
||||||
|
.format(releaseDate);
|
||||||
|
}
|
||||||
|
|
||||||
public String getReleaseDateAsString() {
|
public String getReleaseDateAsString() {
|
||||||
return DateTimeFormatter.ISO_DATE_TIME
|
return DateTimeFormatter.ISO_DATE_TIME
|
||||||
.withZone(ZoneId.systemDefault())
|
.withZone(ZoneId.systemDefault())
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ package org.librecms.pages.models;
|
||||||
import org.librecms.contenttypes.News;
|
import org.librecms.contenttypes.News;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
|
|
||||||
|
|
@ -48,7 +49,9 @@ public class NewsListItemModelBuilder
|
||||||
) {
|
) {
|
||||||
super.addProperties(news, model);
|
super.addProperties(news, model);
|
||||||
model.setReleaseDate(
|
model.setReleaseDate(
|
||||||
LocalDateTime.from(news.getReleaseDate().toInstant())
|
LocalDateTime.from(
|
||||||
|
news.getReleaseDate().toInstant().atZone(ZoneId.systemDefault())
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,20 +18,19 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.pages.models;
|
package org.librecms.pages.models;
|
||||||
|
|
||||||
import org.libreccm.l10n.GlobalizationHelper;
|
|
||||||
import org.librecms.contentsection.ContentItem;
|
|
||||||
import org.librecms.contenttypes.News;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Date;
|
import java.util.Optional;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.transaction.Transactional;
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
|
import org.libreccm.l10n.GlobalizationHelper;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
import org.librecms.contenttypes.News;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
@ -39,7 +38,7 @@ import javax.ws.rs.core.Response;
|
||||||
*/
|
*/
|
||||||
@RequestScoped
|
@RequestScoped
|
||||||
@Named("CmsPagesNewsModel")
|
@Named("CmsPagesNewsModel")
|
||||||
public class NewsModel {
|
public class NewsModel implements ProcessesContentItem {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ContentItemModel contentItemModel;
|
private ContentItemModel contentItemModel;
|
||||||
|
|
@ -47,46 +46,130 @@ public class NewsModel {
|
||||||
@Inject
|
@Inject
|
||||||
private GlobalizationHelper globalizationHelper;
|
private GlobalizationHelper globalizationHelper;
|
||||||
|
|
||||||
|
private boolean initialized;
|
||||||
|
|
||||||
|
private final DateTimeFormatter isoDateTimeFormatter;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
private LocalDateTime releaseDateTime;
|
||||||
|
|
||||||
|
private boolean homepage;
|
||||||
|
|
||||||
|
public NewsModel() {
|
||||||
|
initialized = false;
|
||||||
|
isoDateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME
|
||||||
|
.withZone(ZoneId.systemDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return globalizationHelper
|
contentItemModel.init();
|
||||||
.getValueFromLocalizedString(getNews().getTitle());
|
|
||||||
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return globalizationHelper
|
contentItemModel.init();
|
||||||
.getValueFromLocalizedString(getNews().getDescription());
|
|
||||||
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return globalizationHelper
|
contentItemModel.init();
|
||||||
.getValueFromLocalizedString(getNews().getText());
|
|
||||||
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getReleaseDateTime() {
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
return DateTimeFormatter.ISO_DATE_TIME
|
public LocalDateTime getReleaseDateTime() {
|
||||||
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return releaseDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the release date of the news represented by this model formatted
|
||||||
|
* using the provided pattern. The pattern MUST be a valid pattern for
|
||||||
|
* {@link DateTimeFormatter#ofPattern(java.lang.String) }.
|
||||||
|
*
|
||||||
|
* @param pattern The pattern to use for formatting the release date.
|
||||||
|
*
|
||||||
|
* @return The formatted release date.
|
||||||
|
*/
|
||||||
|
public String getReleaseDate(final String pattern) {
|
||||||
|
return Optional
|
||||||
|
.ofNullable(releaseDateTime)
|
||||||
|
.map(
|
||||||
|
dateTime -> DateTimeFormatter
|
||||||
|
.ofPattern(
|
||||||
|
pattern,
|
||||||
|
globalizationHelper.getNegotiatedLocale()
|
||||||
|
)
|
||||||
.withZone(ZoneId.systemDefault())
|
.withZone(ZoneId.systemDefault())
|
||||||
.format(
|
.format(dateTime)
|
||||||
LocalDateTime.from(getNews().getReleaseDate().toInstant())
|
)
|
||||||
);
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getReleaseDateTimeAsString() {
|
||||||
|
return Optional
|
||||||
|
.ofNullable(releaseDateTime)
|
||||||
|
.map(
|
||||||
|
dateTime -> DateTimeFormatter.ISO_DATE_TIME
|
||||||
|
.withZone(ZoneId.systemDefault())
|
||||||
|
.format(dateTime)
|
||||||
|
)
|
||||||
|
.orElse("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public boolean getHomepage() {
|
public boolean getHomepage() {
|
||||||
return getNews().isHomepage();
|
contentItemModel.init();
|
||||||
|
|
||||||
|
return homepage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public void init(final ContentItem contentItem) {
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected News getNews() {
|
|
||||||
final ContentItem contentItem = contentItemModel.getContentItem();
|
|
||||||
if (contentItem instanceof News) {
|
if (contentItem instanceof News) {
|
||||||
return (News) contentItem;
|
final News news = (News) contentItem;
|
||||||
} else {
|
|
||||||
throw new WebApplicationException(
|
title = Optional
|
||||||
"Current content item is not a news item.",
|
.ofNullable(news.getTitle())
|
||||||
Response
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
.status(Response.Status.INTERNAL_SERVER_ERROR)
|
.orElse("");
|
||||||
.entity("Current content item is not a new item.")
|
description = Optional
|
||||||
.build()
|
.ofNullable(news.getDescription())
|
||||||
);
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
|
.orElse("");
|
||||||
|
text = Optional
|
||||||
|
.ofNullable(news.getText())
|
||||||
|
.map(globalizationHelper::getValueFromLocalizedString)
|
||||||
|
.orElse("");
|
||||||
|
releaseDateTime = Optional
|
||||||
|
.ofNullable(news.getReleaseDate())
|
||||||
|
.map(
|
||||||
|
date -> LocalDateTime.from(
|
||||||
|
date.toInstant().atZone(ZoneId.systemDefault())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.orElse(null);
|
||||||
|
homepage = news.isHomepage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,13 @@ package org.librecms.pages.models;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model initalized by the Pages application containing information about the
|
* Model initialized by the Pages application containing information about the
|
||||||
* URL requested.
|
* URL requested.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
|
@ -93,4 +94,20 @@ public class PageUrlModel {
|
||||||
this.queryParameters = new HashMap<>(queryParameters);
|
this.queryParameters = new HashMap<>(queryParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getQueryString() {
|
||||||
|
return queryParameters
|
||||||
|
.entrySet()
|
||||||
|
.stream()
|
||||||
|
.map(
|
||||||
|
entry -> String.format(
|
||||||
|
"%s=%s",
|
||||||
|
entry.getKey(),
|
||||||
|
entry.getValue()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.collect(
|
||||||
|
Collectors.joining("&", "?", "")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.models;
|
||||||
|
|
||||||
|
import org.hibernate.LazyInitializationException;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models that provide data for the current content item (either the index item
|
||||||
|
* of a category or a selected content item) SHOULD implement this interface.
|
||||||
|
*
|
||||||
|
* This {@link ContentItemModel} collects all instances of classes implementing
|
||||||
|
* this interface and calls their implemententation of the
|
||||||
|
* {@link #init(org.librecms.contentsection.ContentItem)} method.
|
||||||
|
*
|
||||||
|
* For an example of an implementation please look at
|
||||||
|
* {@link ContentItemTypeModel}, {@link ArticleModel} or
|
||||||
|
* at {@link MultiPartArticleModel} for a more complex model.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
public interface ProcessesContentItem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initalizes a model providing the data of a content item for MVC
|
||||||
|
* templates.
|
||||||
|
*
|
||||||
|
* If the implementing model only provides data for specific sub classes of
|
||||||
|
* {@link ContentItem} the implementation MUST check the correct type using
|
||||||
|
* the {@code instanceof} operator. If the item is not a the correct type a
|
||||||
|
* implementation MUST gracefully ignore the item.
|
||||||
|
*
|
||||||
|
* To avoid a {@link LazyInitializationException} implementations SHOULD be
|
||||||
|
* annotated with {@link Transactional} and the
|
||||||
|
* {@link Transactional.TxType#REQUIRED}.
|
||||||
|
*
|
||||||
|
* @param item The item.
|
||||||
|
*/
|
||||||
|
void init(ContentItem item);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -515,7 +515,7 @@ public class PagesController {
|
||||||
return showPageDetails(pagesInstance, categoryParam);
|
return showPageDetails(pagesInstance, categoryParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!propertyKey.matches("^([a-z0-9-_]*)$")) {
|
if (!propertyKey.matches("^([a-zA-Z0-9-_\\.]*)$")) {
|
||||||
models.put("propertyKeyInvalid", true);
|
models.put("propertyKeyInvalid", true);
|
||||||
return showPageDetails(pagesInstance, categoryParam);
|
return showPageDetails(pagesInstance, categoryParam);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,6 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.ui.contentsections;
|
package org.librecms.ui.contentsections;
|
||||||
|
|
||||||
import com.arsdigita.cms.ui.authoring.multipartarticle.SectionPreviewPanel;
|
|
||||||
|
|
||||||
import org.libreccm.api.Identifier;
|
import org.libreccm.api.Identifier;
|
||||||
import org.libreccm.api.IdentifierParser;
|
import org.libreccm.api.IdentifierParser;
|
||||||
import org.libreccm.categorization.Categorization;
|
import org.libreccm.categorization.Categorization;
|
||||||
|
|
@ -33,8 +31,12 @@ import org.libreccm.core.CcmObject;
|
||||||
import org.libreccm.l10n.GlobalizationHelper;
|
import org.libreccm.l10n.GlobalizationHelper;
|
||||||
import org.libreccm.security.AuthorizationRequired;
|
import org.libreccm.security.AuthorizationRequired;
|
||||||
import org.libreccm.security.PermissionChecker;
|
import org.libreccm.security.PermissionChecker;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
import org.librecms.contentsection.ContentItemManager;
|
||||||
|
import org.librecms.contentsection.ContentItemVersion;
|
||||||
import org.librecms.contentsection.ContentSection;
|
import org.librecms.contentsection.ContentSection;
|
||||||
import org.librecms.contentsection.ContentSectionRepository;
|
import org.librecms.contentsection.ContentSectionRepository;
|
||||||
|
import org.librecms.contentsection.Folder;
|
||||||
import org.librecms.contentsection.privileges.AdminPrivileges;
|
import org.librecms.contentsection.privileges.AdminPrivileges;
|
||||||
|
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
|
|
@ -87,6 +89,12 @@ public class CategoriesController {
|
||||||
@Inject
|
@Inject
|
||||||
private CategorySystemModel categorySystemModel;
|
private CategorySystemModel categorySystemModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ContentItemManager}.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private ContentItemManager itemManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link ContentSectionModel} which stores the data of the current
|
* The {@link ContentSectionModel} which stores the data of the current
|
||||||
* content section for the view.
|
* content section for the view.
|
||||||
|
|
@ -812,18 +820,59 @@ public class CategoriesController {
|
||||||
category.setAbstractCategory(Objects.equals("true", isAbstract));
|
category.setAbstractCategory(Objects.equals("true", isAbstract));
|
||||||
categoryRepo.save(category);
|
categoryRepo.save(category);
|
||||||
|
|
||||||
|
// return String.format(
|
||||||
|
// "redirect:/%s/categorysystems/%s/categories/%s/%s",
|
||||||
|
// sectionIdentifier,
|
||||||
|
// context,
|
||||||
|
// categoryManager.getCategoryPath(category.getParentCategory()),
|
||||||
|
// categoryName
|
||||||
|
// );
|
||||||
return String.format(
|
return String.format(
|
||||||
"redirect:/%s/categorysystems/%s/categories/%s/%s",
|
"redirect:/%s/categorysystems/%s/categories/%s",
|
||||||
sectionIdentifier,
|
sectionIdentifier,
|
||||||
context,
|
context,
|
||||||
categoryManager.getCategoryPath(category.getParentCategory()),
|
categoryManager.getCategoryPath(category)
|
||||||
categoryName
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return result.getFailedResponseTemplate();
|
return result.getFailedResponseTemplate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the index element of the root category.
|
||||||
|
*
|
||||||
|
* @param sectionIdentifier The identifier of the current
|
||||||
|
* {@link ContentSection}.
|
||||||
|
* @param context The mapping context of the assigned category
|
||||||
|
* system.
|
||||||
|
* @param indexElementUuid The UUID of the new index element.
|
||||||
|
*
|
||||||
|
* @return A redirect to the category page or the template for generating an
|
||||||
|
* error view.
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@Path(
|
||||||
|
"/{context}/categories/@index-element/{indexElementUuid}")
|
||||||
|
@AuthorizationRequired
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public String setIndexElement(
|
||||||
|
@PathParam("sectionIdentifier") final String sectionIdentifier,
|
||||||
|
@PathParam("context") final String context,
|
||||||
|
@PathParam("indexElementUuid") final String indexElementUuid
|
||||||
|
) {
|
||||||
|
final RetrieveResult<Category> result = retrieveCategory(
|
||||||
|
sectionIdentifier, context, "/"
|
||||||
|
);
|
||||||
|
|
||||||
|
return setIndexObject(
|
||||||
|
result,
|
||||||
|
sectionIdentifier,
|
||||||
|
context,
|
||||||
|
context,
|
||||||
|
indexElementUuid
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the index element of a category.
|
* Sets the index element of a category.
|
||||||
*
|
*
|
||||||
|
|
@ -837,7 +886,7 @@ public class CategoriesController {
|
||||||
* @return A redirect to the category page or the template for generating an
|
* @return A redirect to the category page or the template for generating an
|
||||||
* error view.
|
* error view.
|
||||||
*/
|
*/
|
||||||
@GET
|
@POST
|
||||||
@Path(
|
@Path(
|
||||||
"/{context}/categories/{categoryPath:(.+)?}/@index-element/{indexElementUuid}")
|
"/{context}/categories/{categoryPath:(.+)?}/@index-element/{indexElementUuid}")
|
||||||
@AuthorizationRequired
|
@AuthorizationRequired
|
||||||
|
|
@ -851,41 +900,95 @@ public class CategoriesController {
|
||||||
final RetrieveResult<Category> result = retrieveCategory(
|
final RetrieveResult<Category> result = retrieveCategory(
|
||||||
sectionIdentifier, context, categoryPath
|
sectionIdentifier, context, categoryPath
|
||||||
);
|
);
|
||||||
if (result.isSuccessful()) {
|
|
||||||
final Category category = result.getResult();
|
return setIndexObject(
|
||||||
final Optional<Categorization> categorizationResult = category
|
result,
|
||||||
.getObjects()
|
|
||||||
.stream()
|
|
||||||
.filter(
|
|
||||||
categorization -> Objects.equals(
|
|
||||||
categorization.getUuid(), indexElementUuid
|
|
||||||
)
|
|
||||||
).findAny();
|
|
||||||
if (categorizationResult.isPresent()) {
|
|
||||||
final CcmObject object = categorizationResult
|
|
||||||
.get()
|
|
||||||
.getCategorizedObject();
|
|
||||||
try {
|
|
||||||
categoryManager.setIndexObject(category, object);
|
|
||||||
} catch (ObjectNotAssignedToCategoryException ex) {
|
|
||||||
models.put("sectionIdentifier", sectionIdentifier);
|
|
||||||
models.put("context", context);
|
|
||||||
models.put("categoryPath", categoryPath);
|
|
||||||
models.put("categorizationUuid", indexElementUuid);
|
|
||||||
return "org/librecms/ui/contentsection/categorysystems/categorization-not-found.xhtml";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
models.put("sectionIdentifier", sectionIdentifier);
|
|
||||||
models.put("context", context);
|
|
||||||
models.put("categoryPath", categoryPath);
|
|
||||||
models.put("categorizationUuid", indexElementUuid);
|
|
||||||
return "org/librecms/ui/contentsection/categorysystems/categorization-not-found.xhtml";
|
|
||||||
}
|
|
||||||
return String.format(
|
|
||||||
"redirect:/%s/categorysystems/%s/categories/%s#objects-sections",
|
|
||||||
sectionIdentifier,
|
sectionIdentifier,
|
||||||
context,
|
context,
|
||||||
categoryPath
|
categoryPath,
|
||||||
|
indexElementUuid
|
||||||
|
);
|
||||||
|
// if (result.isSuccessful()) {
|
||||||
|
// final Category category = result.getResult();
|
||||||
|
// final Optional<Categorization> categorizationResult = category
|
||||||
|
// .getObjects()
|
||||||
|
// .stream()
|
||||||
|
// .filter(
|
||||||
|
// categorization -> Objects.equals(
|
||||||
|
// categorization.getUuid(), indexElementUuid
|
||||||
|
// )
|
||||||
|
// ).findAny();
|
||||||
|
// if (categorizationResult.isPresent()) {
|
||||||
|
// final CcmObject object = categorizationResult
|
||||||
|
// .get()
|
||||||
|
// .getCategorizedObject();
|
||||||
|
// try {
|
||||||
|
// categoryManager.setIndexObject(category, object);
|
||||||
|
// if (object instanceof ContentItem) {
|
||||||
|
// final ContentItem item = (ContentItem) object;
|
||||||
|
// final ContentItem live = itemManager.getDraftVersion(
|
||||||
|
// item,
|
||||||
|
// ContentItem.class
|
||||||
|
// );
|
||||||
|
// categoryManager.setIndexObject(category, live);
|
||||||
|
// }
|
||||||
|
// } catch (ObjectNotAssignedToCategoryException ex) {
|
||||||
|
// models.put("sectionIdentifier", sectionIdentifier);
|
||||||
|
// models.put("context", context);
|
||||||
|
// models.put("categoryPath", categoryPath);
|
||||||
|
// models.put("categorizationUuid", indexElementUuid);
|
||||||
|
// return "org/librecms/ui/contentsection/categorysystems/categorization-not-found.xhtml";
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// models.put("sectionIdentifier", sectionIdentifier);
|
||||||
|
// models.put("context", context);
|
||||||
|
// models.put("categoryPath", categoryPath);
|
||||||
|
// models.put("categorizationUuid", indexElementUuid);
|
||||||
|
// return "org/librecms/ui/contentsection/categorysystems/categorization-not-found.xhtml";
|
||||||
|
// }
|
||||||
|
// return String.format(
|
||||||
|
// "redirect:/%s/categorysystems/%s/categories/%s#objects-sections",
|
||||||
|
// sectionIdentifier,
|
||||||
|
// context,
|
||||||
|
// categoryPath
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// return result.getFailedResponseTemplate();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the index object of the root category. The object is still
|
||||||
|
* associated with the category after this, but no longer the index object
|
||||||
|
* of the category.
|
||||||
|
*
|
||||||
|
* @param sectionIdentifier The identifier of the current
|
||||||
|
* {@link ContentSection}.
|
||||||
|
* @param context The mapping context of the assigned category
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* @return A redirect to the category page or the template for generating an
|
||||||
|
* error view.
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@Path("/{context}/categories/@index-element/reset")
|
||||||
|
@AuthorizationRequired
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public String resetIndexElement(
|
||||||
|
@PathParam("sectionIdentifier") final String sectionIdentifier,
|
||||||
|
@PathParam("context") final String context
|
||||||
|
) {
|
||||||
|
final RetrieveResult<Category> result = retrieveCategory(
|
||||||
|
sectionIdentifier, context, "/"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.isSuccessful()) {
|
||||||
|
final Category category = result.getResult();
|
||||||
|
categoryManager.resetIndexObject(category);
|
||||||
|
return String.format(
|
||||||
|
"redirect:/%s/categorysystems/%s/categories/",
|
||||||
|
sectionIdentifier,
|
||||||
|
context
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return result.getFailedResponseTemplate();
|
return result.getFailedResponseTemplate();
|
||||||
|
|
@ -893,7 +996,9 @@ public class CategoriesController {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rests (removes) the index element of a category.
|
* Resets the index object of a category. The object is still associated
|
||||||
|
* with the category after this, but no longer the index object of the
|
||||||
|
* category.
|
||||||
*
|
*
|
||||||
* @param sectionIdentifier The identifier of the current
|
* @param sectionIdentifier The identifier of the current
|
||||||
* {@link ContentSection}.
|
* {@link ContentSection}.
|
||||||
|
|
@ -904,7 +1009,7 @@ public class CategoriesController {
|
||||||
* @return A redirect to the category page or the template for generating an
|
* @return A redirect to the category page or the template for generating an
|
||||||
* error view.
|
* error view.
|
||||||
*/
|
*/
|
||||||
@GET
|
@POST
|
||||||
@Path("/{context}/categories/{categoryPath:(.+)?}/@index-element/reset")
|
@Path("/{context}/categories/{categoryPath:(.+)?}/@index-element/reset")
|
||||||
@AuthorizationRequired
|
@AuthorizationRequired
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
|
@ -920,7 +1025,7 @@ public class CategoriesController {
|
||||||
final Category category = result.getResult();
|
final Category category = result.getResult();
|
||||||
categoryManager.resetIndexObject(category);
|
categoryManager.resetIndexObject(category);
|
||||||
return String.format(
|
return String.format(
|
||||||
"redirect:/%s/categorysystems/%s/categories/%s#objects-sections",
|
"redirect:/%s/categorysystems/%s/categories/%s",
|
||||||
sectionIdentifier,
|
sectionIdentifier,
|
||||||
context,
|
context,
|
||||||
categoryPath
|
categoryPath
|
||||||
|
|
@ -1220,7 +1325,47 @@ public class CategoriesController {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reorders subcategories.
|
* Reorders objects assigned to the root category.
|
||||||
|
*
|
||||||
|
* @param sectionIdentifier The identifier of the current
|
||||||
|
* {@link ContentSection}.
|
||||||
|
* @param context The mapping context of the assigned category
|
||||||
|
* system.
|
||||||
|
* @param objectIdentifier The identifier of the object to move.
|
||||||
|
* @param direction The direction of the move.
|
||||||
|
*
|
||||||
|
* @return A redirect to the details page of the parent category or the
|
||||||
|
* template for building an error message.
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@Path(
|
||||||
|
"/{context}/categories/@objects/{objectIdentifier}/order"
|
||||||
|
)
|
||||||
|
@AuthorizationRequired
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public String orderObjects(
|
||||||
|
@PathParam("sectionIdentifier") final String sectionIdentifier,
|
||||||
|
@PathParam("context") final String context,
|
||||||
|
@PathParam("objectIdentifier") final String objectIdentifier,
|
||||||
|
@FormParam("direction") final String direction
|
||||||
|
) {
|
||||||
|
final RetrieveResult<Category> result = retrieveCategory(
|
||||||
|
sectionIdentifier,
|
||||||
|
context,
|
||||||
|
"/"
|
||||||
|
);
|
||||||
|
|
||||||
|
return orderObjects(
|
||||||
|
result,
|
||||||
|
sectionIdentifier,
|
||||||
|
context,
|
||||||
|
objectIdentifier,
|
||||||
|
direction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorders objects assigned to a category.
|
||||||
*
|
*
|
||||||
* @param sectionIdentifier The identifier of the current
|
* @param sectionIdentifier The identifier of the current
|
||||||
* {@link ContentSection}.
|
* {@link ContentSection}.
|
||||||
|
|
@ -1246,9 +1391,147 @@ public class CategoriesController {
|
||||||
@FormParam("direction") final String direction
|
@FormParam("direction") final String direction
|
||||||
) {
|
) {
|
||||||
final RetrieveResult<Category> result = retrieveCategory(
|
final RetrieveResult<Category> result = retrieveCategory(
|
||||||
sectionIdentifier, context, categoryPath
|
sectionIdentifier,
|
||||||
|
context,
|
||||||
|
categoryPath
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return orderObjects(
|
||||||
|
result,
|
||||||
|
sectionIdentifier,
|
||||||
|
context,
|
||||||
|
objectIdentifier,
|
||||||
|
direction
|
||||||
|
);
|
||||||
|
//
|
||||||
|
// if (result.isSuccessful()) {
|
||||||
|
// final Category category = result.getResult();
|
||||||
|
//
|
||||||
|
// final Optional<Categorization> categorizationResult = category
|
||||||
|
// .getObjects()
|
||||||
|
// .stream()
|
||||||
|
// .filter(
|
||||||
|
// categorization -> Objects.equals(
|
||||||
|
// categorization.getUuid(), objectIdentifier
|
||||||
|
// )
|
||||||
|
// ).findAny();
|
||||||
|
// if (categorizationResult.isPresent()) {
|
||||||
|
// final CcmObject object = categorizationResult
|
||||||
|
// .get()
|
||||||
|
// .getCategorizedObject();
|
||||||
|
// try {
|
||||||
|
// switch (direction) {
|
||||||
|
// case "DECREASE":
|
||||||
|
// categoryManager.decreaseObjectOrder(
|
||||||
|
// object, category
|
||||||
|
// );
|
||||||
|
// break;
|
||||||
|
// case "INCREASE":
|
||||||
|
// categoryManager.increaseObjectOrder(
|
||||||
|
// object, category
|
||||||
|
// );
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// // Nothing
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// } catch (ObjectNotAssignedToCategoryException ex) {
|
||||||
|
// return String.format(
|
||||||
|
// "redirect:/%s/categorysystems/%s/categories/%s#objects-sections",
|
||||||
|
// sectionIdentifier,
|
||||||
|
// context,
|
||||||
|
// categoryManager.getCategoryPath(category)
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return String.format(
|
||||||
|
// "redirect:/%s/categorysystems/%s/categories/%s",
|
||||||
|
// sectionIdentifier,
|
||||||
|
// context,
|
||||||
|
// categoryManager.getCategoryPath(category)
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// return result.getFailedResponseTemplate();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private String setIndexObject(
|
||||||
|
final RetrieveResult<Category> result,
|
||||||
|
@PathParam("sectionIdentifier") final String sectionIdentifier,
|
||||||
|
@PathParam("context") final String context,
|
||||||
|
@PathParam("categoryPath") final String categoryPath,
|
||||||
|
@PathParam("indexElementUuid") final String indexElementUuid
|
||||||
|
) {
|
||||||
|
if (result.isSuccessful()) {
|
||||||
|
final Category category = result.getResult();
|
||||||
|
final List<Categorization> categorizationResult = category
|
||||||
|
.getObjects()
|
||||||
|
.stream()
|
||||||
|
.filter(
|
||||||
|
categorization -> Objects.equals(
|
||||||
|
categorization.getCategorizedObject().getUuid(),
|
||||||
|
indexElementUuid
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (!categorizationResult.isEmpty()) {
|
||||||
|
for (final Categorization categorization : categorizationResult) {
|
||||||
|
final CcmObject object = categorization
|
||||||
|
.getCategorizedObject();
|
||||||
|
try {
|
||||||
|
categoryManager.setIndexObject(category, object);
|
||||||
|
if (object instanceof ContentItem) {
|
||||||
|
final ContentItem item = (ContentItem) object;
|
||||||
|
final ContentItem live = itemManager
|
||||||
|
.getDraftVersion(
|
||||||
|
item,
|
||||||
|
ContentItem.class
|
||||||
|
);
|
||||||
|
categoryManager.setIndexObject(category, live);
|
||||||
|
}
|
||||||
|
} catch (ObjectNotAssignedToCategoryException ex) {
|
||||||
|
models.put("sectionIdentifier", sectionIdentifier);
|
||||||
|
models.put("context", context);
|
||||||
|
models.put("categoryPath", categoryPath);
|
||||||
|
models.put("categorizationUuid", indexElementUuid);
|
||||||
|
return "org/librecms/ui/contentsection/categorysystems/categorization-not-found.xhtml";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
models.put("sectionIdentifier", sectionIdentifier);
|
||||||
|
models.put("context", context);
|
||||||
|
models.put("categoryPath", categoryPath);
|
||||||
|
models.put("categorizationUuid", indexElementUuid);
|
||||||
|
return "org/librecms/ui/contentsection/categorysystems/categorization-not-found.xhtml";
|
||||||
|
}
|
||||||
|
if ("/".equals(categoryPath)
|
||||||
|
|| category.getParentCategory() == null) {
|
||||||
|
return String.format(
|
||||||
|
"redirect:/%s/categorysystems/%s/categories/",
|
||||||
|
sectionIdentifier,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return String.format(
|
||||||
|
"redirect:/%s/categorysystems/%s/categories/%s",
|
||||||
|
sectionIdentifier,
|
||||||
|
context,
|
||||||
|
categoryPath
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return result.getFailedResponseTemplate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String orderObjects(
|
||||||
|
final RetrieveResult<Category> result,
|
||||||
|
final String sectionIdentifier,
|
||||||
|
final String context,
|
||||||
|
final String objectIdentifier,
|
||||||
|
final String direction
|
||||||
|
) {
|
||||||
if (result.isSuccessful()) {
|
if (result.isSuccessful()) {
|
||||||
final Category category = result.getResult();
|
final Category category = result.getResult();
|
||||||
|
|
||||||
|
|
@ -1358,7 +1641,7 @@ public class CategoriesController {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final ContentSection section = sectionResult.get();
|
final ContentSection section = sectionResult.get();
|
||||||
if (permissionChecker.isPermitted(
|
if (!permissionChecker.isPermitted(
|
||||||
AdminPrivileges.ADMINISTER_CATEGORIES, section
|
AdminPrivileges.ADMINISTER_CATEGORIES, section
|
||||||
)) {
|
)) {
|
||||||
return RetrieveResult.failed(
|
return RetrieveResult.failed(
|
||||||
|
|
@ -1477,6 +1760,15 @@ public class CategoriesController {
|
||||||
category
|
category
|
||||||
.getObjects()
|
.getObjects()
|
||||||
.stream()
|
.stream()
|
||||||
|
.filter(
|
||||||
|
categorization -> categorization
|
||||||
|
.getCategorizedObject() instanceof ContentItem
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
categorization -> ((ContentItem) categorization
|
||||||
|
.getCategorizedObject())
|
||||||
|
.getVersion() == ContentItemVersion.DRAFT
|
||||||
|
)
|
||||||
.map(this::buildCategorizedObjectModel)
|
.map(this::buildCategorizedObjectModel)
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ public class CategoryModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setObjects(final List<CategorizedObjectModel> objects) {
|
public void setObjects(final List<CategorizedObjectModel> objects) {
|
||||||
this.objects = new ArrayList<>();
|
this.objects = new ArrayList<>(objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getCategoryOrder() {
|
public long getCategoryOrder() {
|
||||||
|
|
|
||||||
|
|
@ -815,7 +815,7 @@ public class DocumentController {
|
||||||
}
|
}
|
||||||
|
|
||||||
return String.format(
|
return String.format(
|
||||||
"redirect:/%s/documentfolders/%s",
|
"redirect:/%s/documentfolders%s",
|
||||||
sectionIdentifier,
|
sectionIdentifier,
|
||||||
folderPath
|
folderPath
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import org.libreccm.api.IdentifierParser;
|
||||||
import org.libreccm.l10n.GlobalizationHelper;
|
import org.libreccm.l10n.GlobalizationHelper;
|
||||||
import org.libreccm.security.PermissionChecker;
|
import org.libreccm.security.PermissionChecker;
|
||||||
import org.libreccm.ui.BaseUrl;
|
import org.libreccm.ui.BaseUrl;
|
||||||
|
import org.librecms.CmsConstants;
|
||||||
import org.librecms.assets.AssetTypesManager;
|
import org.librecms.assets.AssetTypesManager;
|
||||||
import org.librecms.contentsection.Asset;
|
import org.librecms.contentsection.Asset;
|
||||||
import org.librecms.contentsection.AssetManager;
|
import org.librecms.contentsection.AssetManager;
|
||||||
|
|
@ -63,6 +64,8 @@ import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
|
|
||||||
|
import static org.librecms.CmsConstants.MEDIA_LIST_PREFIX;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
|
@ -83,8 +86,6 @@ public class MediaStep extends AbstractMvcAuthoringStep {
|
||||||
*/
|
*/
|
||||||
static final String PATH_FRAGMENT = "media";
|
static final String PATH_FRAGMENT = "media";
|
||||||
|
|
||||||
protected static final String MEDIA_LIST_PREFIX = ".media-";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link AssetManager} instance of managing {@link Asset}s.
|
* {@link AssetManager} instance of managing {@link Asset}s.
|
||||||
*/
|
*/
|
||||||
|
|
@ -186,7 +187,11 @@ public class MediaStep extends AbstractMvcAuthoringStep {
|
||||||
getDocument()
|
getDocument()
|
||||||
.getAttachments()
|
.getAttachments()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(list -> list.getName().startsWith(MEDIA_LIST_PREFIX))
|
.filter(
|
||||||
|
list -> list.getName().startsWith(
|
||||||
|
CmsConstants.MEDIA_LIST_PREFIX
|
||||||
|
)
|
||||||
|
)
|
||||||
.map(this::buildMediaListDto)
|
.map(this::buildMediaListDto)
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.ui.contentsections.documents.media;
|
package org.librecms.ui.contentsections.documents.media;
|
||||||
|
|
||||||
|
import org.librecms.CmsConstants;
|
||||||
import org.librecms.contentsection.AttachmentList;
|
import org.librecms.contentsection.AttachmentList;
|
||||||
import org.librecms.contentsection.AttachmentListRepository;
|
import org.librecms.contentsection.AttachmentListRepository;
|
||||||
import org.librecms.contentsection.ContentItem;
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
|
@ -102,7 +103,10 @@ public class MediaStepService {
|
||||||
.getAttachments()
|
.getAttachments()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(
|
.filter(
|
||||||
list -> list.getName().startsWith(MediaStep.MEDIA_LIST_PREFIX))
|
list -> list.getName().startsWith(
|
||||||
|
CmsConstants.MEDIA_LIST_PREFIX
|
||||||
|
)
|
||||||
|
)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
final List<String> attachmentListsOrder = order
|
final List<String> attachmentListsOrder = order
|
||||||
.getMediaListsOrder();
|
.getMediaListsOrder();
|
||||||
|
|
@ -147,7 +151,7 @@ public class MediaStepService {
|
||||||
.stream()
|
.stream()
|
||||||
.filter(
|
.filter(
|
||||||
list -> list.getName().startsWith(
|
list -> list.getName().startsWith(
|
||||||
MediaStep.MEDIA_LIST_PREFIX
|
CmsConstants.MEDIA_LIST_PREFIX
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.filter(list -> attachmentsOrder.getKey().equals(list.getUuid()))
|
.filter(list -> attachmentsOrder.getKey().equals(list.getUuid()))
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@
|
||||||
class="form-control"
|
class="form-control"
|
||||||
id="property-key"
|
id="property-key"
|
||||||
name="propertyKey"
|
name="propertyKey"
|
||||||
pattern="^([a-zA-Z0-9-_]*)$"
|
pattern="^([a-zA-Z0-9-_\.]*)$"
|
||||||
required="true"
|
required="true"
|
||||||
type="text" />
|
type="text" />
|
||||||
<span class="form-text text-muted"
|
<span class="form-text text-muted"
|
||||||
|
|
|
||||||
|
|
@ -154,18 +154,21 @@
|
||||||
pattern="[\\w-.]*"
|
pattern="[\\w-.]*"
|
||||||
required="true"
|
required="true"
|
||||||
value="#{CategorySystemModel.selectedCategory.uniqueId}" />
|
value="#{CategorySystemModel.selectedCategory.uniqueId}" />
|
||||||
<bootstrap:formCheck label="#{CmsAdminMessages['contentsecton.categorysystems.category.properties.edit.dialog.enabled.label']}"
|
<bootstrap:formCheck checked="#{CategorySystemModel.selectedCategory.enabled ? 'checked' : ''}"
|
||||||
|
label="#{CmsAdminMessages['contentsecton.categorysystems.category.properties.edit.dialog.enabled.label']}"
|
||||||
inputId="isEnabled"
|
inputId="isEnabled"
|
||||||
name="isEnabled"
|
name="isEnabled"
|
||||||
value="#{CategorySystemModel.selectedCategory.enabled}" />
|
value="true" />
|
||||||
<bootstrap:formCheck label="#{CmsAdminMessages['contentsecton.categorysystems.category.properties.edit.dialog.visible.label']}"
|
<bootstrap:formCheck checked="#{CategorySystemModel.selectedCategory.visible ? 'checked' : ''}"
|
||||||
|
label="#{CmsAdminMessages['contentsecton.categorysystems.category.properties.edit.dialog.visible.label']}"
|
||||||
inputId="isvisible"
|
inputId="isvisible"
|
||||||
name="isVisible"
|
name="isVisible"
|
||||||
value="#{CategorySystemModel.selectedCategory.visible}" />
|
value="true" />
|
||||||
<bootstrap:formCheck label="#{CmsAdminMessages['contentsecton.categorysystems.category.properties.edit.dialog.abstract_category.label']}"
|
<bootstrap:formCheck checked="#{CategorySystemModel.selectedCategory.abstractCategory ? 'checked' : ''}"
|
||||||
|
label="#{CmsAdminMessages['contentsecton.categorysystems.category.properties.edit.dialog.abstract_category.label']}"
|
||||||
inputId="isAbstract"
|
inputId="isAbstract"
|
||||||
name="isAbstract"
|
name="isAbstract"
|
||||||
value="#{CategorySystemModel.selectedCategory.abstractCategory}" />
|
value="true" />
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button class="btn btn-danger"
|
<button class="btn btn-danger"
|
||||||
|
|
@ -451,23 +454,15 @@
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
#{CmsAdminMessages['contentsections.categorystems.category.objects.name']}
|
#{CmsAdminMessages['contentsections.categorystems.category.objects.name']}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
#{CmsAdminMessages['contentsections.categorystems.category.objects.title']}
|
#{CmsAdminMessages['contentsections.categorystems.category.objects.title']}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
#{CmsAdminMessages['contentsections.categorystems.category.objects.type']}
|
#{CmsAdminMessages['contentsections.categorystems.category.objects.type']}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
#{CmsAdminMessages['contentsections.categorystems.category.objects.index']}
|
#{CmsAdminMessages['contentsections.categorystems.category.objects.index']}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th colspan="3">
|
<th colspan="3">
|
||||||
#{CmsAdminMessages['contentsections.categorystems.category.objects.actions']}
|
#{CmsAdminMessages['contentsections.categorystems.category.objects.actions']}
|
||||||
</th>
|
</th>
|
||||||
|
|
@ -498,7 +493,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td class="actions-order-col">
|
<td class="actions-order-col">
|
||||||
<c:if test="#{object.objectOrder != 1}">
|
<c:if test="#{object.objectOrder != 1}">
|
||||||
<form action="#"
|
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/categorysystems/#{CategorySystemModel.selectedCategorySystem.context}/categories#{category.path}/@objects/#{object.objectId}/order"
|
||||||
method="post">
|
method="post">
|
||||||
<input name="direction"
|
<input name="direction"
|
||||||
value="DECREASE"
|
value="DECREASE"
|
||||||
|
|
@ -513,7 +508,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td class="actions-order-col">
|
<td class="actions-order-col">
|
||||||
<c:if test="#{object.objectOrder lt CategorySystemModel.selectedCategory.objects.size()}">
|
<c:if test="#{object.objectOrder lt CategorySystemModel.selectedCategory.objects.size()}">
|
||||||
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/categorysystems/#{CategorySystemModel.selectedCategorySystem.context}/@objects/#{object.objectId}/order"
|
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/categorysystems/#{CategorySystemModel.selectedCategorySystem.context}/categories#{category.path}/@objects/#{object.objectId}/order"
|
||||||
method="post">
|
method="post">
|
||||||
<input name="direction"
|
<input name="direction"
|
||||||
value="INCREASE"
|
value="INCREASE"
|
||||||
|
|
@ -529,18 +524,24 @@
|
||||||
<td class="actions-setindex-col">
|
<td class="actions-setindex-col">
|
||||||
<c:choose>
|
<c:choose>
|
||||||
<c:when test="#{object.indexObject}">
|
<c:when test="#{object.indexObject}">
|
||||||
<a class="btn btn-danger"
|
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/categorysystems/#{CategorySystemModel.selectedCategorySystem.context}/categories#{CategorySystemModel.selectedCategory.path}/@index-element/reset"
|
||||||
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/categorysystems/#{CategorySystemModel.selectedCategorySystem.context}/@index-element/#{object.objectUuid}">
|
method="post">
|
||||||
|
<button class="btn btn-danger"
|
||||||
|
type="submit">
|
||||||
<bootstrap:svgIcon icon="bookmark-x" />
|
<bootstrap:svgIcon icon="bookmark-x" />
|
||||||
<span>#{CmsAdminMessages['contentsections.categorystems.category.objects.index_object.reset']}</span>
|
<span>#{CmsAdminMessages['contentsections.categorystems.category.objects.index_object.reset']}</span>
|
||||||
</a>
|
</button>
|
||||||
|
</form>
|
||||||
</c:when>
|
</c:when>
|
||||||
<c:otherwise>
|
<c:otherwise>
|
||||||
<a class="btn btn-info"
|
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/categorysystems/#{CategorySystemModel.selectedCategorySystem.context}/categories#{CategorySystemModel.selectedCategory.path}/@index-element/#{object.objectUuid}"
|
||||||
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/categorysystems/#{CategorySystemModel.selectedCategorySystem.context}/@index-element/reset">
|
method="post">
|
||||||
|
<button class="btn btn-info"
|
||||||
|
type="submit">
|
||||||
<bootstrap:svgIcon icon="bookmark-star" />
|
<bootstrap:svgIcon icon="bookmark-star" />
|
||||||
<span>#{CmsAdminMessages['contentsections.categorystems.category.objects.index_object.set']}</span>
|
<span>#{CmsAdminMessages['contentsections.categorystems.category.objects.index_object.set']}</span>
|
||||||
</a>
|
</button>
|
||||||
|
</form>
|
||||||
</c:otherwise>
|
</c:otherwise>
|
||||||
</c:choose>
|
</c:choose>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
||||||
|
|
@ -999,7 +999,7 @@ pages.errors.primaryurl_null_or_empty=The primary URL of a page tree can't be nu
|
||||||
pages.errors.pages_instance_already_existing=There is already a page tree with the primary URL {1} for site {0}.
|
pages.errors.pages_instance_already_existing=There is already a page tree with the primary URL {1} for site {0}.
|
||||||
pages.errors.primaryurl_invalid=The primary URL "{0}" contains invalid characters. The primary URL of a page tree must only contain the letters a to z and A to Z, numbers, the dash ("-") and the underscore ("_").
|
pages.errors.primaryurl_invalid=The primary URL "{0}" contains invalid characters. The primary URL of a page tree must only contain the letters a to z and A to Z, numbers, the dash ("-") and the underscore ("_").
|
||||||
pages.page.details.properties.error.key_empty=The name/key of a property can't be null or blank.
|
pages.page.details.properties.error.key_empty=The name/key of a property can't be null or blank.
|
||||||
pages.page.details.properties.error.key_invalid=The name of a property must only contain the letters A to Z, a to z, numbers, the dash ("-") and the underscore ("_").
|
pages.page.details.properties.error.key_invalid=The name of a property must only contain the letters A to Z, a to z, numbers, the dash ("-"), the underscore ("_") and the dot (".").
|
||||||
pages.page.details.properties.error.value_empty=The value of a property must not be empty.
|
pages.page.details.properties.error.value_empty=The value of a property must not be empty.
|
||||||
pages.page.details.dialog.title=Page Details
|
pages.page.details.dialog.title=Page Details
|
||||||
pages.page.details.dialog.close=Close
|
pages.page.details.dialog.close=Close
|
||||||
|
|
|
||||||
|
|
@ -1000,7 +1000,7 @@ pages.errors.primaryurl_null_or_empty=Die prim\u00e4re URL eines Seitenbaumes da
|
||||||
pages.errors.pages_instance_already_existing=Es gibt bereits einen Seitenbaum mit der prim\u00e4ren URL {1} f\u00fcr die Site {0}.
|
pages.errors.pages_instance_already_existing=Es gibt bereits einen Seitenbaum mit der prim\u00e4ren URL {1} f\u00fcr die Site {0}.
|
||||||
pages.errors.primaryurl_invalid=Die prim\u00e4re URL "{0}" enth\u00e4lt ung\u00fcltige Zeichen. Die prim\u00e4re URL eines Seitenbaumes darf nur die Buchstaben a bis z, A bis Z, Ziffern, den Bindestrich ("-") und den Unterstrich ("_") enthalten.
|
pages.errors.primaryurl_invalid=Die prim\u00e4re URL "{0}" enth\u00e4lt ung\u00fcltige Zeichen. Die prim\u00e4re URL eines Seitenbaumes darf nur die Buchstaben a bis z, A bis Z, Ziffern, den Bindestrich ("-") und den Unterstrich ("_") enthalten.
|
||||||
pages.page.details.properties.error.key_empty=Der Name eines Eigenschaft darf nicht leer sein.
|
pages.page.details.properties.error.key_empty=Der Name eines Eigenschaft darf nicht leer sein.
|
||||||
pages.page.details.properties.error.key_invalid=Der Name einer Eigenschaft darf nur die Buchstaben A bis Z, a bis z, Ziffern, den Bindestrich ("-") und den Unterstrich ("_") enthalten.
|
pages.page.details.properties.error.key_invalid=Der Name einer Eigenschaft darf nur die Buchstaben A bis Z, a bis z, Ziffern, den Bindestrich ("-"), den Unterstrich ("_") und den Punkt (".") enthalten.
|
||||||
pages.page.details.properties.error.value_empty=Der Wert einer Eigenschaft darf nicht leer sein.
|
pages.page.details.properties.error.value_empty=Der Wert einer Eigenschaft darf nicht leer sein.
|
||||||
pages.page.details.dialog.title=Details Seite
|
pages.page.details.dialog.title=Details Seite
|
||||||
pages.page.details.dialog.close=Schlie\u00dfen
|
pages.page.details.dialog.close=Schlie\u00dfen
|
||||||
|
|
|
||||||
|
|
@ -83,8 +83,10 @@ import javax.persistence.Table;
|
||||||
+ "AND c.type = :type"),
|
+ "AND c.type = :type"),
|
||||||
@NamedQuery(
|
@NamedQuery(
|
||||||
name = "Categorization.findIndexObject",
|
name = "Categorization.findIndexObject",
|
||||||
query = "SELECT c.categorizedObject FROM Categorization c "
|
query = "SELECT c.categorizedObject "
|
||||||
+ "WHERE c.category = :category "
|
+ "FROM Categorization c "
|
||||||
|
+ "JOIN c.category a "
|
||||||
|
+ "WHERE a.uuid = :catuuid "
|
||||||
+ "AND c.indexObject = TRUE"),
|
+ "AND c.indexObject = TRUE"),
|
||||||
@NamedQuery(
|
@NamedQuery(
|
||||||
name = "Categorization.findIndexObjectCategorization",
|
name = "Categorization.findIndexObjectCategorization",
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@code CategoryManager} provides several helper methods for managing
|
* The {@code CategoryManager} provides several helper methods for managing
|
||||||
|
|
@ -58,7 +59,8 @@ public class CategoryManager implements Serializable {
|
||||||
private static final long serialVersionUID = -3354487547729008811L;
|
private static final long serialVersionUID = -3354487547729008811L;
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(
|
private static final Logger LOGGER = LogManager.getLogger(
|
||||||
CategoryManager.class);
|
CategoryManager.class
|
||||||
|
);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private CcmObjectRepository ccmObjectRepo;
|
private CcmObjectRepository ccmObjectRepo;
|
||||||
|
|
@ -982,16 +984,13 @@ public class CategoryManager implements Serializable {
|
||||||
*/
|
*/
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public List<CcmObject> getIndexObject(final Category category) {
|
public List<CcmObject> getIndexObject(final Category category) {
|
||||||
// if (hasIndexObject(category)) {
|
final long start = System.currentTimeMillis();
|
||||||
final TypedQuery<CcmObject> query = entityManager.createNamedQuery(
|
return category
|
||||||
"Categorization.findIndexObject", CcmObject.class);
|
.getObjects()
|
||||||
query.setParameter("category", category);
|
.stream()
|
||||||
|
.filter(Categorization::isIndexObject)
|
||||||
return query.getResultList();
|
.map(Categorization::getCategorizedObject)
|
||||||
// return Optional.of(query.getSingleResult());
|
.collect(Collectors.toList());
|
||||||
// } else {
|
|
||||||
// return Optional.empty();
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,8 @@ public abstract class AbstractEntityRepository<K, E> implements Serializable {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public EntityGraph<E> createEntityGraph(final String entityGraphName) {
|
public EntityGraph<E> createEntityGraph(final String entityGraphName) {
|
||||||
return (EntityGraph<E>) entityManager.createEntityGraph(
|
return (EntityGraph<E>) entityManager.createEntityGraph(
|
||||||
entityGraphName);
|
entityGraphName
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -153,16 +154,18 @@ public abstract class AbstractEntityRepository<K, E> implements Serializable {
|
||||||
*/
|
*/
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Optional<E> findById(final K entityId) {
|
public Optional<E> findById(final K entityId) {
|
||||||
|
|
||||||
Objects.requireNonNull(entityId);
|
Objects.requireNonNull(entityId);
|
||||||
|
|
||||||
return Optional.ofNullable(entityManager.find(getEntityClass(),
|
return Optional.ofNullable(
|
||||||
entityId));
|
entityManager.find(
|
||||||
|
getEntityClass(),
|
||||||
|
entityId
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Optional<E> findById(final K entityId, final String entityGraphName) {
|
public Optional<E> findById(final K entityId, final String entityGraphName) {
|
||||||
|
|
||||||
Objects.requireNonNull(entityId);
|
Objects.requireNonNull(entityId);
|
||||||
Objects.requireNonNull(entityGraphName);
|
Objects.requireNonNull(entityGraphName);
|
||||||
|
|
||||||
|
|
@ -175,15 +178,18 @@ public abstract class AbstractEntityRepository<K, E> implements Serializable {
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Optional<E> findById(final K entityId,
|
public Optional<E> findById(final K entityId,
|
||||||
final EntityGraph<E> entityGraph) {
|
final EntityGraph<E> entityGraph) {
|
||||||
|
|
||||||
Objects.requireNonNull(entityId);
|
Objects.requireNonNull(entityId);
|
||||||
Objects.requireNonNull(entityGraph);
|
Objects.requireNonNull(entityGraph);
|
||||||
|
|
||||||
final Map<String, Object> hints = new HashMap<>();
|
final Map<String, Object> hints = new HashMap<>();
|
||||||
hints.put(FETCH_GRAPH_HINT_KEY, entityGraph);
|
hints.put(FETCH_GRAPH_HINT_KEY, entityGraph);
|
||||||
return Optional.ofNullable(entityManager.find(getEntityClass(),
|
return Optional.ofNullable(
|
||||||
|
entityManager.find(
|
||||||
|
getEntityClass(),
|
||||||
entityId,
|
entityId,
|
||||||
hints));
|
hints
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -206,16 +212,18 @@ public abstract class AbstractEntityRepository<K, E> implements Serializable {
|
||||||
Objects.requireNonNull(entityId);
|
Objects.requireNonNull(entityId);
|
||||||
|
|
||||||
final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||||
final CriteriaQuery<E> criteriaQuery = builder
|
final CriteriaQuery<E> criteriaQuery = builder.createQuery(
|
||||||
.createQuery(getEntityClass());
|
getEntityClass()
|
||||||
|
);
|
||||||
final Root<E> from = criteriaQuery.from(getEntityClass());
|
final Root<E> from = criteriaQuery.from(getEntityClass());
|
||||||
criteriaQuery.from(getEntityClass());
|
criteriaQuery.from(getEntityClass());
|
||||||
for (final String fetchJoin : fetchJoins) {
|
for (final String fetchJoin : fetchJoins) {
|
||||||
from.fetch(fetchJoin);
|
from.fetch(fetchJoin);
|
||||||
}
|
}
|
||||||
|
|
||||||
criteriaQuery
|
criteriaQuery.where(
|
||||||
.where(builder.equal(from.get(getIdAttributeName()), entityId));
|
builder.equal(from.get(getIdAttributeName()), entityId)
|
||||||
|
);
|
||||||
|
|
||||||
final TypedQuery<E> query = entityManager.createQuery(criteriaQuery);
|
final TypedQuery<E> query = entityManager.createQuery(criteriaQuery);
|
||||||
try {
|
try {
|
||||||
|
|
@ -229,10 +237,15 @@ public abstract class AbstractEntityRepository<K, E> implements Serializable {
|
||||||
public E reload(final E entity, final String... fetchJoins) {
|
public E reload(final E entity, final String... fetchJoins) {
|
||||||
|
|
||||||
return findById(getIdOfEntity(entity), fetchJoins)
|
return findById(getIdOfEntity(entity), fetchJoins)
|
||||||
.orElseThrow(() -> new IllegalArgumentException(String
|
.orElseThrow(
|
||||||
.format("No Entity of type \"%s\" with ID %s in the database.",
|
() -> new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"No Entity of type \"%s\" with ID %s in the database.",
|
||||||
getEntityClass().getName(),
|
getEntityClass().getName(),
|
||||||
Objects.toString(getIdOfEntity(entity)))));
|
Objects.toString(getIdOfEntity(entity))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -273,7 +286,8 @@ public abstract class AbstractEntityRepository<K, E> implements Serializable {
|
||||||
final CriteriaBuilder criteriaBuilder = entityManager
|
final CriteriaBuilder criteriaBuilder = entityManager
|
||||||
.getCriteriaBuilder();
|
.getCriteriaBuilder();
|
||||||
final CriteriaQuery<E> criteriaQuery = criteriaBuilder.createQuery(
|
final CriteriaQuery<E> criteriaQuery = criteriaBuilder.createQuery(
|
||||||
getEntityClass());
|
getEntityClass()
|
||||||
|
);
|
||||||
final Root<E> root = criteriaQuery.from(getEntityClass());
|
final Root<E> root = criteriaQuery.from(getEntityClass());
|
||||||
return criteriaQuery.select(root);
|
return criteriaQuery.select(root);
|
||||||
}
|
}
|
||||||
|
|
@ -303,8 +317,7 @@ public abstract class AbstractEntityRepository<K, E> implements Serializable {
|
||||||
final String graphName) {
|
final String graphName) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
final EntityGraph<E> entityGraph = (EntityGraph< E>) entityManager
|
final EntityGraph<E> entityGraph = (EntityGraph< E>) entityManager
|
||||||
.getEntityGraph(
|
.getEntityGraph(graphName);
|
||||||
graphName);
|
|
||||||
return executeCriteriaQuery(criteriaQuery, entityGraph);
|
return executeCriteriaQuery(criteriaQuery, entityGraph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,7 +347,6 @@ public abstract class AbstractEntityRepository<K, E> implements Serializable {
|
||||||
*/
|
*/
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public void save(final E entity) {
|
public void save(final E entity) {
|
||||||
|
|
||||||
Objects.requireNonNull(entity, "Can't save null.");
|
Objects.requireNonNull(entity, "Can't save null.");
|
||||||
|
|
||||||
if (isNew(entity)) {
|
if (isNew(entity)) {
|
||||||
|
|
@ -363,12 +375,11 @@ public abstract class AbstractEntityRepository<K, E> implements Serializable {
|
||||||
*/
|
*/
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public void delete(final E entity) {
|
public void delete(final E entity) {
|
||||||
|
Objects.requireNonNull(
|
||||||
|
entity, "Can't delete a null entity."
|
||||||
|
);
|
||||||
|
|
||||||
Objects.requireNonNull(entity,
|
entityManager.remove(entity);
|
||||||
"Can't delete a null entity.");
|
|
||||||
|
|
||||||
//We need to make sure we use a none detached entity, therefore the merge
|
|
||||||
entityManager.remove(entityManager.merge(entity));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
import org.libreccm.core.CoreConstants;
|
import org.libreccm.core.CoreConstants;
|
||||||
|
import org.libreccm.l10n.GlobalizationHelper;
|
||||||
import org.libreccm.sites.Site;
|
import org.libreccm.sites.Site;
|
||||||
import org.libreccm.sites.SiteRepository;
|
import org.libreccm.sites.SiteRepository;
|
||||||
import org.libreccm.theming.ThemeInfo;
|
import org.libreccm.theming.ThemeInfo;
|
||||||
|
|
@ -51,6 +52,9 @@ public class ThemesMvc {
|
||||||
|
|
||||||
public static final String DEFAULT_THEME_PARAM = "--DEFAULT--";
|
public static final String DEFAULT_THEME_PARAM = "--DEFAULT--";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private GlobalizationHelper globalizationHelper;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Models models;
|
private Models models;
|
||||||
|
|
||||||
|
|
@ -146,6 +150,10 @@ public class ThemesMvc {
|
||||||
|
|
||||||
models.put("application", application);
|
models.put("application", application);
|
||||||
models.put("contextPath", servletContext.getContextPath());
|
models.put("contextPath", servletContext.getContextPath());
|
||||||
|
models.put(
|
||||||
|
"negotiatedLocale",
|
||||||
|
globalizationHelper.getNegotiatedLocale().toString()
|
||||||
|
);
|
||||||
models.put("themeName", themeInfo.getName());
|
models.put("themeName", themeInfo.getName());
|
||||||
models.put("themeVersion", themeInfo.getVersion());
|
models.put("themeVersion", themeInfo.getVersion());
|
||||||
models.put(
|
models.put(
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import * as fsPromises from "fs/promises";
|
||||||
import * as mime from "mime-types";
|
import * as mime from "mime-types";
|
||||||
import { fileTypeFromFile, FileTypeResult } from "file-type";
|
import { fileTypeFromFile, FileTypeResult } from "file-type";
|
||||||
|
|
||||||
|
const AMBIGOUS_FILE_TYPES = ["application/xml"];
|
||||||
|
|
||||||
console.log("Static Theme Builder");
|
console.log("Static Theme Builder");
|
||||||
|
|
||||||
if (process.argv.length < 3) {
|
if (process.argv.length < 3) {
|
||||||
|
|
@ -143,7 +145,10 @@ function mapFileTypeResultToMimeType(
|
||||||
fileTypeResult: FileTypeResult | undefined
|
fileTypeResult: FileTypeResult | undefined
|
||||||
): string {
|
): string {
|
||||||
if (fileTypeResult) {
|
if (fileTypeResult) {
|
||||||
if (fileTypeResult.mime) {
|
if (
|
||||||
|
fileTypeResult.mime &&
|
||||||
|
!AMBIGOUS_FILE_TYPES.includes(fileTypeResult.mime)
|
||||||
|
) {
|
||||||
return fileTypeResult.mime;
|
return fileTypeResult.mime;
|
||||||
} else {
|
} else {
|
||||||
const result = mime.lookup(name);
|
const result = mime.lookup(name);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue