MVC edit views for MultiPartArticle part II

pull/10/head
Jens Pelzetter 2021-12-15 20:41:07 +01:00
parent 7182696aba
commit 43943e1c46
8 changed files with 534 additions and 13 deletions

View File

@ -123,6 +123,11 @@
<artifactId>jsoup</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View File

@ -18,7 +18,6 @@
*/
package org.librecms.ui.contenttypes.article;
import com.arsdigita.kernel.KernelConfig;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

View File

@ -18,13 +18,23 @@
*/
package org.librecms.ui.contenttypes.mpa;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentItemRepository;
import org.librecms.contentsection.ContentSection;
import org.librecms.contenttypes.MultiPartArticle;
import org.librecms.contenttypes.MultiPartArticleSection;
import org.librecms.contenttypes.MultiPartArticleSectionRepository;
import org.librecms.ui.contentsections.ContentSectionsUi;
import org.librecms.ui.contentsections.documents.MvcAuthoringSteps;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@ -39,6 +49,15 @@ import javax.ws.rs.core.Response;
@Path(MvcAuthoringSteps.PATH_PREFIX + "mpa-sections-service")
public class MpaSectionStepService {
@Inject
private ContentItemRepository itemRepo;
@Inject
private MultiPartArticleSectionRepository sectionRepo;
@Inject
private ContentSectionsUi sectionsUi;
@POST
@Path("/save-order")
@Consumes(MediaType.APPLICATION_JSON)
@ -50,8 +69,80 @@ public class MpaSectionStepService {
final String documentPath,
final List<String> sectionsOrder
) {
// ToDo
throw new UnsupportedOperationException();
final ContentSection contentSection = sectionsUi
.findContentSection(sectionIdentifier)
.orElseThrow(
() -> new NotFoundException(
String.format(
"No content identifed by %s found.",
sectionIdentifier
)
)
);
final ContentItem document = itemRepo
.findByPath(contentSection, documentPath)
.orElseThrow(
() -> new NotFoundException(
String.format(
"No document for path %s in section %s.",
documentPath,
contentSection.getLabel()
)
)
);
if ((document instanceof MultiPartArticle)) {
throw new BadRequestException(
String.format(
"Document %s is not a %s.",
documentPath,
MultiPartArticle.class.getSimpleName()
)
);
}
final MultiPartArticle mpa = (MultiPartArticle) document;
final List<MultiPartArticleSection> sections = mpa.getSections();
if (sectionsOrder.size() != sections.size()) {
throw new BadRequestException(
String.format(
"Number of sections of the MultiPartArticle %s does "
+ "not match the number of values in the oder "
+ "list. Number of sections: %d, number of values in "
+ "the sections order list: %d",
documentPath,
sections.size(),
sectionsOrder.size()
)
);
}
for (int i = 0; i < sectionsOrder.size(); i++) {
final String sectionIdParam = sectionsOrder.get(i);
final long sectionId = Long.parseLong(sectionIdParam);
final MultiPartArticleSection section = sections
.stream()
.filter(sec -> sec.getSectionId() == sectionId)
.findAny()
.orElseThrow(
() -> new BadRequestException(
String.format(
"sectionsOrder has an entry for section with "
+ "ID %d, but there is not section with that "
+ "ID.",
sectionId
)
)
);
section.setRank(i);
sectionRepo.save(section);
}
return Response.ok().build();
}
}

View File

@ -18,6 +18,10 @@
*/
package org.librecms.ui.contenttypes.mpa;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
@ -31,6 +35,8 @@ public class MpaSectionsStepModel {
private boolean canEdit;
private List<MpaSectionsTableRow> rows;
public boolean getCanEdit() {
return canEdit;
}
@ -39,4 +45,12 @@ public class MpaSectionsStepModel {
this.canEdit = canEdit;
}
public List<MpaSectionsTableRow> getRows() {
return Collections.unmodifiableList(rows);
}
protected void setRows(final List<MpaSectionsTableRow> rows) {
this.rows = new ArrayList<>(rows);
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2021 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.ui.contenttypes.mpa;
import java.util.Comparator;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class MpaSectionsTableRow implements Comparable<MpaSectionsTableRow> {
private long sectionId;
private String title;
private int rank;
private boolean pageBreak;
private String textPreview;
public long getSectionId() {
return sectionId;
}
protected void setSectionId(final long sectionId) {
this.sectionId = sectionId;
}
public String getTitle() {
return title;
}
protected void setTitle(final String title) {
this.title = title;
}
public int getRank() {
return rank;
}
protected void setRank(final int rank) {
this.rank = rank;
}
public boolean isPageBreak() {
return pageBreak;
}
protected void setPageBreak(final boolean pageBreak) {
this.pageBreak = pageBreak;
}
public String getTextPreview() {
return textPreview;
}
protected void setTextPreview(final String textPreview) {
this.textPreview = textPreview;
}
@Override
public int compareTo(final MpaSectionsTableRow other) {
return Comparator
.comparing(MpaSectionsTableRow::getRank)
.thenComparing(
Comparator.comparing(MpaSectionsTableRow::getTitle)
)
.compare(this, other);
}
}

View File

@ -35,7 +35,6 @@ import java.util.Optional;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.mvc.Models;
import javax.transaction.Transactional;
/**

View File

@ -18,7 +18,11 @@
*/
package org.librecms.ui.contenttypes.mpa;
import org.apache.commons.lang3.StringUtils;
import org.libreccm.l10n.GlobalizationHelper;
import org.librecms.contenttypes.MultiPartArticle;
import org.librecms.contenttypes.MultiPartArticleSection;
import org.librecms.contenttypes.MultiPartArticleSectionManager;
import org.librecms.ui.contentsections.ContentSectionNotFoundException;
import org.librecms.ui.contentsections.ItemPermissionChecker;
import org.librecms.ui.contentsections.documents.AbstractMvcAuthoringStep;
@ -27,10 +31,18 @@ import org.librecms.ui.contentsections.documents.DocumentUi;
import org.librecms.ui.contentsections.documents.MvcAuthoringStepDef;
import org.librecms.ui.contentsections.documents.MvcAuthoringSteps;
import java.util.Comparator;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.mvc.Controller;
import javax.mvc.Models;
import javax.transaction.Transactional;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
@ -59,9 +71,18 @@ public class MvcMpaSectionsStep extends AbstractMvcAuthoringStep {
@Inject
private DocumentUi documentUi;
@Inject
private GlobalizationHelper globalizationHelper;
@Inject
private ItemPermissionChecker itemPermissionChecker;
@Inject
private MultiPartArticleSectionManager sectionManager;
@Inject
private Models models;
@Inject
private MpaSectionsStepModel mpaSectionsStepModel;
@ -88,6 +109,15 @@ public class MvcMpaSectionsStep extends AbstractMvcAuthoringStep {
}
if (itemPermissionChecker.canEditItem(getMpa())) {
mpaSectionsStepModel.setRows(
getMpa()
.getSections()
.stream()
.map(this::buildMpaSectionsTableRow)
.sorted()
.collect(Collectors.toList())
);
return "org/librecms/ui/contenttypes/mpa/mpa-sections.xhtml";
} else {
return documentUi.showAccessDenied(
@ -99,34 +129,293 @@ public class MvcMpaSectionsStep extends AbstractMvcAuthoringStep {
}
@POST
@Path("/add")
@Path("/@add")
@Transactional(Transactional.TxType.REQUIRED)
public String addSection(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@FormParam("initialLocal")
@FormParam("initialLocal") @DefaultValue("")
final String initialLocaleParam,
@FormParam("title")
@FormParam("title") @DefaultValue("")
final String title,
@FormParam("text")
@FormParam("text") @DefaultValue("")
final String text
) {
try {
init();
} catch (ContentSectionNotFoundException ex) {
return ex.showErrorMessage();
} catch (DocumentNotFoundException ex) {
return ex.showErrorMessage();
}
if (itemPermissionChecker.canEditItem(getMpa())) {
if (initialLocaleParam.isBlank()) {
models.put("initialLocaleMissing", true);
models.put("title", title);
models.put("text", text);
return showStep(sectionIdentifier, documentPath);
}
if (title.isBlank()) {
models.put("titleMissing", true);
models.put("initialLocale", initialLocaleParam);
models.put("text", text);
return showStep(sectionIdentifier, documentPath);
}
final MultiPartArticleSection section
= new MultiPartArticleSection();
section.setPageBreak(false);
section.setRank(
getMpa()
.getSections()
.stream()
.map(MultiPartArticleSection::getRank)
.max(Comparator.naturalOrder())
.orElse(0) + 1
);
final Locale initialLocale = new Locale(initialLocaleParam);
section.getText().addValue(initialLocale, text);
section.getTitle().addValue(initialLocale, title);
sectionManager.addSectionToMultiPartArticle(section, getMpa());
return buildRedirectPathForStep();
} else {
return documentUi.showAccessDenied(
getContentSection(),
getMpa(),
mpaMessageBundle.getMessage("mpa.edit.denied")
);
}
}
@POST
@Path("/@remove/{sectionId}")
@Transactional(Transactional.TxType.REQUIRED)
public String removeSection(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@PathParam("sectionId")
final String sectionIdParam
) {
try {
init();
} catch (ContentSectionNotFoundException ex) {
return ex.showErrorMessage();
} catch (DocumentNotFoundException ex) {
return ex.showErrorMessage();
}
if (itemPermissionChecker.canEditItem(getMpa())) {
if (!sectionIdParam.matches("[0-9]*")) {
models.put("invalidSectionId", true);
return showStep(sectionIdentifier, documentPath);
}
final long sectionId = Long.parseLong(sectionIdParam);
final Optional<MultiPartArticleSection> result
= getMpa()
.getSections()
.stream()
.filter(section -> section.getSectionId() == sectionId)
.findAny();
if (!result.isPresent()) {
models.put("sectionNotFound", true);
return showStep(sectionIdentifier, documentPath);
}
final MultiPartArticleSection sectionToRemove = result.get();
sectionManager.removeSectionFromMultiPartArticle(
sectionToRemove, getMpa()
);
return buildRedirectPathForStep();
} else {
return documentUi.showAccessDenied(
getContentSection(),
getMpa(),
mpaMessageBundle.getMessage("mpa.edit.denied")
);
}
}
@POST
@Path("/{sectionId}")
@Transactional(Transactional.TxType.REQUIRED)
public String showSection(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@PathParam("sectionId")
final String sectionIdParam
) {
// ToDo
throw new UnsupportedOperationException();
}
@POST
@Path("/remove/{sectionId}")
@Path("/{sectionId}/title/@add")
@Transactional(Transactional.TxType.REQUIRED)
public String removeSection(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
public String addTitleValue(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@PathParam("sectionId")
final String sectionIdParam
final String sectionIdParam,
@FormParam("locale")
final String localeParam
) {
// ToDo
throw new UnsupportedOperationException();
}
@GET
@Path("/{sectionId}/title/@edit/{locale}")
@Transactional(Transactional.TxType.REQUIRED)
public String editTitleValue(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@PathParam("sectionId")
final String sectionIdParam,
@PathParam("locale")
final String localeParam
) {
// ToDo
throw new UnsupportedOperationException();
}
@POST
@Path("/{sectionId}/title/@edit/{locale}")
@Transactional(Transactional.TxType.REQUIRED)
public String editTitleValue(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@PathParam("sectionId")
final String sectionIdParam,
@PathParam("locale")
final String localeParam,
@FormParam("value")
final String value
) {
// ToDo
throw new UnsupportedOperationException();
}
@POST
@Path("/{sectionId}/title/@remove")
@Transactional(Transactional.TxType.REQUIRED)
public String removeTitleValue(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@PathParam("sectionId")
final String sectionIdParam,
@FormParam("locale")
final String localeParam
) {
// ToDo
throw new UnsupportedOperationException();
}
@POST
@Path("/{sectionId}/text/@add")
@Transactional(Transactional.TxType.REQUIRED)
public String addTextValue(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@PathParam("sectionId")
final String sectionIdParam,
@FormParam("locale")
final String localeParam
) {
// ToDo
throw new UnsupportedOperationException();
}
@GET
@Path("/{sectionId}/text/@edit/{locale}")
@Transactional(Transactional.TxType.REQUIRED)
public String editTextValue(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@PathParam("sectionId")
final String sectionIdParam,
@PathParam("locale")
final String localeParam
) {
// ToDo
throw new UnsupportedOperationException();
}
@POST
@Path("/{sectionId}/text/@edit/{locale}")
@Transactional(Transactional.TxType.REQUIRED)
public String editTextValue(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@PathParam("sectionId")
final String sectionIdParam,
@PathParam("locale")
final String localeParam,
@FormParam("value")
final String value
) {
// ToDo
throw new UnsupportedOperationException();
}
@POST
@Path("/{sectionId}/text/@remove")
@Transactional(Transactional.TxType.REQUIRED)
public String removeTextValue(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@PathParam("sectionId")
final String sectionIdParam,
@FormParam("locale")
final String localeParam
) {
// ToDo
throw new UnsupportedOperationException();
}
@POST
@Path("/{sectionId}/pagebreak")
@Transactional(Transactional.TxType.REQUIRED)
public String setPageBreak(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@PathParam("sectionId")
final String sectionIdParam,
@FormParam("pageBreak") final String pageBreakParam
) {
// ToDo
throw new UnsupportedOperationException();
@ -149,4 +438,34 @@ public class MvcMpaSectionsStep extends AbstractMvcAuthoringStep {
return (MultiPartArticle) getDocument();
}
private MpaSectionsTableRow buildMpaSectionsTableRow(
final MultiPartArticleSection section
) {
final MpaSectionsTableRow row = new MpaSectionsTableRow();
row.setPageBreak(section.isPageBreak());
row.setRank(section.getRank());
row.setSectionId(section.getSectionId());
final String text = Objects.requireNonNullElse(
globalizationHelper.getValueFromLocalizedString(section.getText()),
""
);
if (text.length() <= 100) {
row.setTextPreview(text);
} else {
row.setTextPreview(
String.format(
"%s...",
StringUtils.truncate(text, 97)
)
);
}
row.setTitle(
globalizationHelper.getValueFromLocalizedString(
section.getText()
)
);
return row;
}
}

View File

@ -708,6 +708,11 @@
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>