Role Managment for content sections

Former-commit-id: 9d017e313fd80872055bd7f3935215357e149d81
pull/10/head
Jens Pelzetter 2021-02-23 21:34:30 +01:00
parent 1e0e5f6f65
commit 99d13efbde
8 changed files with 557 additions and 15 deletions

View File

@ -14,6 +14,7 @@ import org.libreccm.security.Permission;
import org.libreccm.security.PermissionChecker; import org.libreccm.security.PermissionChecker;
import org.libreccm.security.Role; import org.libreccm.security.Role;
import org.libreccm.security.RoleMembership; import org.libreccm.security.RoleMembership;
import org.libreccm.security.RoleRepository;
import java.util.Optional; import java.util.Optional;
@ -27,15 +28,22 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentSectionManager;
import org.librecms.contentsection.ContentSectionRepository; import org.librecms.contentsection.ContentSectionRepository;
import org.librecms.contentsection.Folder; import org.librecms.contentsection.Folder;
import org.librecms.contentsection.privileges.AdminPrivileges; import org.librecms.contentsection.privileges.AdminPrivileges;
import org.librecms.ui.CmsAdminMessages;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
/** /**
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
@ -45,6 +53,12 @@ import java.util.stream.Collectors;
@Path("/{sectionIdentifier}/configuration/roles") @Path("/{sectionIdentifier}/configuration/roles")
public class ConfigurationRolesController { public class ConfigurationRolesController {
@Inject
private CmsAdminMessages messages;
@Inject
private ContentSectionManager sectionManager;
@Inject @Inject
private ContentSectionModel sectionModel; private ContentSectionModel sectionModel;
@ -63,6 +77,9 @@ public class ConfigurationRolesController {
@Inject @Inject
private PermissionChecker permissionChecker; private PermissionChecker permissionChecker;
@Inject
private RoleRepository roleRepo;
@Inject @Inject
private SelectedRoleModel selectedRoleModel; private SelectedRoleModel selectedRoleModel;
@ -112,12 +129,30 @@ public class ConfigurationRolesController {
return "org/librecms/ui/contentsection/access-denied.xhtml"; return "org/librecms/ui/contentsection/access-denied.xhtml";
} }
final List<RoleListItemModel> roles = section final List<Role> sectionRoles = section.getRoles();
.getRoles()
final Set<Role> otherRoles = roleRepo
.findAll()
.stream() .stream()
.map(this::buildRoleListModel) .filter(role -> !sectionRoles.contains(role))
.collect(Collectors.toList()); .collect(Collectors.toSet());
models.put("roles", roles);
models.put(
"roles",
sectionRoles
.stream()
.map(this::buildRoleListModel)
.collect(Collectors.toList())
);
models.put(
"otherRoles",
otherRoles
.stream()
.map(this::buildRoleListModel)
.sorted(
(role1, role2) -> role1.getName().compareTo(role2.getName())
).collect(Collectors.toList())
);
return "org/librecms/ui/contentsection/configuration/roles.xhtml"; return "org/librecms/ui/contentsection/configuration/roles.xhtml";
} }
@ -231,6 +266,308 @@ public class ConfigurationRolesController {
return "org/librecms/ui/contentsection/configuration/role.xhtml"; return "org/librecms/ui/contentsection/configuration/role.xhtml";
} }
@POST
@Path("/@new")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String createRole(
@PathParam("sectionIdentifier") final String sectionIdentifierParam,
@FormParam("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 List<String> errors = new ArrayList<>();
if (roleName == null || roleName.matches("\\s*")) {
errors.add(
messages.get(
"contentsection.configuration.roles.errors.name_not_empty"
)
);
}
if (roleName != null && !roleName.matches("[a-zA-Z0-9_-]*")) {
errors.add(
messages.get(
"contentsection.configuration.roles.errors.name_invalid"
)
);
}
if (!errors.isEmpty()) {
models.put("errors", errors);
models.put("roleName", roleName);
return listRoles(sectionIdentifierParam);
}
sectionManager.addRoleToContentSection(section, roleName);
return String.format(
"redirect:/%s/configuration/roles", sectionIdentifierParam
);
}
@POST
@Path("/@add")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String addRole(
@PathParam("sectionIdentifier") final String sectionIdentifierParam,
@FormParam("rolesToAdd") final List<String> rolesToAdd
) {
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";
}
for (final String roleUuid : rolesToAdd) {
roleRepo
.findByUuid(roleUuid)
.ifPresent(
role -> sectionManager.addRoleToContentSection(
role, section
)
);
}
return String.format(
"redirect:/%s/configuration/roles", sectionIdentifierParam
);
}
@POST
@Path("/{roleIdentifier}/@remove")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String removeRole(
@PathParam("sectionIdentifier") final String sectionIdentifierParam,
@PathParam("roleIdentifier") final String roleIdentifierParam
) {
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 Identifier roleIdentifier = identifierParser.parseIdentifier(
roleIdentifierParam
);
final Optional<Role> roleResult;
switch (roleIdentifier.getType()) {
case ID:
roleResult = roleRepo.findById(
Long.parseLong(roleIdentifier.getIdentifier())
);
break;
case UUID:
roleResult = roleRepo.findByUuid(
roleIdentifier.getIdentifier()
);
break;
default:
roleResult = roleRepo.findByName(
roleIdentifier.getIdentifier()
);
break;
}
if (!roleResult.isPresent()) {
models.put("roleIdentifier", roleIdentifierParam);
return "org/librecms/ui/contentsection/configuration/role-not-found.xhtml";
}
final Role role = roleResult.get();
sectionManager.removeRoleFromContentSection(section, role);
return String.format(
"redirect:/%s/configuration/roles", sectionIdentifierParam
);
}
@POST
@Path("/{roleIdentifier}/@delete")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String deleteRole(
@PathParam("sectionIdentifier") final String sectionIdentifierParam,
@PathParam("roleIdentifier") final String roleIdentifierParam
) {
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 Identifier roleIdentifier = identifierParser.parseIdentifier(
roleIdentifierParam
);
final Optional<Role> roleResult;
switch (roleIdentifier.getType()) {
case ID:
roleResult = roleRepo.findById(
Long.parseLong(roleIdentifier.getIdentifier())
);
break;
case UUID:
roleResult = roleRepo.findByUuid(
roleIdentifier.getIdentifier()
);
break;
default:
roleResult = roleRepo.findByName(
roleIdentifier.getIdentifier()
);
break;
}
if (!roleResult.isPresent()) {
models.put("roleIdentifier", roleIdentifierParam);
return "org/librecms/ui/contentsection/configuration/role-not-found.xhtml";
}
final Role role = roleResult.get();
sectionManager.removeRoleFromContentSection(section, role);
roleRepo.delete(role);
return String.format(
"redirect:/%s/configuration/roles", sectionIdentifierParam
);
}
private RoleListItemModel buildRoleListModel(final Role role) { private RoleListItemModel buildRoleListModel(final Role role) {
final RoleListItemModel model = new RoleListItemModel(); final RoleListItemModel model = new RoleListItemModel();
model.setRoleId(role.getRoleId()); model.setRoleId(role.getRoleId());

View File

@ -0,0 +1,26 @@
<!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/content-section/contentsection.xhtml">
<ui:param name="activePage" value="folderBrowser" />
<ui:param name="title" value="#{CmsAdminMessages['contentsection.not_found.title']}" />
<ui:define name="breadcrumb">
<li class="breadcrumb-item">
#{CmsAdminMessages['contentsections.list.label']}
</li>
</ui:define>
<ui:define name="main">
<div class="container">
<div class="alert alert-danger" role="alert">
#{CmsAdminMessages.getMessage('contentsection.role.not_found', [roleIdentifier])}
</div>
</div>
</ui:define>
</ui:composition>
</html>

View File

@ -29,6 +29,14 @@
</ui:include> </ui:include>
<h1>#{CmsAdminMessages['contentsection.configuration.roles.title']}</h1> <h1>#{CmsAdminMessages['contentsection.configuration.roles.title']}</h1>
<c:if test="#{not empty errors}">
<c:forEach items="#{errors}" var="error">
<div class="alert alert-danger" role="alert">
#{error}
</div>
</c:forEach>
</c:if>
<div class="mb-2"> <div class="mb-2">
<div class="text-right"> <div class="text-right">
<button class="btn btn-primary" <button class="btn btn-primary"
@ -46,8 +54,114 @@
<span>#{CmsAdminMessages['contentsection.configuration.roles.create']}</span> <span>#{CmsAdminMessages['contentsection.configuration.roles.create']}</span>
</button> </button>
</div> </div>
<div aria-hidden="true"
aria-labelledby="add-role-dialog-title"
class="modal fade"
id="add-role-dialog"
tabindex="-1">
<div class="modal-dialog">
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/roles/@add"
class="modal-content"
method="post">
<div class="modal-header">
<h3 class="modal-title"
id="add-role-dialog-title">
#{CmsAdminMessages.getMessage('contentsection.configuration.roles.add.dialog.title', [ContentSectionModel.sectionName])}
</h3>
<button aria-label="#{CmsAdminMessages['contentsection.configuration.roles.add.dialog.cancel']}"
class="close"
data-dismiss="modal"
type="button">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<c:forEach items="#{otherRoles}"
var="role">
<div class="form-check">
<input class="form-check-input"
id="add-role-dialog-role-#{role.name}"
name="rolesToAdd"
type="checkbox"
value="#{role.uuid}" />
<label class="form-check-label"
for="add-role-dialog-role-#{role.name}">
#{role.name}
</label>
</div>
</c:forEach>
</div>
<div class="modal-footer">
<button class="btn btn-warning"
data-dismiss="modal"
type="button">
#{CmsAdminMessages['contentsection.configuration.roles.add.dialog.cancel']}
</button>
<button class="btn btn-primary"
type="submit" >
#{CmsAdminMessages['contentsection.configuration.roles.add.dialog.submit']}
</button>
</div>
</form>
</div>
</div>
<!-- Dialog for adding existing role --> <!-- Dialog for adding existing role -->
<!-- Dialog for creating role --> <div aria-hidden="true"
aria-lablledby="create-role-dialog-title"
class="modal fade"
id="create-role-dialog"
tabindex="-1">
<div class="modal-dialog">
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/roles/@new"
class="modal-content"
method="post">
<div class="modal-header">
<h3 class="modal-title"
id="create-role-dialog-title">
#{CmsAdminMessages.getMessage('contentsection.configuration.roles.create.dialog.title', [ContentSectionModel.sectionName])}
</h3>
<button aria-label="#{CmsAdminMessages['contentsection.configuration.roles.create.dialog.cancel']}"
class="close"
data-dismiss="modal"
type="button">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="rolename">
#{CmsAdminMessages['contentsection.configuration.roles.create.dialog.rolename.label']}
</label>
<input aria-described-by="rolename-help"
class="form-control"
id="rolename"
name="roleName"
pattern="[a-zA-Z0-9_-]*"
required="required"
value="#{roleName}"
type="text" />
<small class="form-text text-muted"
id="rolename-help">
#{CmsAdminMessages['contentsection.configuration.roles.create.dialog.rolename.help']}
</small>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-warning"
data-dismiss="modal"
type="button">
#{CmsAdminMessages['contentsection.configuration.roles.create.dialog.cancel']}
</button>
<button class="btn btn-primary"
type="submit" >
#{CmsAdminMessages['contentsection.configuration.roles.create.dialog.submit']}
</button>
</div>
</form>
</div>
</div>
</div> </div>
<table class="contentsection-roles-table table table-hover"> <table class="contentsection-roles-table table table-hover">
<thead> <thead>
@ -79,22 +193,39 @@
</a> </a>
</td> </td>
<td class="actions-delete-col"> <td class="actions-delete-col">
<button class="btn btn-warning" <libreccm:deleteDialog actionTarget="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/roles/UUID-#{role.uuid}/@remove"
buttonClass="warning"
buttonText="#{CmsAdminMessages['contentsection.configuration.roles.table.actions.remove']}"
cancelLabel="#{CmsAdminMessages['contentsection.configuration.roles.table.actions.remove.cancel']}"
confirmLabel="#{CmsAdminMessages['contentsection.configuration.roles.table.actions.remove.submit']}"
dialogId="role-#{role.uuid}-remove"
dialogTitle="#{CmsAdminMessages['contentsection.configuration.roles.table.actions.remove.title']}"
message="#{CmsAdminMessages.getMessage('contentsection.configuration.roles.table.actions.remove.message',[role.name, ContentSectionModel.sectionName])}"
/>
<!-- <button class="btn btn-warning"
type="button"> type="button">
<bootstrap:svgIcon icon="x-circle" /> <bootstrap:svgIcon icon="x-circle" />
<span> <span>
#{CmsAdminMessages['contentsection.configuration.roles.table.actions.remove']} #{CmsAdminMessages['contentsection.configuration.roles.table.actions.remove']}
</span> </span>
</button> </button>-->
</td> </td>
<td class="actions-delete-col"> <td class="actions-delete-col">
<button class="btn btn-danger" <libreccm:deleteDialog actionTarget="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/roles/UUID-#{role.uuid}/@delete"
buttonText="#{CmsAdminMessages['contentsection.configuration.roles.table.actions.delete']}"
cancelLabel="#{CmsAdminMessages['contentsection.configuration.roles.table.actions.delete.cancel']}"
confirmLabel="#{CmsAdminMessages['contentsection.configuration.roles.table.actions.delete.submit']}"
dialogId="role-#{role.uuid}-delete"
dialogTitle="#{CmsAdminMessages['contentsection.configuration.roles.table.actions.delete.title']}"
message="#{CmsAdminMessages.getMessage('contentsection.configuration.roles.table.actions.delete.message',[role.name, ContentSectionModel.sectionName])}"
/>
<!-- <button class="btn btn-danger"
type="button"> type="button">
<bootstrap:svgIcon icon="x-circle" /> <bootstrap:svgIcon icon="x-circle" />
<span> <span>
#{CmsAdminMessages['contentsection.configuration.roles.table.actions.delete']} #{CmsAdminMessages['contentsection.configuration.roles.table.actions.delete']}
</span> </span>
</button> </button>-->
</td> </td>
</tr> </tr>
</c:forEach> </c:forEach>

View File

@ -10,7 +10,12 @@
<ui:param name="title" value="#{CmsAdminMessages['contentsection.not_found.title']}" /> <ui:param name="title" value="#{CmsAdminMessages['contentsection.not_found.title']}" />
<ui:define name="breadcrumb"> <ui:define name="breadcrumb">
<li class="breadcrumb-item"> <li class="breadcrumb-item">
#{CmsAdminMessages['contentsections.list.label']} <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> </li>
</ui:define> </ui:define>

View File

@ -308,3 +308,22 @@ contentsection.configuration.role_details.members.cols.name=Member Name
contentsection.configuration.role_details.members.cols.actions=Actions contentsection.configuration.role_details.members.cols.actions=Actions
contentsection.configuration.roles.table.actions.remove=Remove contentsection.configuration.roles.table.actions.remove=Remove
contentsection.configuration.roles.role_details.name.edit=Edit contentsection.configuration.roles.role_details.name.edit=Edit
contentsection.configuration.roles.create.dialog.cancel=Cancel
contentsection.configuration.roles.create.dialog.submit=Create new role
contentsection.configuration.roles.create.dialog.title=Create role for content section {0}
contentsection.configuration.roles.create.dialog.rolename.help=Unique name of the role
contentsection.configuration.roles.create.dialog.rolename.label=Name
contentsection.configuration.roles.errors.name_not_empty=The name of a role can't be empty.
contentsection.configuration.roles.errors.name_invalid=The name of a role may only contain the letters a to z, A to Z, numbers, the underscore and the dash.
contentsection.configuration.roles.add.dialog.title=Add roles to content section {0}
contentsection.configuration.roles.add.dialog.cancel=Cancel
contentsection.configuration.roles.add.dialog.submit=Add selected roles
contentsection.role.not_found=Role {0} not found
contentsection.configuration.roles.table.actions.remove.cancel=Cancel
contentsection.configuration.roles.table.actions.remove.submit=Remove role from content section
contentsection.configuration.roles.table.actions.remove.title=Remove role from content section?
contentsection.configuration.roles.table.actions.remove.message=Are you sure to remove the role {0} from content section {1}?
contentsection.configuration.roles.table.actions.delete.cancel=Cancel
contentsection.configuration.roles.table.actions.delete.submit=Delete role
contentsection.configuration.roles.table.actions.delete.title=Confirm role deletion
contentsection.configuration.roles.table.actions.delete.message=Are you sure to remove role {0} from content section {1} and delete it?

View File

@ -309,3 +309,22 @@ contentsection.configuration.role_details.members.cols.name=Name des Mitglieds
contentsection.configuration.role_details.members.cols.actions=Aktionen contentsection.configuration.role_details.members.cols.actions=Aktionen
contentsection.configuration.roles.table.actions.remove=Entfernen contentsection.configuration.roles.table.actions.remove=Entfernen
contentsection.configuration.roles.role_details.name.edit=Bearbeiten contentsection.configuration.roles.role_details.name.edit=Bearbeiten
contentsection.configuration.roles.create.dialog.cancel=Abbrechen
contentsection.configuration.roles.create.dialog.submit=Neue Rolle anlegen
contentsection.configuration.roles.create.dialog.title=Neue Rolle f\u00fcr Content Section {0} anlegen
contentsection.configuration.roles.create.dialog.rolename.help=Eindeutiger Name der Rolle
contentsection.configuration.roles.create.dialog.rolename.label=Name
contentsection.configuration.roles.errors.name_not_empty=Der Name einer Rolle darf nicht leer sein.
contentsection.configuration.roles.errors.name_invalid=Der Name einer Rolle darf nur die Buchstaben a bis z, A bis Z, Ziffern, den Unterstrich und den Bindestrich enthalten.
contentsection.configuration.roles.add.dialog.title=Rollen der Content Section {0} hinzuf\u00fcgen
contentsection.configuration.roles.add.dialog.cancel=Abbrechen
contentsection.configuration.roles.add.dialog.submit=Ausgew\u00e4hlte Rollen hinzuf\u00fcgen
contentsection.role.not_found=Rolle {0} nicht gefunden
contentsection.configuration.roles.table.actions.remove.cancel=Abbrechen
contentsection.configuration.roles.table.actions.remove.submit=Remove role from content section
contentsection.configuration.roles.table.actions.remove.title=Remove role from content section?
contentsection.configuration.roles.table.actions.remove.message=Sind Sie sicher, dass Sie die Rolle {0} aus der Content Section {1} entfernen wollen?
contentsection.configuration.roles.table.actions.delete.cancel=Abbrechen
contentsection.configuration.roles.table.actions.delete.submit=Rolle l\u00f6schen
contentsection.configuration.roles.table.actions.delete.title=Confirm role deletion
contentsection.configuration.roles.table.actions.delete.message=Sind Sie sicher, dass die die Rolle {0} aus der Content Section {1} entfernen und l\u00f6schen wollen?

View File

@ -97,7 +97,7 @@ public class RoleFormController {
) )
); );
} }
if (!roleName.matches("[a-zA-Z0-9_-]")) { if (!roleName.matches("[a-zA-Z0-9_-]*")) {
errors.add( errors.add(
adminMessages.get( adminMessages.get(
"usersgroupsroles.roles.form.errors.name_invalid" "usersgroupsroles.roles.form.errors.name_invalid"

View File

@ -7,9 +7,14 @@
<cc:attribute name="actionTarget" <cc:attribute name="actionTarget"
required="true" required="true"
shortDescription="URL to POST request is send." /> shortDescription="URL to POST request is send." />
<cc:attribute name="buttonClass"
default="danger"
required="false"
shortDescription="Class for the button. Defaults to danger."
type="String" />
<cc:attribute name="buttonText" <cc:attribute name="buttonText"
required="true" required="true"
shortDescription="Text of the button toggleing the modal form." shortDescription="Text of the button toggling the modal form."
type="String" /> type="String" />
<cc:attribute name="buttonTextClass" <cc:attribute name="buttonTextClass"
default="" default=""
@ -45,7 +50,7 @@
<cc:implementation> <cc:implementation>
<div class="#{cc.attrs.buttonTextClass}"> <div class="#{cc.attrs.buttonTextClass}">
<button <button
class="btn btn-danger" class="btn btn-#{cc.attrs.buttonClass}"
data-target="##{cc.attrs.dialogId}" data-target="##{cc.attrs.dialogId}"
data-toggle="modal" data-toggle="modal"
type="button"> type="button">
@ -112,7 +117,7 @@
type="button" > type="button" >
#{cc.attrs.cancelLabel} #{cc.attrs.cancelLabel}
</button> </button>
<button type="submit" class="btn btn-danger"> <button type="submit" class="btn btn-#{cc.attrs.buttonClass}">
#{cc.attrs.confirmLabel} #{cc.attrs.confirmLabel}
</button> </button>
</div> </div>