Role management for content sections

Former-commit-id: 5cf55c6de7f02399e7680010babdd93961003038
pull/10/head
Jens Pelzetter 2021-02-20 19:01:45 +01:00
parent ddcd759c2e
commit f687a2c875
14 changed files with 915 additions and 7 deletions

View File

@ -0,0 +1,113 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.libreccm.api.Identifier;
import org.libreccm.api.IdentifierParser;
import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.PermissionChecker;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentSectionRepository;
import org.librecms.contentsection.privileges.AdminPrivileges;
import java.util.Optional;
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.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Controller
@Path("/{sectionIdentifier}/configuration")
public class ConfigurationController {
@Inject
private ContentSectionModel sectionModel;
@Inject
private ContentSectionRepository sectionRepo;
@Inject
private IdentifierParser identifierParser;
@Inject
private Models models;
@Inject
private PermissionChecker permissionChecker;
@GET
@Path("/")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String showConfigurationIndexPage(
@PathParam("sectionIdentifier") final String sectionIdentifierParam
) {
final Identifier sectionIdentifier = identifierParser.parseIdentifier(
sectionIdentifierParam
);
final Optional<ContentSection> sectionResult;
switch (sectionIdentifier.getType()) {
case ID:
sectionResult = sectionRepo.findById(
Long.parseLong(
sectionIdentifier.getIdentifier()
)
);
break;
case UUID:
sectionResult = sectionRepo.findByUuid(
sectionIdentifier.getIdentifier()
);
break;
default:
sectionResult = sectionRepo.findByLabel(
sectionIdentifier.getIdentifier()
);
break;
}
if (!sectionResult.isPresent()) {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/contentsection-not-found.xhtml";
}
final ContentSection section = sectionResult.get();
sectionModel.setSection(section);
if (!hasRequiredPermission(section)) {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/access-denied.xhtml";
}
return "org/librecms/ui/contentsection/configuration/index.xhtml";
}
private boolean hasRequiredPermission(final ContentSection section) {
return permissionChecker.isPermitted(
AdminPrivileges.ADMINISTER_CONTENT_TYPES, section
)
|| permissionChecker.isPermitted(
AdminPrivileges.ADMINISTER_LIFECYLES, section
)
|| permissionChecker.isPermitted(
AdminPrivileges.ADMINISTER_ROLES, section
)
|| permissionChecker.isPermitted(
AdminPrivileges.ADMINISTER_WORKFLOW, section
);
}
}

View File

@ -0,0 +1,269 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.libreccm.api.Identifier;
import org.libreccm.api.IdentifierParser;
import org.libreccm.core.CcmObject;
import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.Permission;
import org.libreccm.security.PermissionChecker;
import org.libreccm.security.Role;
import org.libreccm.security.RoleMembership;
import java.util.Optional;
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.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentSectionRepository;
import org.librecms.contentsection.Folder;
import org.librecms.contentsection.privileges.AdminPrivileges;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Controller
@Path("/{sectionIdentifier}/configuration/roles")
public class ConfigurationRolesController {
@Inject
private ContentSectionModel sectionModel;
@Inject
private ContentSectionRepository sectionRepo;
@Inject
private GlobalizationHelper globalizationHelper;
@Inject
private IdentifierParser identifierParser;
@Inject
private Models models;
@Inject
private PermissionChecker permissionChecker;
@Inject
private SelectedRoleModel selectedRoleModel;
@GET
@Path("/")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String listRoles(
@PathParam("sectionIdentifier") final String sectionIdentifierParam
) {
final Identifier sectionIdentifier = identifierParser.parseIdentifier(
sectionIdentifierParam
);
final Optional<ContentSection> sectionResult;
switch (sectionIdentifier.getType()) {
case ID:
sectionResult = sectionRepo.findById(
Long.parseLong(
sectionIdentifier.getIdentifier()
)
);
break;
case UUID:
sectionResult = sectionRepo.findByUuid(
sectionIdentifier.getIdentifier()
);
break;
default:
sectionResult = sectionRepo.findByLabel(
sectionIdentifier.getIdentifier()
);
break;
}
if (!sectionResult.isPresent()) {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/contentsection-not-found.xhtml";
}
final ContentSection section = sectionResult.get();
sectionModel.setSection(section);
if (!permissionChecker.isPermitted(
AdminPrivileges.ADMINISTER_ROLES, section
)) {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/access-denied.xhtml";
}
final List<RoleListItemModel> roles = section
.getRoles()
.stream()
.map(this::buildRoleListModel)
.collect(Collectors.toList());
models.put("roles", roles);
return "org/librecms/ui/contentsection/configuration/roles.xhtml";
}
@GET
@Path("/{roleName}")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String showRole(
@PathParam("sectionIdentifier") final String sectionIdentifierParam,
@PathParam("roleName") final String roleName
) {
final Identifier sectionIdentifier = identifierParser.parseIdentifier(
sectionIdentifierParam
);
final Optional<ContentSection> sectionResult;
switch (sectionIdentifier.getType()) {
case ID:
sectionResult = sectionRepo.findById(
Long.parseLong(
sectionIdentifier.getIdentifier()
)
);
break;
case UUID:
sectionResult = sectionRepo.findByUuid(
sectionIdentifier.getIdentifier()
);
break;
default:
sectionResult = sectionRepo.findByLabel(
sectionIdentifier.getIdentifier()
);
break;
}
if (!sectionResult.isPresent()) {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/contentsection-not-found.xhtml";
}
final ContentSection section = sectionResult.get();
sectionModel.setSection(section);
if (!permissionChecker.isPermitted(
AdminPrivileges.ADMINISTER_ROLES, section
)) {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/access-denied.xhtml";
}
final Optional<Role> result = section
.getRoles()
.stream()
.filter(role -> roleName.equals(role.getName()))
.findAny();
if (!result.isPresent()) {
models.put("sectionIdentifier", sectionIdentifier);
models.put("roleName", roleName);
return "org/librecms/ui/contentsection/configuration/role-not-found.xhtml";
}
final Role role = result.get();
selectedRoleModel.setDescription(
role
.getDescription()
.getValues()
.entrySet()
.stream()
.collect(
Collectors.toMap(
entry -> entry.getKey().toString(),
entry -> entry.getValue()
)
)
);
selectedRoleModel.setMembers(
role
.getMemberships()
.stream()
.map(this::buildRoleMembershipModel)
.collect(Collectors.toList())
);
selectedRoleModel.setName(role.getName());
selectedRoleModel.setPermissions(
role
.getPermissions()
.stream()
.filter(
permission -> onlyContentSectionPermissions(
permission, section
)
)
.map(permission -> permission.getGrantedPrivilege())
.collect(Collectors.toList())
);
final Set<Locale> descriptionLocales = role
.getDescription()
.getAvailableLocales();
final List<Locale> availableLocales = globalizationHelper
.getAvailableLocales();
selectedRoleModel.setUnusedDescriptionLocales(
availableLocales
.stream()
.filter(locale -> !descriptionLocales.contains(locale))
.map(Locale::toString)
.collect(Collectors.toList())
);
return "org/librecms/ui/contentsection/configuration/role.xhtml";
}
private RoleListItemModel buildRoleListModel(final Role role) {
final RoleListItemModel model = new RoleListItemModel();
model.setRoleId(role.getRoleId());
model.setUuid(role.getUuid());
model.setName(role.getName());
model.setDescription(
globalizationHelper.getValueFromLocalizedString(
role.getDescription()
)
);
return model;
}
private RoleMembershipModel buildRoleMembershipModel(
final RoleMembership membership
) {
final RoleMembershipModel model = new RoleMembershipModel();
model.setMemberName(membership.getMember().getName());
model.setMemberUuid(membership.getMember().getUuid());
return model;
}
private boolean onlyContentSectionPermissions(
final Permission permission, final ContentSection section
) {
final Folder rootDocumentsFolder = section.getRootDocumentsFolder();
final Folder rootAssetsFolder = section.getRootAssetsFolder();
final CcmObject object = permission.getObject();
return section.equals(object)
|| rootDocumentsFolder.equals(object)
|| rootAssetsFolder.equals(object);
}
}

View File

@ -23,17 +23,16 @@ public class ContentSectionApplication extends Application {
@Override @Override
public Set<Class<?>> getClasses() { public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<>(); final Set<Class<?>> classes = new HashSet<>();
classes.add(AssetFolderController.class); classes.add(AssetFolderController.class);
classes.add(CategoriesController.class); classes.add(CategoriesController.class);
classes.add(ConfigurationController.class);
classes.add(ConfigurationRolesController.class);
classes.add(ContentSectionController.class); classes.add(ContentSectionController.class);
classes.add(DocumentFolderController.class); classes.add(DocumentFolderController.class);
classes.add(IsAuthenticatedFilter.class); classes.add(IsAuthenticatedFilter.class);
return classes; return classes;
} }
} }

View File

@ -0,0 +1,54 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class RoleListItemModel {
private long roleId;
private String uuid;
private String name;
private String description;
public long getRoleId() {
return roleId;
}
public void setRoleId(final long roleId) {
this.roleId = roleId;
}
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 String getDescription() {
return description;
}
public void setDescription(final String description) {
this.description = description;
}
}

View File

@ -0,0 +1,34 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class RoleMembershipModel {
private String memberName;
private String memberUuid;
public String getMemberName() {
return memberName;
}
public void setMemberName(final String memberName) {
this.memberName = memberName;
}
public String getMemberUuid() {
return memberUuid;
}
public void setMemberUuid(final String memberUuid) {
this.memberUuid = memberUuid;
}
}

View File

@ -0,0 +1,87 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("SelectedRoleModel")
public class SelectedRoleModel {
private String name;
private Map<String, String> description;
private List<String> unusedDescriptionLocales;
private List<RoleMembershipModel> members;
/**
* Permissions of the role for the content section.
*/
private List<String> permissions;
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public Map<String, String> getDescription() {
return Collections.unmodifiableMap(description);
}
public void setDescription(final Map<String, String> description) {
this.description = new HashMap<>(description);
}
public List<RoleMembershipModel> getMembers() {
return Collections.unmodifiableList(members);
}
public void setMembers(final List<RoleMembershipModel> members) {
this.members = new ArrayList<>(members);
}
public List<String> getPermissions() {
return Collections.unmodifiableList(permissions);
}
public void setPermissions(final List<String> permissions) {
this.permissions = new ArrayList<>(permissions);
}
public List<String> getUnusedDescriptionLocales() {
return Collections.unmodifiableList(unusedDescriptionLocales);
}
public void setUnusedDescriptionLocales(
final List<String> unusedDescriptionLocales
) {
this.unusedDescriptionLocales
= new ArrayList<>(unusedDescriptionLocales);
}
public boolean getHasUnusedDescriptionLocales() {
return !unusedDescriptionLocales.isEmpty();
}
}

View File

@ -0,0 +1,36 @@
<!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:cms="http://xmlns.jcp.org/jsf/composite/components/cms"
xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition>
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link #{activeConfPage == 'roles' ? 'active' : ''}"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/roles">
#{CmsAdminMessages['contentsection.configuration.roles.title']}
</a>
</li>
<li class="nav-item">
<a class="nav-link #{activeConfPage == 'contenttypes' ? 'active' : ''}"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/contenttypes">
#{CmsAdminMessages['contentsection.configuration.contenttypes.title']}
</a>
</li>
<li class="nav-item">
<a class="nav-link #{activeConfPage == 'lifecycles' ? 'active' : ''}"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/lifecycles">
#{CmsAdminMessages['contentsection.configuration.lifecycles.title']}
</a>
</li>
<li class="nav-item">
<a class="nav-link #{activeConfPage == 'workflows' ? 'active' : ''}"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/workflows">
#{CmsAdminMessages['contentsection.configuration.workflows.title']}
</a>
</li>
</ul>
</ui:composition>
</html>

View File

@ -0,0 +1,122 @@
<!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:cms="http://xmlns.jcp.org/jsf/composite/components/cms"
xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:xlink="http://www.w3.org/1999/xlink">
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/contentsection.xhtml">
<ui:param name="activePage" value="configuration" />
<ui:param name="title"
value="#{CmsAdminMessages['contentsection.configuration.title']}" />
<ui:define name="breadcrumb">
<li aria-current="page" class="breadcrumb-item">
#{CmsAdminMessages['contentsection.configuration.title']}
</li>
</ui:define>
<ui:define name="main">
<div class="container">
<h1>#{CmsAdminMessages.getMessage('contentsection.configuration.heading', [ContentSectionModel.sectionName])}</h1>
<div class="row row-cols-1 row-cols-sm-1 row-cols-md-2 row-cols-lg-3 row-cols-xl-4">
<div class="col mb-6">
<div aria-describedby="configuration-roles-body"
class="card pt-2"
id="configuration-roles">
<svg aria-hidden="true"
class="card-img-top"
fill="currentColor">
<use xlink:href="#{request.contextPath}/assets/bootstrap/bootstrap-icons.svg#people-fill" />
</svg>
</div>
<div class="card-body"
id="configuration-roles-body">
<h2 class="card-title">
<a class="stretched-link"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/roles">
#{CmsAdminMessages['contentsection.configuration.roles.title']}
</a>
</h2>
<p class="card-text">
#{CmsAdminMessages['contentsection.configuration.roles.description']}
</p>
</div>
</div>
<div class="col mb-4">
<div aria-describedby="configuration-contenttypes-body"
class="card pt-2"
id="configuration-contenttypes">
<svg aria-hidden="true"
class="card-img-top"
fill="currentColor">
<use xlink:href="#{request.contextPath}/assets/bootstrap/bootstrap-icons.svg#puzzle-fill" />
</svg>
</div>
<div class="card-body"
id="configuration-contenttypes-body">
<h2 class="card-title">
<a class="stretched-link"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/contenttypes">
#{CmsAdminMessages['contentsection.configuration.contenttypes.title']}
</a>
</h2>
<p class="card-text">
#{CmsAdminMessages['contentsection.configuration.contenttypes.description']}
</p>
</div>
</div>
<div class="col mb-4">
<div aria-describedby="configuration-lifecycles-body"
class="card pt-2"
id="configuration-lifecycles">
<svg aria-hidden="true"
class="card-img-top"
fill="currentColor">
<use xlink:href="#{request.contextPath}/assets/bootstrap/bootstrap-icons.svg#arrow-repeat" />
</svg>
</div>
<div class="card-body"
id="configuration-lifecycles-body">
<h2 class="card-title">
<a class="stretched-link"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/lifecycles">
#{CmsAdminMessages['contentsection.configuration.lifecycles.title']}
</a>
</h2>
<p class="card-text">
#{CmsAdminMessages['contentsection.configuration.lifecycles.description']}
</p>
</div>
</div>
<div class="col mb-4">
<div aria-describedby="configuration-workflows-body"
class="card pt-2"
id="configuration-workflows">
<svg aria-hidden="true"
class="card-img-top"
fill="currentColor">
<use xlink:href="#{request.contextPath}/assets/bootstrap/bootstrap-icons.svg#list-check" />
</svg>
</div>
<div class="card-body"
id="configuration-workflows-body">
<h2 class="card-title">
<a class="stretched-link"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/workflows">
#{CmsAdminMessages['contentsection.configuration.workflows.title']}
</a>
</h2>
<p class="card-text">
#{CmsAdminMessages['contentsection.configuration.workflows.description']}
</p>
</div>
</div>
</div>
</div>
</ui:define>
</ui:composition>
</html>

View File

@ -0,0 +1,56 @@
<!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:cms="http://xmlns.jcp.org/jsf/composite/components/cms"
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/contentsection.xhtml">
<ui:param name="activePage" value="configuration" />
<ui:param name="title"
value="#{CmsAdminMessages['contentsection.configuration.roles.title']}" />
<ui:define name="breadcrumb">
<li class="breadcrumb-item">
<a href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration">
#{CmsAdminMessages['contentsection.configuration.title']}
</a>
</li>
<li class="breadcrumb-item">
<a href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/roles">
#{CmsAdminMessages['contentsection.configuration.roles.title']}
</a>
</li>
<li aria-current="page" class="breadcrumb-item">
#{CmsAdminMessages['contentsection.configuration.roles.breadcrumbs']} #{SelectedRoleModel.name}
</li>
</ui:define>
<ui:define name="main">
<div class="container">
<ui:include src="configuration-tabs.xhtml">
<ui:param name="activeConfPage" value="roles" />
</ui:include>
<h1>#{CmsAdminMessages.getMessage('contentsection.configuration.roles.role_details.title', [SelectedRoleModel.name])}</h1>
<dl>
<div>
<dt>#{CmsAdminMessages['contentsection.configuration.roles.role_details.name']}</dt>
<dd>#{SelectedRoleModel.name}</dd>
</div>
</dl>
<libreccm:localizedStringEditor
addMethod="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/roles/#{SelectedRoleModel.name}/description/add"
editMethod="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/roles/#{SelectedRoleModel.name}/description/edit"
editorId="role-description"
hasUnusedLocales="#{SelectedRoleModel.hasUnusedDescriptionLocales}"
objectIdentifier="#{SelectedRoleModel.name}"
removeMethod="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/roles/#{SelectedRoleModel.name}/description/remove"
title="#{CmsAdminMessages['contentsection.configuration.roles.role_details.description.title']}"
unusedLocales="#{SelectedRoleModel.unusedDescriptionLocales}"
values="#{SelectedRoleModel.description}"
/>
</div>
</ui:define>
</ui:composition>
</html>

View File

@ -0,0 +1,90 @@
<!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:cms="http://xmlns.jcp.org/jsf/composite/components/cms"
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/contentsection.xhtml">
<ui:param name="activePage" value="configuration" />
<ui:param name="title"
value="#{CmsAdminMessages['contentsection.configuration.roles.title']}" />
<ui:define name="breadcrumb">
<li class="breadcrumb-item">
<a href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration">
#{CmsAdminMessages['contentsection.configuration.title']}
</a>
</li>
<li aria-current="page" class="breadcrumb-item">
#{CmsAdminMessages['contentsection.configuration.roles.title']}
</li>
</ui:define>
<ui:define name="main">
<div class="container">
<ui:include src="configuration-tabs.xhtml">
<ui:param name="activeConfPage" value="roles" />
</ui:include>
<h1>#{CmsAdminMessages['contentsection.configuration.roles.title']}</h1>
<div class="mb-2">
<div class="text-right">
<button class="btn btn-primary"
data-toggle="modal"
data-target="#add-role-dialog"
type="button">
<bootstrap:svgIcon icon="plus-circle" />
<span>#{CmsAdminMessages['contentsection.configuration.roles.add']}</span>
</button>
</div>
<!-- Dialog for adding role -->
</div>
<table class="contentsection-roles-table table table-hover">
<thead>
<tr>
<th scope="col">
#{CmsAdminMessages['contentsection.configuration.roles.table.name']}
</th>
<th scope="col">
#{CmsAdminMessages['contentsection.configuration.roles.table.description']}
</th>
<th class="text-center" colspan="2">
#{CmsAdminMessages['contentsection.configuration.roles.table.actions']}
</th>
</tr>
</thead>
<tbody>
<c:forEach items="#{roles}"
var="role">
<tr>
<td>#{role.name}</td>
<td>#{role.description}</td>
<td class="actions-details-col">
<a class="btn btn-info"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/roles/#{role.name}">
<bootstrap:svgIcon icon="eye" />
<span>
#{CmsAdminMessages['contentsection.configuration.roles.table.actions.details']}
</span>
</a>
</td>
<td class="actions-delete-col">
<button class="btn btn-info"
type="button">
<bootstrap:svgIcon icon="x-circle" />
<span>
#{CmsAdminMessages['contentsection.configuration.roles.table.actions.delete']}
</span>
</button>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</ui:define>
</ui:composition>
</html>

View File

@ -275,3 +275,22 @@ contentsections.categorystems.category.objects.reorder.increase=Down
contentsections.categorystems.category.objects.index_object.reset=Reset index object contentsections.categorystems.category.objects.index_object.reset=Reset index object
contentsections.categorystems.category.objects.index_object.set=Use as index object contentsections.categorystems.category.objects.index_object.set=Use as index object
contentsections.categorystems.category.objects.none=No objects in this category contentsections.categorystems.category.objects.none=No objects in this category
contentsection.configuration.heading=Configuration of Content Section {0}
contentsection.configuration.roles.title=Roles
contentsection.configuration.roles.description=Manage roles for this content section
contentsection.configuration.contenttypes.title=Content Types
contentsection.configuration.contenttypes.description=Manage the document types available in this content section
contentsection.configuration.lifecycles.title=Lifecycles
contentsection.configuration.lifecycles.description=Manage lifecycles for documents in this content section
contentsection.configuration.workflows.title=Workflows
contentsection.configuration.workflows.description=Manage workflows for documents in this content section
contentsection.configuration.roles.table.name=Name
contentsection.configuration.roles.table.description=Description
contentsection.configuration.roles.table.actions=Actions
contentsection.configuration.roles.table.actions.details=Details
contentsection.configuration.roles.table.actions.delete=Delete role
contentsection.configuration.roles.role_details.title=Details Role {0}
contentsection.configuration.roles.role_details.name=Name
contentsection.configuration.roles.role_details.description.title=Description
contentsection.configuration.roles.breadcrumbs=Role
contentsection.configuration.roles.add=Add role

View File

@ -276,3 +276,22 @@ contentsections.categorystems.category.objects.reorder.increase=Runter
contentsections.categorystems.category.objects.index_object.reset=Index Objekt zur\u00fccksetzen contentsections.categorystems.category.objects.index_object.reset=Index Objekt zur\u00fccksetzen
contentsections.categorystems.category.objects.index_object.set=Als Index-Objekt nutzen contentsections.categorystems.category.objects.index_object.set=Als Index-Objekt nutzen
contentsections.categorystems.category.objects.none=Dieser Kategorie sind keine Objekte zugeordnet contentsections.categorystems.category.objects.none=Dieser Kategorie sind keine Objekte zugeordnet
contentsection.configuration.heading=Konfiguration Content Section {0}
contentsection.configuration.roles.title=Rollen
contentsection.configuration.roles.description=Rollen dieser Content Section verwalten
contentsection.configuration.contenttypes.title=Dokumenttypen
contentsection.configuration.contenttypes.description=In dieser Content Section verf\u00fcgbare Dokumenttypes verwalten
contentsection.configuration.lifecycles.title=Lebenszyklen
contentsection.configuration.lifecycles.description=Lebenszyklen f\u00fcr Dokumente dieser Content Section verwalten
contentsection.configuration.workflows.title=Arbeitsabl\u00e4ufe
contentsection.configuration.workflows.description=Arbeitsabl\u00e4ufe f\u00fcr Dokumente in dieser Content Section verwalten
contentsection.configuration.roles.table.name=Name
contentsection.configuration.roles.table.description=Beschreibung
contentsection.configuration.roles.table.actions=Aktionen
contentsection.configuration.roles.table.actions.details=Details
contentsection.configuration.roles.table.actions.delete=Rolle l\u00f6schen
contentsection.configuration.roles.role_details.title=Details Rolle {0}
contentsection.configuration.roles.role_details.name=Name
contentsection.configuration.roles.role_details.description.title=Beschreibung
contentsection.configuration.roles.breadcrumbs=Rolle
contentsection.configuration.roles.add=Rolle hinzuf\u00fcgen

View File

@ -103,4 +103,14 @@ table.contentsections.categories-table {
td.actions-setindex-col { td.actions-setindex-col {
width: 11em; width: 11em;
} }
}
table.contentsection-roles-table {
td.actions-details-col {
width: 9em;
}
td.actions-delete-col {
width: 11em;
}
} }

View File

@ -15,7 +15,7 @@
<ui:define name="main"> <ui:define name="main">
<div class="container-fluid"> <div class="container-fluid">
<h1>#{AdminMessages['dashboard.label']}</h1> <h1>#{AdminMessages['dashboard.label']}</h1>
<div class="row row-cols-1 row-cols-sm-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 row-cols-xl-5"> <div class="row row-cols-1 row-cols-sm-1 row-cols-md-3 row-cols-lg-4 row-cols-xl-5">
<c:forEach begin="1" <c:forEach begin="1"
items="#{AdminPagesModel.adminPages}" items="#{AdminPagesModel.adminPages}"
var="page"> var="page">