CCM NG: Several things for the installation phase of a module

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4191 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2016-07-06 17:05:00 +00:00
parent 741e0e5dc0
commit 167ca2f9eb
10 changed files with 218 additions and 46 deletions

View File

@ -21,6 +21,23 @@ public class Cms implements CcmModule {
@Override @Override
public void install(final InstallEvent event) { public void install(final InstallEvent event) {
//ToDo Create initial data for the module if neccessary //ToDo Create initial data for the module if neccessary
// Create initial content section
// If a list of sections is provided in the integration properties
// use that list, otherwise create a content section named 'info'.
// Map given domains to content section(s)
// Also create the following roles for each content section and assign
// the permissions
//
// * Alert Recipient
// * Author : Categorize Items, Create New Items, Edit Items, View Published Items, Preview Items
// * Editor : Categorize Items, Create New Items, Edit Items, Approve Items, Delete Items, View Published Items, Preview Items
// * Manager : Administer Roles, Administer Workflow, Administer Lifecycles, Administer Categories, Administer Content Types, Categorize Items, Create New Items, Edit Items, Approve Items, Publish Items, Delete Items, View Published Items, Preview Items
// * Publisher : Categorize Items, Create New Items, Edit Items, Approve Items, Publish Items, Delete Items, View Published Items, Preview Items
// * [Thrusted User]: Categorize Items, Create New Items, Edit Items, Apply Alternate Workflows, Approve Items, Publish Items, Delete Items, View Published Items, Preview Items
// * Content Reader: View Published Items
} }
@Override @Override

View File

@ -69,11 +69,11 @@ public class ContentSection extends CcmApplication implements Serializable {
@OneToOne @OneToOne
@JoinColumn(name = "STAFF_ROLE_ID") @JoinColumn(name = "STAFF_ROLE_ID")
private Role staffRole; private Role staffRole; //ToDo: Check if this is still necessary
@OneToOne @OneToOne
@JoinColumn(name = "VIEWERS_ROLE_ID") @JoinColumn(name = "VIEWERS_ROLE_ID")
private Role viewersRole; private Role viewersRole; //ToDo: Check if this is still necessary
@Column(name = "DEFAULT_LOCALE") @Column(name = "DEFAULT_LOCALE")
private Locale defaultLocale; private Locale defaultLocale;

View File

@ -18,6 +18,7 @@
*/ */
package org.libreccm.categorization; package org.libreccm.categorization;
import static org.libreccm.categorization.CategorizationConstants.*;
import static org.libreccm.core.CoreConstants.*; import static org.libreccm.core.CoreConstants.*;
import org.hibernate.validator.constraints.NotBlank; import org.hibernate.validator.constraints.NotBlank;
@ -48,6 +49,9 @@ import javax.persistence.NamedSubgraph;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import javax.validation.constraints.Pattern; import javax.validation.constraints.Pattern;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
/** /**
* The category entity represents a single category. Each category is part of a * The category entity represents a single category. Each category is part of a
@ -91,6 +95,7 @@ import javax.validation.constraints.Pattern;
) )
}) })
@DefaultEntityGraph("Category.withSubCategoriesAndObjects") @DefaultEntityGraph("Category.withSubCategoriesAndObjects")
@XmlRootElement(name = "category", namespace = CAT_XML_NS)
public class Category extends CcmObject implements InheritsPermissions, public class Category extends CcmObject implements InheritsPermissions,
Serializable { Serializable {
@ -101,6 +106,7 @@ public class Category extends CcmObject implements InheritsPermissions,
* category system/domain is used in different installations. * category system/domain is used in different installations.
*/ */
@Column(name = "UNIQUE_ID") @Column(name = "UNIQUE_ID")
@XmlElement(name = "unique-id", namespace = CAT_XML_NS)
private String uniqueId; private String uniqueId;
/** /**
@ -110,6 +116,7 @@ public class Category extends CcmObject implements InheritsPermissions,
@Column(name = "NAME", nullable = false) @Column(name = "NAME", nullable = false)
@NotBlank @NotBlank
@Pattern(regexp = "[\\w-.]*") @Pattern(regexp = "[\\w-.]*")
@XmlElement(name ="name", namespace = CAT_XML_NS)
private String name; private String name;
/** /**
@ -123,6 +130,7 @@ public class Category extends CcmObject implements InheritsPermissions,
joinColumns = { joinColumns = {
@JoinColumn(name = "OBJECT_ID")} @JoinColumn(name = "OBJECT_ID")}
)) ))
@XmlElementWrapper(name = "title", namespace = CAT_XML_NS)
private LocalizedString title; private LocalizedString title;
/** /**
@ -136,6 +144,7 @@ public class Category extends CcmObject implements InheritsPermissions,
joinColumns = { joinColumns = {
@JoinColumn(name = "OBJECT_ID")} @JoinColumn(name = "OBJECT_ID")}
)) ))
@XmlElementWrapper(name = "title", namespace = CAT_XML_NS)
private LocalizedString description; private LocalizedString description;
/** /**
@ -143,6 +152,7 @@ public class Category extends CcmObject implements InheritsPermissions,
* enabled, the category can't be used in any way. * enabled, the category can't be used in any way.
*/ */
@Column(name = "ENABLED") @Column(name = "ENABLED")
@XmlElement(name = "enabled", namespace = CAT_XML_NS)
private boolean enabled; private boolean enabled;
/** /**
@ -150,6 +160,7 @@ public class Category extends CcmObject implements InheritsPermissions,
* visible should be only visible in the backend but not in the frontend. * visible should be only visible in the backend but not in the frontend.
*/ */
@Column(name = "VISIBLE") @Column(name = "VISIBLE")
@XmlElement(name = "visible", namespace = CAT_XML_NS)
private boolean visible; private boolean visible;
/** /**
@ -157,18 +168,21 @@ public class Category extends CcmObject implements InheritsPermissions,
* an abstract category. * an abstract category.
*/ */
@Column(name = "ABSTRACT_CATEGORY") @Column(name = "ABSTRACT_CATEGORY")
@XmlElement(name = "abstract", namespace = CAT_XML_NS)
private boolean abstractCategory; private boolean abstractCategory;
/** /**
* The objects assigned to this category. * The objects assigned to this category.
*/ */
@OneToMany(mappedBy = "category") @OneToMany(mappedBy = "category")
@XmlElementWrapper(name = "objects", namespace = CAT_XML_NS)
private List<Categorization> objects; private List<Categorization> objects;
/** /**
* The sub categories of this category. * The sub categories of this category.
*/ */
@OneToMany(mappedBy = "parentCategory") @OneToMany(mappedBy = "parentCategory")
@XmlElementWrapper(name = "subcategories", namespace = CAT_XML_NS)
private List<Category> subCategories; private List<Category> subCategories;
/** /**
@ -183,6 +197,7 @@ public class Category extends CcmObject implements InheritsPermissions,
* Numeric value to define the order of the categories. * Numeric value to define the order of the categories.
*/ */
@Column(name = "CATEGORY_ORDER") @Column(name = "CATEGORY_ORDER")
@XmlElement(name = "order", namespace = CAT_XML_NS)
private long categoryOrder; private long categoryOrder;
public Category() { public Category() {

View File

@ -74,8 +74,6 @@ public class CcmCore implements CcmModule {
@Override @Override
public void install(final InstallEvent event) { public void install(final InstallEvent event) {
// final EntityManager entityManager = event.getEntityManager();
final SystemUsersSetup systemUsersSetup = new SystemUsersSetup( final SystemUsersSetup systemUsersSetup = new SystemUsersSetup(
event); event);
systemUsersSetup.setupSystemUsers(); systemUsersSetup.setupSystemUsers();
@ -87,6 +85,9 @@ public class CcmCore implements CcmModule {
final LoginApplicationSetup loginSetup final LoginApplicationSetup loginSetup
= new LoginApplicationSetup(event); = new LoginApplicationSetup(event);
loginSetup.setup(); loginSetup.setup();
// Load category domains from bundle/classpath
// File format: JAXB (but Jackson for reading the XML)
} }
@Override @Override

View File

@ -37,6 +37,12 @@ public final class CoreConstants {
*/ */
public static final String DB_SCHEMA = "CCM_CORE"; public static final String DB_SCHEMA = "CCM_CORE";
/**
* Fully qualified name of file containing the integration properties of a
* bundle.
*/
public static final String INTEGRATION_PROPS = "/integration.properties";
/** /**
* String used as display name for the virtual <i>Access denied</i> objects * String used as display name for the virtual <i>Access denied</i> objects
* in the security API. * in the security API.

View File

@ -31,6 +31,7 @@ import org.libreccm.configuration.LongSetting;
import org.libreccm.configuration.Setting; import org.libreccm.configuration.Setting;
import org.libreccm.configuration.StringListSetting; import org.libreccm.configuration.StringListSetting;
import org.libreccm.configuration.StringSetting; import org.libreccm.configuration.StringSetting;
import org.libreccm.core.CoreConstants;
import org.libreccm.l10n.LocalizedString; import org.libreccm.l10n.LocalizedString;
import java.io.IOException; import java.io.IOException;
@ -43,8 +44,6 @@ import java.util.Properties;
import java.util.Set; import java.util.Set;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.transaction.Transaction;
/** /**
* A helper class used by the {@link ModuleManager} to load the initial * A helper class used by the {@link ModuleManager} to load the initial
@ -74,7 +73,7 @@ class ConfigurationLoader {
integration = new Properties(); integration = new Properties();
try (final InputStream inputStream = getClass().getResourceAsStream( try (final InputStream inputStream = getClass().getResourceAsStream(
"/integration.properties")) { CoreConstants.INTEGRATION_PROPS)) {
if (inputStream == null) { if (inputStream == null) {
LOGGER.warn("No integration properties found. Using empty " LOGGER.warn("No integration properties found. Using empty "

View File

@ -96,6 +96,10 @@ public class ModuleManager {
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void initModules() { public void initModules() {
LOGGER.info("Initalising modules..."); LOGGER.info("Initalising modules...");
final ConfigurationLoader confLoader = new ConfigurationLoader(
entityManager);
//Initialise all modules in the correct order //Initialise all modules in the correct order
for (final TreeNode node : moduleNodes) { for (final TreeNode node : moduleNodes) {
@ -111,6 +115,7 @@ public class ModuleManager {
if (installedModule != null if (installedModule != null
&& installedModule.getStatus() == ModuleStatus.NEW) { && installedModule.getStatus() == ModuleStatus.NEW) {
node.getModule().install(installEvent); node.getModule().install(installEvent);
confLoader.loadConfigurations(node.getModule());
installedModule.setStatus(ModuleStatus.INSTALLED); installedModule.setStatus(ModuleStatus.INSTALLED);
entityManager.merge(installedModule); entityManager.merge(installedModule);
} }

View File

@ -0,0 +1,77 @@
/*
* 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.libreccm.security;
import org.libreccm.core.CcmObject;
import org.libreccm.web.AbstractCcmApplicationSetup;
import javax.persistence.EntityManager;
/**
* A helper class used by the {@link AbstractCcmApplicationSetup} to create
* roles and permissions for the roles. This class is necessary because some
* constructors and methods of the classes {@link Role} and {@link Permission}
* are only accessible from this package.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ApplicationRoleSetup {
private final EntityManager entityManager;
public ApplicationRoleSetup(final EntityManager entityManager) {
this.entityManager = entityManager;
}
public Role createRole(final String name) {
final Role role = new Role();
role.setName(name);
entityManager.persist(role);
return role;
}
private Permission createPermission(final Role role, final String privilege) {
final Permission permission = new Permission();
permission.setGrantedPrivilege(privilege);
permission.setGrantee(role);
role.addPermission(permission);
return permission;
}
public void grantPermission(final Role role, final String privilege) {
final Permission permission = createPermission(role, privilege);
entityManager.persist(permission);
entityManager.merge(role);
}
public void grantPermission(final Role role,
final String privilege,
final CcmObject ccmObject) {
final Permission permission = createPermission(role, privilege);
permission.setObject(ccmObject);
entityManager.persist(privilege);
entityManager.merge(role);
}
}

View File

@ -21,6 +21,7 @@ package org.libreccm.security;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.libreccm.core.CcmCore; import org.libreccm.core.CcmCore;
import org.libreccm.core.CoreConstants;
import org.libreccm.core.EmailAddress; import org.libreccm.core.EmailAddress;
import org.libreccm.modules.InstallEvent; import org.libreccm.modules.InstallEvent;
@ -41,6 +42,12 @@ public class SystemUsersSetup {
private static final Logger LOGGER = LogManager.getLogger( private static final Logger LOGGER = LogManager.getLogger(
SystemUsersSetup.class); SystemUsersSetup.class);
private static final String ADMIN_NAME = "admin.name";
private static final String ADMIN_FAMILY_NAME = "admin.family_name";
private static final String ADMIN_GIVEN_NAME = "admin.given_name";
private static final String ADMIN_EMAIL_ADDRESS = "admin.email_address";
private static final String ADMIN_PASSWORD = "admin.password";
//Default password is "libreccm" //Default password is "libreccm"
private static final String DEFAULT_ADMIN_PW private static final String DEFAULT_ADMIN_PW
= "$shiro1$SHA-512$500000$MFPkVikNoRrBZ8R8CxQIHA==$ybEECtSPukmXDbV27a3LnWktFsh9lQl2ZYqCUtV0NF9G35Rt0+Tzp1msNLBQUVv15SrsdFgBSfhgWfZFyTva+Q=="; = "$shiro1$SHA-512$500000$MFPkVikNoRrBZ8R8CxQIHA==$ybEECtSPukmXDbV27a3LnWktFsh9lQl2ZYqCUtV0NF9G35Rt0+Tzp1msNLBQUVv15SrsdFgBSfhgWfZFyTva+Q==";
@ -59,41 +66,26 @@ public class SystemUsersSetup {
private void createAdmin() { private void createAdmin() {
LOGGER.info("Creating admin user..."); LOGGER.info("Creating admin user...");
final User admin = new User();
admin.setName("admin");
admin.setFamilyName("LibreCCM");
admin.setGivenName("System Administrator");
final EmailAddress adminEmail = new EmailAddress();
adminEmail.setAddress("admin@libreccm.example");
admin.setPrimaryEmailAddress(adminEmail);
String adminPassword = DEFAULT_ADMIN_PW; final Properties integrationProps = getIntegrationProps();
try (final InputStream inputStream = getClass().getResourceAsStream( final String adminName = integrationProps.getProperty(ADMIN_NAME,
"/integration.properties")) { "admin");
if (inputStream == null) { final String adminFamilyName = integrationProps.getProperty(
LOGGER.warn( ADMIN_FAMILY_NAME, "LibreCCM");
"No integration.properties file found. Using default " final String adminGivenName = integrationProps.getProperty(
+ "password (see documentation)"); ADMIN_GIVEN_NAME, "System Administrator");
} else { final String adminEmailAddress = integrationProps.getProperty(
final Properties properties = new Properties(); ADMIN_EMAIL_ADDRESS, "admin@libreccm.example");
try { final String adminPassword = integrationProps.getProperty(
properties.load(inputStream); ADMIN_PASSWORD, DEFAULT_ADMIN_PW);;
final String password = properties.getProperty(
"admin.password"); final User admin = new User();
if (password != null && !password.isEmpty()) { admin.setName(adminName);
adminPassword = password; admin.setFamilyName(adminFamilyName);
} admin.setGivenName(adminGivenName);
} catch (IOException ex) { final EmailAddress adminEmail = new EmailAddress();
LOGGER.warn("Failed to load integration.properties. " adminEmail.setAddress(adminEmailAddress);
+ "Using default password.", admin.setPrimaryEmailAddress(adminEmail);
ex);
}
}
} catch (IOException ex) {
LOGGER.warn("Exception while reading integration.properties file."
+ "Using default password for admin account. ",
ex);
}
admin.setPassword(adminPassword); admin.setPassword(adminPassword);
final Role adminRole = new Role(); final Role adminRole = new Role();
@ -128,4 +120,20 @@ public class SystemUsersSetup {
entityManager.persist(user); entityManager.persist(user);
} }
private Properties getIntegrationProps() {
try (final InputStream inputStream = getClass().getResourceAsStream(
CoreConstants.INTEGRATION_PROPS)) {
final Properties properties = new Properties();
if (inputStream == null) {
LOGGER.warn("No integration properties available.");
properties.load(inputStream);
}
return properties;
} catch (IOException ex) {
LOGGER.warn("Failed to load integration properties from bundle. "
+ "Using empty integration properties.", ex);
return new Properties();
}
}
} }

View File

@ -18,7 +18,18 @@
*/ */
package org.libreccm.web; package org.libreccm.web;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.core.CcmObject;
import org.libreccm.core.CoreConstants;
import org.libreccm.modules.InstallEvent; import org.libreccm.modules.InstallEvent;
import org.libreccm.security.ApplicationRoleSetup;
import org.libreccm.security.Permission;
import org.libreccm.security.Role;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
@ -28,16 +39,49 @@ import javax.persistence.EntityManager;
*/ */
public abstract class AbstractCcmApplicationSetup { public abstract class AbstractCcmApplicationSetup {
private static final Logger LOGGER = LogManager.getLogger(
AbstractCcmApplicationSetup.class);
private final EntityManager entityManager; private final EntityManager entityManager;
private final ApplicationRoleSetup appRoleSetup;
public AbstractCcmApplicationSetup(final InstallEvent event) { public AbstractCcmApplicationSetup(final InstallEvent event) {
this.entityManager = event.getEntityManager(); this.entityManager = event.getEntityManager();
appRoleSetup = new ApplicationRoleSetup(entityManager);
} }
protected EntityManager getEntityManager() { protected EntityManager getEntityManager() {
return entityManager; return entityManager;
} }
protected Properties getIntegrationProps() {
try (InputStream inputStream = getClass().getResourceAsStream(
CoreConstants.INTEGRATION_PROPS)) {
final Properties properties = new Properties();
properties.load(inputStream);
return properties;
} catch (IOException ex) {
LOGGER.warn(
"Failed to load integration properties. Using empty properties.",
ex);
return new Properties();
}
}
public Role createRole(final String name) {
return appRoleSetup.createRole(name);
}
public void grantPermission(final Role role, final String privilege) {
appRoleSetup.grantPermission(role, privilege);
}
public void grantPermission(final Role role,
final String privilege,
final CcmObject ccmObject) {
appRoleSetup.grantPermission(role, privilege, ccmObject);
}
public abstract void setup(); public abstract void setup();
} }