Setting target for related link.

pull/10/head
Jens Pelzetter 2021-07-26 21:18:04 +02:00
parent c8f36b9099
commit 16bdc50f0e
11 changed files with 230 additions and 29 deletions

View File

@ -82,7 +82,7 @@ import java.util.Properties;
descBundle = CmsConstants.CONTENT_SECTION_DESC_BUNDLE, descBundle = CmsConstants.CONTENT_SECTION_DESC_BUNDLE,
creator = ContentSectionCreator.class, creator = ContentSectionCreator.class,
servletPath = "/templates/servlet/content-section", servletPath = "/templates/servlet/content-section",
applicationController = ContentSectionApplicationController.class applicationController = ContentSectionApplicationController.class
), ),
@ApplicationType( @ApplicationType(
name = "org.librecms.pages.Pages", name = "org.librecms.pages.Pages",

View File

@ -152,6 +152,8 @@ public class ContentItems {
} else { } else {
result.put("place", ""); result.put("place", "");
} }
result.put("uuid", item.getUuid());
return result; return result;
} }

View File

@ -26,6 +26,7 @@ import org.libreccm.l10n.LocalizedTextsUtil;
import org.libreccm.security.PermissionChecker; import org.libreccm.security.PermissionChecker;
import org.libreccm.ui.BaseUrl; import org.libreccm.ui.BaseUrl;
import org.librecms.assets.AssetTypesManager; import org.librecms.assets.AssetTypesManager;
import org.librecms.assets.Bookmark;
import org.librecms.assets.RelatedLink; import org.librecms.assets.RelatedLink;
import org.librecms.contentsection.Asset; import org.librecms.contentsection.Asset;
import org.librecms.contentsection.AssetManager; import org.librecms.contentsection.AssetManager;
@ -135,13 +136,13 @@ public class RelatedInfoStep extends AbstractMvcAuthoringStep {
@Inject @Inject
private BaseUrl baseUrl; private BaseUrl baseUrl;
@Inject @Inject
private DocumentUi documentUi; private DocumentUi documentUi;
@Context @Context
private HttpServletRequest request; private HttpServletRequest request;
/** /**
* Model for the details view of an internal {@link RelatedLink}. * Model for the details view of an internal {@link RelatedLink}.
*/ */
@ -1165,7 +1166,7 @@ public class RelatedInfoStep extends AbstractMvcAuthoringStep {
} else { } else {
linkDetailsModel.setLinkType("--none--"); linkDetailsModel.setLinkType("--none--");
} }
linkDetailsModel.setBaseUrl(baseUrl.getBaseUrl(request)); linkDetailsModel.setBaseUrl(baseUrl.getBaseUrl(request));
final LocalizedTextsUtil textsUtil = globalizationHelper final LocalizedTextsUtil textsUtil = globalizationHelper
@ -1222,23 +1223,23 @@ public class RelatedInfoStep extends AbstractMvcAuthoringStep {
} }
/** /**
* Updates the target of a link.. * Updates to target of a related link and sets it to the provided target
* item, making the link an internal link.
* *
* @param sectionIdentifier * @param sectionIdentifier
* @param documentPath * @param documentPath
* @param listIdentifierParam The identifier of the {@link AttachmentList} * @param listIdentifierParam The identifier of the {@link AttachmentList}
* to which the link belongs. * to which the link belongs.
* @param linkUuid The UUID of the link. * @param linkUuid The UUID of the link.
* @param targetItemUuid The UUID of the new target item. * @param targetItemIdentifier The UUID of the new target item.
* *
* @return A redirect to the details view of the link. * @return A redirect to the details page of the link.
*/ */
@POST @POST
@Path( @Path(
"/attachmentlists/{attachmentListIdentifier}/links/{linkUuid}" "/attachmentlists/{attachmentListIdentifier}/links/{linkUuid}/details/@set-target-item")
)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public String updateLinkTarget( public String setTargetItem(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier, final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
@ -1247,8 +1248,8 @@ public class RelatedInfoStep extends AbstractMvcAuthoringStep {
final String listIdentifierParam, final String listIdentifierParam,
@PathParam("linkUuid") @PathParam("linkUuid")
final String linkUuid, final String linkUuid,
@FormParam("targetItemUuid") @FormParam("targetItemIdentifier")
final String targetItemUuid final String targetItemIdentifier
) { ) {
try { try {
init(); init();
@ -1269,14 +1270,34 @@ public class RelatedInfoStep extends AbstractMvcAuthoringStep {
} }
final AttachmentList list = listResult.get(); final AttachmentList list = listResult.get();
final Optional<ContentItem> itemResult = itemRepo.findByUuid( final Optional<ContentItem> itemResult;
targetItemUuid final Identifier itemIdentifier = identifierParser.parseIdentifier(
targetItemIdentifier
); );
if (!itemResult.isPresent()) { switch (itemIdentifier.getType()) {
models.put("targetItemUuid", targetItemUuid); case ID:
return "org/librecms/ui/contentsection/documents/target-item-not-found.xhtml"; itemResult = itemRepo.findById(
Long.parseLong(itemIdentifier.getIdentifier())
);
break;
case UUID:
itemResult = itemRepo.findByUuid(
itemIdentifier.getIdentifier()
);
break;
default:
itemResult = itemRepo.findByPath(
getContentSection(),
itemIdentifier.getIdentifier()
);
break;
} }
if (!itemResult.isPresent()) {
models.put("targetItemIdentifier", targetItemIdentifier);
return "org/librecms/ui/contentsection/documents/target-item-not-found.xhtml";
}
final Optional<RelatedLink> linkResult = list final Optional<RelatedLink> linkResult = list
.getAttachments() .getAttachments()
.stream() .stream()
@ -1294,11 +1315,138 @@ public class RelatedInfoStep extends AbstractMvcAuthoringStep {
} }
final RelatedLink link = linkResult.get(); final RelatedLink link = linkResult.get();
link.setBookmark(null);
link.setTargetItem(itemResult.get()); link.setTargetItem(itemResult.get());
assetRepo.save(link); assetRepo.save(link);
return buildRedirectPathForStep( return buildRedirectPathForStep(
String.format("/attachmentlists/%s/@details", list.getName()) String.format(
"/attachmentlists/%s/links/%s/@details",
list.getName(),
link.getUuid()
)
);
} else {
return documentUi.showAccessDenied(
getContentSection(),
getDocument(),
getLabel()
);
}
}
/**
* Updates to target of a related link and sets it to the provided bookmark,
* making the link an external link.
*
* @param sectionIdentifier
* @param documentPath
* @param listIdentifierParam The identifier of the
* {@link AttachmentList} to which the link
* belongs.
* @param linkUuid The UUID of the link.
* @param targetBookmarkIdentifier The UUID of the new target bookmark.
*
* @return A redirect to the details page of the link.
*/
@POST
@Path(
"/attachmentlists/{attachmentListIdentifier}/links/{linkUuid}/details/@set-target-bookmark")
@Transactional(Transactional.TxType.REQUIRED)
public String setTargetBookmark(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath,
@PathParam("attachmentListIdentifier")
final String listIdentifierParam,
@PathParam("linkUuid")
final String linkUuid,
@FormParam("targetBookmarkIdentifier")
final String targetBookmarkIdentifier
) {
try {
init();
} catch (ContentSectionNotFoundException ex) {
return ex.showErrorMessage();
} catch (DocumentNotFoundException ex) {
return ex.showErrorMessage();
}
if (permissionChecker.isPermitted(
ItemPrivileges.EDIT, getDocument()
)) {
final Optional<AttachmentList> listResult = findAttachmentList(
listIdentifierParam
);
if (!listResult.isPresent()) {
return showAttachmentListNotFound(listIdentifierParam);
}
final AttachmentList list = listResult.get();
final Optional<Bookmark> bookmarkResult;
final Identifier bookmarkIdentifer = identifierParser
.parseIdentifier(targetBookmarkIdentifier);
switch (bookmarkIdentifer.getType()) {
case ID:
bookmarkResult = assetRepo
.findById(
Long.parseLong(
bookmarkIdentifer.getIdentifier()
),
Bookmark.class
);
break;
case UUID:
bookmarkResult = assetRepo
.findByUuidAndType(
bookmarkIdentifer.getIdentifier(),
Bookmark.class
);
break;
default:
bookmarkResult = assetRepo
.findByPath(
getContentSection(),
bookmarkIdentifer.getIdentifier()
)
.filter(asset -> asset instanceof Bookmark)
.map(asset -> (Bookmark) asset);
}
if (!bookmarkResult.isPresent()) {
models.put("targetBookmarkIdentifier", targetBookmarkIdentifier);
return "org/librecms/ui/contentsection/documents/target-bookmark-not-found.xhtml";
}
final Optional<RelatedLink> linkResult = list
.getAttachments()
.stream()
.map(ItemAttachment::getAsset)
.filter(asset -> asset instanceof RelatedLink)
.map(asset -> (RelatedLink) asset)
.filter(link -> link.getUuid().equals(linkUuid))
.findAny();
if (!linkResult.isPresent()) {
models.put("contentItem", getDocumentPath());
models.put("listIdentifier", listIdentifierParam);
models.put("linkUuid", linkUuid);
return "org/librecms/ui/contentsection/documents/link-asset-not-found.xhtml";
}
final RelatedLink link = linkResult.get();
link.setTargetItem(null);
link.setBookmark(bookmarkResult.get());
assetRepo.save(link);
return buildRedirectPathForStep(
String.format(
"/attachmentlists/%s/links/%s/@details",
list.getName(),
link.getUuid()
)
); );
} else { } else {
return documentUi.showAccessDenied( return documentUi.showAccessDenied(

View File

@ -90,7 +90,7 @@
contentItemPickerId="item-picker" contentItemPickerId="item-picker"
baseUrl="#{CmsLinkDetailsModel.baseUrl}" baseUrl="#{CmsLinkDetailsModel.baseUrl}"
contentSection="#{CmsLinkDetailsModel.sectionName}" contentSection="#{CmsLinkDetailsModel.sectionName}"
formParamName="itemIdentifier" formParamName="targetItemIdentifier"
/> />
</div> </div>
@ -125,7 +125,7 @@
assetPickerId="bookmark-picker" assetPickerId="bookmark-picker"
baseUrl="#{CmsLinkDetailsModel.baseUrl}" baseUrl="#{CmsLinkDetailsModel.baseUrl}"
contentSection="#{CmsLinkDetailsModel.sectionName}" contentSection="#{CmsLinkDetailsModel.sectionName}"
formParamName="bookmarkIdentifier" formParamName="targetBookmarkIdentifier"
/> />
</div> </div>

View File

@ -424,19 +424,19 @@
data-target="#attachmentlist-#{list.name}-add-attachment-dialog" data-target="#attachmentlist-#{list.name}-add-attachment-dialog"
data-toggle="modal" data-toggle="modal"
type="button"> type="button">
<bootstrap:svgIcon icon="plus-circle" /> <bootstrap:svgIcon icon="file-earmark-plus" />
<span>#{CmsDefaultStepsMessageBundle['relatedinfo.attachmentlists.attachment.add.label']}</span> <span class="sr-only">#{CmsDefaultStepsMessageBundle['relatedinfo.attachmentlists.attachment.add.label']}</span>
</button> </button>
<a class="btn btn-primary" <a class="btn btn-primary"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@relatedinfo/attachmentlists/#{list.name}/links/@create" href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@relatedinfo/attachmentlists/#{list.name}/links/@create"
type="button"> type="button">
<bootstrap:svgIcon icon="link-45deg" /> <bootstrap:svgIcon icon="bookmark-plus" />
<span>#{CmsDefaultStepsMessageBundle['relatedinfo.attachmentlists.link.add.label']}</span> <span>#{CmsDefaultStepsMessageBundle['relatedinfo.attachmentlists.link.add.label']}</span>
</a> </a>
<button class="btn btn-danger" <button class="btn btn-danger"
type="button"> type="button">
<bootstrap:svgIcon icon="x-circle" /> <bootstrap:svgIcon icon="x-circle" />
<span>#{CmsDefaultStepsMessageBundle['relatedinfo.attachmentlists.attachment.remove.label']}</span> <span class="sr-only">#{CmsDefaultStepsMessageBundle['relatedinfo.attachmentlists.attachment.remove.label']}</span>
</button> </button>
</div> </div>
</div> </div>

View File

@ -0,0 +1,39 @@
<!DOCTYPE html [<!ENTITY times '&#215;'>]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/documents/document.xhtml">
<ui:param name="activePage" value="document" />
<ui:param name="title" value="#{CmsDefaultStepsMessageBundle['relatedinfo.target_bookmark.not_found.title']}" />
<ui:define name="breadcrumb">
<ui:include src="document-breadcrumbs.xhtml" />
<li aria-current="page" class="breadcrumb-item">
#{CmsDefaultStepsMessageBundle['contentsection.document.relatedlinfo.breadcrumb']}
</li>
</ui:define>
<ui:define name="main">
<div class="container">
<div class="alert alert-danger" role="alert">
#{CmsDefaultStepsMessageBundle.getMessage('relatedinfo.target_bookmark.not_found.message', [targetBookmarkIdentifier])}
</div>
</div>
</ui:define>
</ui:composition>
</html>

View File

@ -19,7 +19,7 @@
<ui:define name="main"> <ui:define name="main">
<div class="container"> <div class="container">
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
#{CmsDefaultStepsMessageBundle.getMessage('relatedinfo.target_item.not_found.message', [targetItemUuid])} #{CmsDefaultStepsMessageBundle.getMessage('relatedinfo.target_item.not_found.message', [targetItemIdentifier])}
</div> </div>
</div> </div>
</ui:define> </ui:define>

View File

@ -218,3 +218,6 @@ relatedinfo.link.details.target.not_set=Target for link has not been set yet.
relatedinfo.link.details.target.type=Type relatedinfo.link.details.target.type=Type
relatedinfo.link.details.target.item_name=Target relatedinfo.link.details.target.item_name=Target
relatedinfo.link.details.target.bookmark_name=Bookmark relatedinfo.link.details.target.bookmark_name=Bookmark
relatedinfo.target_bookmark.not_found.title=Bookmark not found
relatedinfo.target_bookmark.not_found.message=The bookmark {0} selected as target was not found.
contentsection.document.relatedlinfo.breadcrumb=Related Information

View File

@ -218,3 +218,6 @@ relatedinfo.link.details.target.not_set=Es wurde noch kein Ziel f\u00fcr den Lin
relatedinfo.link.details.target.type=Typ relatedinfo.link.details.target.type=Typ
relatedinfo.link.details.target.item_name=Ziel relatedinfo.link.details.target.item_name=Ziel
relatedinfo.link.details.target.bookmark_name=Lesezeichen relatedinfo.link.details.target.bookmark_name=Lesezeichen
relatedinfo.target_bookmark.not_found.title=Lesezeichen nicht gefunden
relatedinfo.target_bookmark.not_found.message=Das als Ziel ausgew\u00e4hlte Lesezeichen {0} ist nicht verf\u00fcgbar.
contentsection.document.relatedlinfo.breadcrumb=Weiterf\u00fchrende Information

View File

@ -1,2 +1,6 @@
@import "custom"; @import "custom";
@import "../../../../node_modules/bootstrap/scss/bootstrap"; @import "../../../../node_modules/bootstrap/scss/bootstrap";
button.btn.cms-sort-handle:hover {
cursor: move;
}

View File

@ -104,6 +104,8 @@ async function selectItem(event: Event, itemPickerElem: Element) {
return; return;
} }
console.log(`itemUuid = ${itemUuid}`);
const itemPickerParam = itemPickerElem.querySelector( const itemPickerParam = itemPickerElem.querySelector(
".contentitempicker-param" ".contentitempicker-param"
) as HTMLInputElement; ) as HTMLInputElement;