Some bugfixes

pull/10/head
Jens Pelzetter 2021-12-21 20:55:12 +01:00
parent 4ef2b9ac8a
commit 6f026f99a7
13 changed files with 251 additions and 72 deletions

View File

@ -55,8 +55,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
@ -736,6 +734,74 @@ public class DocumentFolderController {
);
}
/**
* Deletes an empty folder.
*
* @param sectionIdentifier The identifier of the content section
* @param folderPath The path of the folder.
*
* @return A redirect to the parent folder.
*/
@POST
@Path("/@delete/{folderPath:(.+)?}")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String deleteFolder(
@PathParam("sectionIdentifier") final String sectionIdentifier,
@PathParam("folderPath") final String folderPath
) {
final Optional<ContentSection> sectionResult = sectionsUi
.findContentSection(sectionIdentifier);
if (!sectionResult.isPresent()) {
return sectionsUi.showContentSectionNotFound(sectionIdentifier);
}
final ContentSection section = sectionResult.get();
if (!itemPermissionChecker.canEditItems(section)) {
return sectionsUi.showAccessDenied(
"sectionidentifier", sectionIdentifier
);
}
final Folder folder;
final Optional<Folder> folderResult = folderRepo
.findByPath(
section,
folderPath,
FolderType.DOCUMENTS_FOLDER
);
if (folderResult.isPresent()) {
folder = folderResult.get();
documentFolderModel.setBreadcrumbs(buildBreadcrumbs(folderPath));
} else {
return showDocumentFolderNotFound(section, folderPath);
}
if (!itemPermissionChecker.canDeleteItems(folder)) {
return sectionsUi.showAccessDenied(
"sectionidentifier", sectionIdentifier,
"folderPath", folderPath
);
}
final String parentFolderPath = Optional
.ofNullable(folder.getParentFolder())
.map(folderManager::getFolderPath)
.orElse("");
if (folderManager.folderIsDeletable(folder)
== FolderManager.FolderIsDeletable.YES) {
folderManager.deleteFolder(folder);
}
return String.format(
"redirect:/%s/documentfolders/%s",
sectionIdentifier,
parentFolderPath
);
}
/**
* A helper method for building the breadcrumb trail of a folder.
*
@ -799,11 +865,11 @@ public class DocumentFolderController {
row.setFolderPath(
folderManager
.getFolderPath(folder)
// .substring(
// folderManager
// .getFolderPath(section.getRootDocumentsFolder())
// .length()
// )
// .substring(
// folderManager
// .getFolderPath(section.getRootDocumentsFolder())
// .length()
// )
);
row.setLanguages(Collections.emptySortedSet());
row.setLastEditPublished(false);

View File

@ -25,6 +25,8 @@ import org.librecms.ui.contentsections.documents.relatedinfo.RelatedInfoStepServ
import org.librecms.ui.contenttypes.article.MvcArticlePropertiesStep;
import org.librecms.ui.contenttypes.article.MvcArticleTextBodyStep;
import org.librecms.ui.contenttypes.article.MvcArticleTextBodyStepResources;
import org.librecms.ui.contenttypes.mpa.MvcMpaPropertiesStep;
import org.librecms.ui.contenttypes.mpa.MvcMpaSectionsStep;
import java.util.Set;
@ -46,7 +48,9 @@ public class CmsMvcAuthoringSteps implements MvcAuthoringSteps {
PublishStep.class,
RelatedInfoStep.class,
MvcArticlePropertiesStep.class,
MvcArticleTextBodyStep.class
MvcArticleTextBodyStep.class,
MvcMpaPropertiesStep.class,
MvcMpaSectionsStep.class
);
}

View File

@ -26,6 +26,7 @@ import org.librecms.contentsection.ContentItemManager;
import org.librecms.contentsection.ContentItemRepository;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.Folder;
import org.librecms.contentsection.FolderManager;
import org.librecms.contentsection.FolderRepository;
import org.librecms.contentsection.FolderType;
import org.librecms.contentsection.privileges.ItemPrivileges;
@ -99,6 +100,9 @@ public class DocumentController {
@Inject
private DocumentUi documentUi;
@Inject
private FolderManager folderManager;
/**
* {@link FolderRepository} instance for retrieving folders.
*/
@ -766,6 +770,57 @@ public class DocumentController {
);
}
/**
* Deletes a document.
*
* @param sectionIdentifier
* @param documentPath
*
* @return A redirect to the folder of the document.
*/
@POST
@Path("/{documentPath:(.+)?}/@delete")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String deleteDocument(
@PathParam("sectionIdentifier") final String sectionIdentifier,
@PathParam("documentPath") final String documentPath
) {
final Optional<ContentSection> sectionResult = sectionsUi
.findContentSection(sectionIdentifier);
if (!sectionResult.isPresent()) {
return sectionsUi.showContentSectionNotFound(sectionIdentifier);
}
final ContentSection section = sectionResult.get();
final Optional<ContentItem> itemResult = itemRepo
.findByPath(section, documentPath);
if (!itemResult.isPresent()) {
return documentUi.showDocumentNotFound(section, documentPath);
}
final ContentItem item = itemResult.get();
if (!permissionChecker.isPermitted(ItemPrivileges.DELETE, item)) {
return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifier,
"documentPath", documentPath
);
}
final String folderPath = itemManager
.getItemFolder(item)
.map(folderManager::getFolderPath)
.orElse("");
if (!itemManager.isLive(item)) {
itemRepo.delete(item);
}
return String.format(
"redirect:/%s/documentfolders/%s",
sectionIdentifier,
folderPath
);
}
/**
* Helper method for reading the authoring steps for the current content
* item.
@ -814,7 +869,7 @@ public class DocumentController {
.replace(
String.format(
"/{%s}",
MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM
MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM
),
itemManager.getItemPath(item)
);
@ -905,7 +960,7 @@ public class DocumentController {
* Helper method for showing the "document type not available" page if the
* requested document type is not available for the current content section.
*
* @param section The content section.
* @param section The content section.
* @param documentType The folder path.
*
* @return The template of the "document type not found" page.

View File

@ -63,4 +63,7 @@ public class MpaSectionsStepModel {
this.sections = new ArrayList<>(sections);
}
public boolean getSectionsEmpty() {
return sections.isEmpty();
}
}

View File

@ -382,11 +382,33 @@
</td>
<td>
<c:if test="#{row.deletable}">
<button class="btn btn-danger"
title="#{CmsAdminMessages['contentsection.documentfolder.actions.delete.button.label']}">
<bootstrap:svgIcon icon="x-circle" />
<span class="sr-only">#{CmsAdminMessages['contentsection.documentfolder.actions.delete.button.label']}</span>
</button>
<c:choose>
<c:when test="#{row.folder}">
<libreccm:deleteDialog
actionTarget="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documentfolders/@delete/#{row.folderPath}"
buttonLabelClass="sr-only"
buttonText="#{CmsAdminMessages['contentsection.documentfolder.actions.delete.button.label']}"
cancelLabel="#{CmsAdminMessages['contentsection.documentfolder.actions.delete.cancel']}"
confirmLabel="#{CmsAdminMessages['contentsection.documentfolder.actions.delete.confirm']}"
dialogId="delete-folder-#{row.name}"
dialogTitle="#{CmsAdminMessages['contentsection.documentfolder.actions.delete.dialog.title']}"
message="#{CmsAdminMessages.getMessage('contentsection.documentfolder.actions.delete.dialog.message', [row.folderPath])}"
/>
</c:when>
<c:otherwise>
<libreccm:deleteDialog
actionTarget="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{DocumentFolderModel.pathWithTrailingSlash}#{row.name}/@delete"
buttonLabelClass="sr-only"
buttonText="#{CmsAdminMessages['contentsection.documentfolder.actions.delete_item.button.label']}"
cancelLabel="#{CmsAdminMessages['contentsection.documentfolder.actions.delete_item.cancel']}"
confirmLabel="#{CmsAdminMessages['contentsection.documentfolder.actions.delete_item.confirm']}"
dialogId="delete-folder-#{row.name}"
dialogTitle="#{CmsAdminMessages['contentsection.documentfolder.actions.delete_item.dialog.title']}"
message="#{CmsAdminMessages.getMessage('contentsection.documentfolder.actions.delete_item.dialog.message', [row.folderPath, row.name])}"
/>
</c:otherwise>
</c:choose>
</c:if>
</td>
</tr>

View File

@ -11,7 +11,7 @@
value="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@mpa-sections" />
<ui:define name="authoringStep">
<h2>#{CmsMpaMessageBundle.getMessage('sectionsstep.header', CmsMpaSectionsStep.articleTitle)}</h2>
<h2>#{CmsMpaMessageBundle.getMessage('sectionsstep.header', [CmsMpaSectionsStep.articleTitle])}</h2>
<c:if test="#{CmsMpaSectionsStep.canEdit}">
<div class="text-right">
@ -95,60 +95,69 @@
</div>
</div>
</c:if>
<table>
<thead>
<tr>
<th>#{CmsMpaMessageBundle['sectionsstep.sections.section.title']}</th>
<th>#{CmsMpaMessageBundle['sectionsstep.sections.text']}</th>
<th>#{CmsMpaMessageBundle['sectionsstep.sections.pagebreak']}</th>
<th>#{CmsMpaMessageBundle['sectionsstep.sections.actions']}</th>
</tr>
</thead>
<tbody>
<c:forEach items="#{CmsMpaSectionsStep.sections}"
var="section">
<tr id="mpa-section-#{section.sectionId}">
<td>
<a href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@mpa-sections/#{section.sectionId}">
#{section.title}
</a>
</td>
<td>#{section.textPreview}</td>
<td>
<c:choose>
<c:when test="#{section.pageBreak}">
<bootstrap:svgIcon icon="check2-square"
iconClass="text-success" />
<span class="sr-only">#{CmsMpaMessageBundle['sectionsstep.sections.section.pagebreak.yes']}</span>
</c:when>
<c:otherwise>
<span class="sr-only">#{CmsMpaMessageBundle['sectionsstep.sections.section.pagebreak.no']}</span>
<bootstrap:svgIcon icon="check" />
</c:otherwise>
</c:choose>
</td>
<td>
<a class="btn btn-primary"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@mpa-sections/#{section.sectionId}">
<bootstrap:svgIcon icon="eye" />
<span class="sr-only">#{CmsMpaMessageBundle['sectionsstep.sections.section.show_details']}</span>
</a>
<c:if test="#{CmsMpaSectionsStep.canEdit}">
<libreccm:deleteDialog
actionTarget="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@mpa-sections/#{section.sectionId}/@remove"
buttonText="#{CmsMpaMessageBundle['sectionsstep.sections.section.remove.label']}"
cancelLabel="#{CmsMpaMessageBundle['sectionsstep.sections.section.remove.dialog.cancel']}"
confirmLabel="#{CmsMpaMessageBundle['sectionsstep.sections.section.remove.dialog.confirm']}"
dialogId="remove-section-dialog-#{section.sectionId}"
dialogTitle="#{CmsMpaMessageBundle['sectionsstep.sections.section.remove.dialog.title']}"
message="#{CmsMpaMessageBundle['sectionsstep.sections.section.remove.dialog.message']}"
/>
</c:if>
</td>
</tr>
</c:forEach>
</tbody>
</table>
<c:choose>
<c:when test="#{CmsMpaSectionsStep.sectionsEmpty}">
<p>
#{CmsMpaMessageBundle['sectionsstep.sections.empty']}
</p>
</c:when>
<c:otherwise>
<table>
<thead>
<tr>
<th>#{CmsMpaMessageBundle['sectionsstep.sections.section.title']}</th>
<th>#{CmsMpaMessageBundle['sectionsstep.sections.text']}</th>
<th>#{CmsMpaMessageBundle['sectionsstep.sections.pagebreak']}</th>
<th>#{CmsMpaMessageBundle['sectionsstep.sections.actions']}</th>
</tr>
</thead>
<tbody>
<c:forEach items="#{CmsMpaSectionsStep.sections}"
var="section">
<tr id="mpa-section-#{section.sectionId}">
<td>
<a href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@mpa-sections/#{section.sectionId}">
#{section.title}
</a>
</td>
<td>#{section.textPreview}</td>
<td>
<c:choose>
<c:when test="#{section.pageBreak}">
<bootstrap:svgIcon icon="check2-square"
iconClass="text-success" />
<span class="sr-only">#{CmsMpaMessageBundle['sectionsstep.sections.section.pagebreak.yes']}</span>
</c:when>
<c:otherwise>
<span class="sr-only">#{CmsMpaMessageBundle['sectionsstep.sections.section.pagebreak.no']}</span>
<bootstrap:svgIcon icon="check" />
</c:otherwise>
</c:choose>
</td>
<td>
<a class="btn btn-primary"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@mpa-sections/#{section.sectionId}">
<bootstrap:svgIcon icon="eye" />
<span class="sr-only">#{CmsMpaMessageBundle['sectionsstep.sections.section.show_details']}</span>
</a>
<c:if test="#{CmsMpaSectionsStep.canEdit}">
<libreccm:deleteDialog
actionTarget="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@mpa-sections/#{section.sectionId}/@remove"
buttonText="#{CmsMpaMessageBundle['sectionsstep.sections.section.remove.label']}"
cancelLabel="#{CmsMpaMessageBundle['sectionsstep.sections.section.remove.dialog.cancel']}"
confirmLabel="#{CmsMpaMessageBundle['sectionsstep.sections.section.remove.dialog.confirm']}"
dialogId="remove-section-dialog-#{section.sectionId}"
dialogTitle="#{CmsMpaMessageBundle['sectionsstep.sections.section.remove.dialog.title']}"
message="#{CmsMpaMessageBundle['sectionsstep.sections.section.remove.dialog.message']}"
/>
</c:if>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</c:otherwise>
</c:choose>
</ui:define>

View File

@ -1014,3 +1014,12 @@ contentsection.document.authoring.workflow.none=No workflow assigned
contentsection.document.authoring.workflow.change_workflow.title=Assign workflow
contentsection.document.authoring.workflow.change_workflow.submit=Assign workflow
contentsection.document.authoring.workflow.change_workflow.close=Cancel
contentsection.documentfolder.actions.delete.cancel=Cancel
contentsection.documentfolder.actions.delete.confirm=Delete folder
contentsection.documentfolder.actions.delete.dialog.title=Confirm deletion of folder
contentsection.documentfolder.actions.delete.dialog.message=Are you sure to delete the folder {0}?
contentsection.documentfolder.actions.delete_item.button.label=Delete document
contentsection.documentfolder.actions.delete_item.cancel=Cancel
contentsection.documentfolder.actions.delete_item.confirm=Delete document
contentsection.documentfolder.actions.delete_item.dialog.title=Confirm deletation of document
contentsection.documentfolder.actions.delete_item.dialog.message=Are you sure to delete the document {0}/{1}?

View File

@ -1015,3 +1015,12 @@ contentsection.document.authoring.workflow.none=Kein Arbeitsablauf zugewiesen
contentsection.document.authoring.workflow.change_workflow.title=Arbeitsablauf zuweisen
contentsection.document.authoring.workflow.change_workflow.submit=Arbeitsablauf zuweisen
contentsection.document.authoring.workflow.change_workflow.close=Abbrechen
contentsection.documentfolder.actions.delete.cancel=Abbrechen
contentsection.documentfolder.actions.delete.confirm=Ordner l\u00f6schen
contentsection.documentfolder.actions.delete.dialog.title=L\u00f6schen des Ordners best\u00e4tigen
contentsection.documentfolder.actions.delete.dialog.message=Are you sure to delete the folder {0}?
contentsection.documentfolder.actions.delete_item.button.label=Dokument l\u00f6schen
contentsection.documentfolder.actions.delete_item.cancel=Abbrechen
contentsection.documentfolder.actions.delete_item.confirm=Dokument l\u00f6schen
contentsection.documentfolder.actions.delete_item.dialog.title=L\u00f6schen des Dokumentes best\u00e4tigen
contentsection.documentfolder.actions.delete_item.dialog.message=Sind Sie sicher, dass Sie das Dokument {0}/{1} l\u00f6schen wollen?

View File

@ -90,7 +90,7 @@ textstep.languages.th.language=Language
textstep.languages.th.actions=Actions
textstep.languages.none=No texts available
textstep.header.edit=Edit text for locale {0}
textstep.header.view=Text for locale {0}
textstep.header.view=Text of Article {0} for locale {1}
textstep.back=Back to available languages
text.editor.add_variant=Add language
text.editor.add.locale.help=The language of the new variant.

View File

@ -90,7 +90,7 @@ textstep.languages.th.language=Sprache
textstep.languages.th.actions=Aktionen
textstep.languages.none=Keine Texte vorhandenen
textstep.header.edit=Text f\u00fcr Sprache {0} bearbeiten
textstep.header.view=Text f\u00fcr Sprache {0}
textstep.header.view=Text des Artikels {0} f\u00fcr Sprache {1}
textstep.back=Zur\u00fcck zur Liste der verf\u00fcgbaren Sprachen
text.editor.add_variant=Sprache hinzuf\u00fcgen
text.editor.add.locale.help=Die Sprache der neuen Variante.

View File

@ -113,3 +113,4 @@ sectionstep.textstep.back=Back
sectionstep.textstep.header.edit=Edit text for locale {2} of section {1} of multipart article {0}
sectionstep.textstep.text.editor.header=Text
authoringsteps.sections.label=Sections
sectionsstep.sections.empty=This multipart article has no sections yet.

View File

@ -113,3 +113,4 @@ sectionstep.textstep.back=Zur\u00fcck
sectionstep.textstep.header.edit=Text f\u00fcr Sprache {2} des Abschnitts {1} des mehrteiligen Artikels {0} bearbeiten
sectionstep.textstep.text.editor.header=Text
authoringsteps.sections.label=Abschnitte
sectionsstep.sections.empty=Diese mehrteilige Artikel hat noch keine Abschnitte.