CCM NG: ContentSectionManager

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4195 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2016-07-13 16:38:26 +00:00
parent 0e291a87b9
commit 2948e65c3a
7 changed files with 454 additions and 58 deletions

View File

@ -131,10 +131,10 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version> <version>3.5.1</version>
<configuration> <configuration>
<source>1.7</source> <source>1.8</source>
<target>1.7</target> <target>1.8</target>
<optimize>true</optimize> <optimize>true</optimize>
<debug>true</debug> <debug>true</debug>
<encoding>${project.build.sourceEncoding}</encoding> <encoding>${project.build.sourceEncoding}</encoding>

View File

@ -23,12 +23,16 @@ import org.libreccm.security.Role;
import org.libreccm.web.CcmApplication; import org.libreccm.web.CcmApplication;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne; import javax.persistence.OneToOne;
import javax.persistence.Table; import javax.persistence.Table;
@ -44,6 +48,16 @@ public class ContentSection extends CcmApplication implements Serializable {
private static final long serialVersionUID = -671718122153931727L; private static final long serialVersionUID = -671718122153931727L;
protected static final String ROOT = "root";
protected static final String ASSETS = "assets";
protected static final String ALERT_RECIPIENT = "alert_recipient";
protected static final String AUTHOR = "author";
protected static final String EDITOR = "editor";
protected static final String MANAGER = "manager";
protected static final String PUBLISHER = "publisher";
protected static final String CONTENT_READER = "content_reader";
@Column(name = "LABEL", length = 512) @Column(name = "LABEL", length = 512)
private String label; private String label;
@ -67,13 +81,16 @@ public class ContentSection extends CcmApplication implements Serializable {
@Column(name = "XML_GENERATOR_CLASS", length = 1024) @Column(name = "XML_GENERATOR_CLASS", length = 1024)
private String xmlGeneratorClass; private String xmlGeneratorClass;
@OneToOne @ManyToMany
@JoinColumn(name = "STAFF_ROLE_ID") @JoinTable(name = "CONTENT_SECTION_ROLES",
private Role staffRole; //ToDo: Check if this is still necessary schema = DB_SCHEMA,
joinColumns = {
@OneToOne @JoinColumn(name = "SECTION_ID")
@JoinColumn(name = "VIEWERS_ROLE_ID") },
private Role viewersRole; //ToDo: Check if this is still necessary inverseJoinColumns = {
@JoinColumn(name = "ROLE_ID")
})
private List<Role> roles;
@Column(name = "DEFAULT_LOCALE") @Column(name = "DEFAULT_LOCALE")
private Locale defaultLocale; private Locale defaultLocale;
@ -134,20 +151,20 @@ public class ContentSection extends CcmApplication implements Serializable {
this.xmlGeneratorClass = xmlGeneratorClass; this.xmlGeneratorClass = xmlGeneratorClass;
} }
public Role getStaffRole() { public List<Role> getRoles() {
return staffRole; return Collections.unmodifiableList(roles);
} }
public void setStaffRole(final Role staffRole) { protected void setRoles(final List<Role> roles) {
this.staffRole = staffRole; this.roles = roles;
} }
public Role getViewersRole() { protected void addRole(final Role role) {
return viewersRole; roles.add(role);
} }
public void setViewersRole(final Role viewersRole) { protected void removeRole(final Role role) {
this.viewersRole = viewersRole; roles.remove(role);
} }
public Locale getDefaultLocale() { public Locale getDefaultLocale() {

View File

@ -0,0 +1,216 @@
/*
* Copyright (C) 2016 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.contentsection;
import org.libreccm.categorization.Category;
import org.libreccm.categorization.CategoryRepository;
import org.libreccm.core.CoreConstants;
import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.PermissionManager;
import org.libreccm.security.RequiresPrivilege;
import org.libreccm.security.Role;
import org.libreccm.security.RoleManager;
import org.libreccm.security.RoleRepository;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
import static org.librecms.CmsConstants.*;
import static org.librecms.contentsection.ContentSection.*;
/**
* Provides several functions for managing content sections.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class ContentSectionManager {
@Inject
private ContentSectionRepository sectionRepo;
@Inject
private CategoryRepository categoryRepo;
@Inject
private RoleRepository roleRepo;
@Inject
private RoleManager roleManager;
@Inject
private PermissionManager permissionManager;
/**
* Creates a new content section including the default roles.
*
* @param name The name of the new content section.
*
* @return The new content section.
*/
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public ContentSection createContentSection(final String name) {
final ContentSection section = new ContentSection();
section.setLabel(name);
final Category rootFolder = new Category();
rootFolder.setName(String.format("%s_root", name));
final Category rootAssetFolder = new Category();
rootFolder.setName(String.format("%s_assets", name));
section.setRootDocumentFolder(rootFolder);
section.setRootAssetsFolder(rootAssetFolder);
sectionRepo.save(section);
categoryRepo.save(rootFolder);
categoryRepo.save(rootAssetFolder);
addRoleToContentSection(section,
String.format("%s_" + ALERT_RECIPIENT, name));
addRoleToContentSection(section,
String.format("%s_" + AUTHOR, name),
PRIVILEGE_ITEMS_CATEGORIZE,
PRIVILEGE_ITEMS_CREATE_NEW,
PRIVILEGE_ITEMS_EDIT,
PRIVILEGE_ITEMS_VIEW_PUBLISHED,
PRIVILEGE_ITEMS_PREVIEW);
addRoleToContentSection(section,
String.format("%s_" + EDITOR, name),
PRIVILEGE_ITEMS_CATEGORIZE,
PRIVILEGE_ITEMS_CREATE_NEW,
PRIVILEGE_ITEMS_EDIT,
PRIVILEGE_ITEMS_APPROVE,
PRIVILEGE_ITEMS_DELETE,
PRIVILEGE_ITEMS_VIEW_PUBLISHED,
PRIVILEGE_ITEMS_PREVIEW);
addRoleToContentSection(section,
String.format("%s_" + MANAGER, name),
PRIVILEGE_ADMINISTER_ROLES,
PRIVILEGE_ADMINISTER_WORKFLOW,
PRIVILEGE_ADMINISTER_LIFECYLES,
PRIVILEGE_ADMINISTER_CATEGORIES,
PRIVILEGE_ADMINISTER_CONTENT_TYPES,
PRIVILEGE_ITEMS_CATEGORIZE,
PRIVILEGE_ITEMS_CREATE_NEW,
PRIVILEGE_ITEMS_EDIT,
PRIVILEGE_ITEMS_APPROVE,
PRIVILEGE_ITEMS_PUBLISH,
PRIVILEGE_ITEMS_DELETE,
PRIVILEGE_ITEMS_VIEW_PUBLISHED,
PRIVILEGE_ITEMS_PREVIEW);
addRoleToContentSection(section,
String.format("%s_" + PUBLISHER, name),
PRIVILEGE_ITEMS_CATEGORIZE,
PRIVILEGE_ITEMS_CREATE_NEW,
PRIVILEGE_ITEMS_EDIT,
PRIVILEGE_ITEMS_APPROVE,
PRIVILEGE_ITEMS_PUBLISH,
PRIVILEGE_ITEMS_DELETE,
PRIVILEGE_ITEMS_VIEW_PUBLISHED,
PRIVILEGE_ITEMS_PREVIEW);
addRoleToContentSection(section,
String.format("%s_" + CONTENT_READER, name),
PRIVILEGE_ITEMS_VIEW_PUBLISHED);
return section;
}
/**
* Renames a content section and all roles associated with it (roles
* starting with the name of the content section).
*
* @param section The section to rename.
*
* @@param name The new name of the content section.
*/
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void renameContentSection(final ContentSection section,
final String name) {
final String oldName = section.getLabel();
section.setLabel(name);
section.getRoles().forEach(r -> renameSectionRole(r, oldName, name));
}
private void renameSectionRole(final Role role,
final String oldName,
final String newName) {
if (role.getName().startsWith(oldName, 0)) {
final String suffix = role.getName().substring(oldName.length());
role.setName(String.join("", newName, suffix));
roleRepo.save(role);
}
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void addRoleToContentSection(final ContentSection section,
final String roleName,
final String... privileges) {
final Role role = new Role();
role.setName(String.join("_", section.getLabel(), roleName));
roleRepo.save(role);
final Category rootFolder = section.getRootDocumentsFolder();
for (String privilege : privileges) {
permissionManager.grantPrivilege(privilege, role, rootFolder);
}
section.addRole(role);
sectionRepo.save(section);
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void removeRoleFromContentSection(
final ContentSection contentSection,
final Role role) {
contentSection.removeRole(role);
sectionRepo.save(contentSection);
roleRepo.delete(role);
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void addTypeToSection(final ContentType type,
final ContentSection section) {
throw new UnsupportedOperationException();
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
public void removeTypeToSection(final ContentType type,
final ContentSection section) {
throw new UnsupportedOperationException();
}
}

View File

@ -19,8 +19,12 @@
package org.librecms.contentsection; package org.librecms.contentsection;
import org.libreccm.core.AbstractEntityRepository; import org.libreccm.core.AbstractEntityRepository;
import org.libreccm.core.CoreConstants;
import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.RequiresPrivilege;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.transaction.Transactional;
/** /**
* *
@ -40,4 +44,20 @@ public class ContentSectionRepository
return section.getObjectId() == 0; return section.getObjectId() == 0;
} }
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
@Override
public void save(final ContentSection section) {
super.save(section);
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
@Transactional(Transactional.TxType.REQUIRED)
@Override
public void delete(final ContentSection section) {
super.delete(section);
}
} }

View File

@ -26,6 +26,7 @@ import org.libreccm.security.Role;
import org.libreccm.web.AbstractCcmApplicationSetup; import org.libreccm.web.AbstractCcmApplicationSetup;
import static org.librecms.CmsConstants.*; import static org.librecms.CmsConstants.*;
import static org.librecms.contentsection.ContentSection.*;
/** /**
* *
@ -45,28 +46,28 @@ public class ContentSectionSetup extends AbstractCcmApplicationSetup {
@Override @Override
public void setup() { public void setup() {
final String contentSectionNames; final String sectionNames;
if (getIntegrationProps().containsKey(INITIAL_CONTENT_SECTIONS)) { if (getIntegrationProps().containsKey(INITIAL_CONTENT_SECTIONS)) {
contentSectionNames = getIntegrationProps().getProperty( sectionNames = getIntegrationProps().getProperty(
INITIAL_CONTENT_SECTIONS); INITIAL_CONTENT_SECTIONS);
} else { } else {
contentSectionNames = "info"; sectionNames = "info";
} }
for (final String contentSectionName : contentSectionNames.split(",")) { for (final String contentSectionName : sectionNames.split(",")) {
createContentSection(contentSectionName); createContentSection(contentSectionName);
} }
} }
private void createContentSection(final String contentSectionName) { private void createContentSection(final String sectionName) {
final ContentSection section = new ContentSection(); final ContentSection section = new ContentSection();
section.setLabel(contentSectionName); section.setLabel(sectionName);
final Category rootFolder = new Category(); final Category rootFolder = new Category();
rootFolder.setName(String.format("%s_root", contentSectionName)); rootFolder.setName(String.format("%s_" + ROOT, sectionName));
final Category rootAssetFolder = new Category(); final Category rootAssetFolder = new Category();
rootFolder.setName(String.format("%s_assets", contentSectionName)); rootFolder.setName(String.format("%s_" + ASSETS, sectionName));
section.setRootDocumentFolder(rootFolder); section.setRootDocumentFolder(rootFolder);
section.setRootAssetsFolder(rootAssetFolder); section.setRootAssetsFolder(rootAssetFolder);
@ -76,17 +77,17 @@ public class ContentSectionSetup extends AbstractCcmApplicationSetup {
getEntityManager().persist(rootAssetFolder); getEntityManager().persist(rootAssetFolder);
final Role alertRecipient = createRole(String.format( final Role alertRecipient = createRole(String.format(
"%s_alert_recipient", contentSectionName)); "%s_" + ALERT_RECIPIENT, sectionName));
final Role author = createRole(String.format("%s_author", final Role author = createRole(String.format("%s_" + AUTHOR,
contentSectionName)); sectionName));
final Role editor = createRole(String.format("%s_editor", final Role editor = createRole(String.format("%s_" + EDITOR,
contentSectionName)); sectionName));
final Role manager = createRole(String.format("%s_manager", final Role manager = createRole(String.format("%s_" + MANAGER,
contentSectionName)); sectionName));
final Role publisher = createRole(String.format("%s_publisher", final Role publisher = createRole(String.format("%s_" + PUBLISHER,
contentSectionName)); sectionName));
final Role contentReader = createRole(String.format("%s_content_reader", final Role contentReader = createRole(String.format(
contentSectionName)); "%s_" + CONTENT_READER, sectionName));
grantPermissions(author, grantPermissions(author,
rootFolder, rootFolder,
@ -122,7 +123,7 @@ public class ContentSectionSetup extends AbstractCcmApplicationSetup {
PRIVILEGE_ITEMS_VIEW_PUBLISHED, PRIVILEGE_ITEMS_VIEW_PUBLISHED,
PRIVILEGE_ITEMS_PREVIEW); PRIVILEGE_ITEMS_PREVIEW);
grantPermissions(editor, grantPermissions(publisher,
rootFolder, rootFolder,
PRIVILEGE_ITEMS_CATEGORIZE, PRIVILEGE_ITEMS_CATEGORIZE,
PRIVILEGE_ITEMS_CREATE_NEW, PRIVILEGE_ITEMS_CREATE_NEW,
@ -134,9 +135,8 @@ public class ContentSectionSetup extends AbstractCcmApplicationSetup {
PRIVILEGE_ITEMS_PREVIEW); PRIVILEGE_ITEMS_PREVIEW);
grantPermissions(contentReader, grantPermissions(contentReader,
rootFolder, rootFolder,
PRIVILEGE_ITEMS_VIEW_PUBLISHED); PRIVILEGE_ITEMS_VIEW_PUBLISHED);
getEntityManager().persist(alertRecipient); getEntityManager().persist(alertRecipient);
getEntityManager().persist(author); getEntityManager().persist(author);

View File

@ -3,18 +3,12 @@
*/ */
package org.librecms; package org.librecms;
import org.librecms.Cms;
import static org.hamcrest.CoreMatchers.*;
import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.ShouldThrowException;
import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.junit.InSequence; import org.jboss.arquillian.junit.InSequence;
import org.jboss.arquillian.persistence.CreateSchema; import org.jboss.arquillian.persistence.CreateSchema;
import org.jboss.arquillian.persistence.PersistenceTest; import org.jboss.arquillian.persistence.PersistenceTest;
import org.jboss.arquillian.persistence.ShouldMatchDataSet;
import org.jboss.arquillian.persistence.UsingDataSet;
import org.jboss.arquillian.transaction.api.annotation.TransactionMode; import org.jboss.arquillian.transaction.api.annotation.TransactionMode;
import org.jboss.arquillian.transaction.api.annotation.Transactional; import org.jboss.arquillian.transaction.api.annotation.Transactional;
import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.ShrinkWrap;
@ -32,13 +26,10 @@ import org.junit.runner.RunWith;
import org.libreccm.tests.categories.IntegrationTest; import org.libreccm.tests.categories.IntegrationTest;
import java.io.File; import java.io.File;
import java.util.List;
import javax.inject.Inject;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext; import javax.persistence.PersistenceContext;
import static org.junit.Assert.*;
@Category(IntegrationTest.class) @Category(IntegrationTest.class)
@RunWith(Arquillian.class) @RunWith(Arquillian.class)

View File

@ -0,0 +1,152 @@
/*
* Copyright (C) 2016 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.contentsection;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.junit.InSequence;
import org.jboss.arquillian.persistence.CreateSchema;
import org.jboss.arquillian.persistence.PersistenceTest;
import org.jboss.arquillian.persistence.ShouldMatchDataSet;
import org.jboss.arquillian.persistence.UsingDataSet;
import org.jboss.arquillian.transaction.api.annotation.TransactionMode;
import org.jboss.arquillian.transaction.api.annotation.Transactional;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.jboss.shrinkwrap.resolver.api.maven.Maven;
import org.jboss.shrinkwrap.resolver.api.maven.PomEquippedResolveStage;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.libreccm.tests.categories.IntegrationTest;
import org.librecms.Cms;
import java.io.File;
import static org.junit.Assert.*;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Category(IntegrationTest.class)
@RunWith(Arquillian.class)
@PersistenceTest
@Transactional(TransactionMode.COMMIT)
@CreateSchema({"create_ccm_cms_schema.sql"})
public class ContentSectionManagerTest {
public ContentSectionManagerTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
@Deployment
public static WebArchive createDeployment() {
final PomEquippedResolveStage pom = Maven
.resolver()
.loadPomFromFile("pom.xml");
final PomEquippedResolveStage dependencies = pom
.importCompileAndRuntimeDependencies();
final File[] libs = dependencies.resolve().withTransitivity().asFile();
for (File lib : libs) {
System.err.printf("Adding file '%s' to test archive...%n",
lib.getName());
}
return ShrinkWrap
.create(WebArchive.class,
"LibreCCM-org.libreccm.cms.CmsTest.war")
.addPackage(Cms.class.getPackage())
.addAsLibraries(libs)
.addAsResource("test-persistence.xml",
"META-INF/persistence.xml")
.addAsWebInfResource("test-web.xml", "WEB-INF/web.xml")
.addAsWebInfResource(EmptyAsset.INSTANCE, "WEB-INF/beans.xml");
}
@Test
@UsingDataSet("datasets/org/librecms/contentsection/"
+ "ContentSectionManagerTest/data.xml")
@ShouldMatchDataSet(
value = "datasets/org/librecms/contentsection/"
+ "ContentSectionManagerTest/after-create.xml",
excludeColumns = {"section_id"})
@InSequence(100)
public void createSection() {
}
@Test
@UsingDataSet("datasets/org/librecms/contentsection/"
+ "ContentSectionManagerTest/data.xml")
@ShouldMatchDataSet(
value = "datasets/org/librecms/contentsection/"
+ "ContentSectionManagerTest/after-rename.xml",
excludeColumns = {"section_id"})
@InSequence(200)
public void renameSection() {
}
@Test
@UsingDataSet("datasets/org/librecms/contentsection/"
+ "ContentSectionManagerTest/data.xml")
@ShouldMatchDataSet(
value = "datasets/org/librecms/contentsection/"
+ "ContentSectionManagerTest/after-add-role.xml",
excludeColumns = {"section_id"})
@InSequence(300)
public void addRole() {
}
@Test
@UsingDataSet("datasets/org/librecms/contentsection/"
+ "ContentSectionManagerTest/data.xml")
@ShouldMatchDataSet(
value = "datasets/org/librecms/contentsection/"
+ "ContentSectionManagerTest/after-remove-role.xml",
excludeColumns = {"section_id"})
@InSequence(300)
public void removeRole() {
}
}