. Refactoring of Invite Users to support inviting users into an existing Web Project space

- Added new Invite Website Users action
 - Content Managers can now invite additional users into the Web Project and sandboxes created for them
 - Refactoring of old-skool Invite Content/Space Users wizard beans to new style wizard framework beans
 - TODO: refactor JSPs to complement new beans
. User Sandbox creation code refactoring into a SandboxFactory helper so various wizards can utilise it
. Workflow selection lists now show workflow 'title' human-readable label instead of 'name' identifier field

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@4433 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2006-11-23 16:08:51 +00:00
parent edd6d29cf4
commit 5d18c75e08
13 changed files with 674 additions and 616 deletions

View File

@@ -851,6 +851,18 @@ create_website_step5_desc=Notify the invited users.
create_website_finish_instruction=To close this wizard and create your web project space click Finish. To review or change your selections click Back. create_website_finish_instruction=To close this wizard and create your web project space click Finish. To review or change your selections click Back.
create_website_summary_users=Users and Roles create_website_summary_users=Users and Roles
# Invite web users wizard messages
manage_invited_users=Manage Website Users
invite_website_users=Invite Website Users
invite_webusers_title=Invite Website Users
invite_webusers_desc=Invite new users and create sandboxes for the web project.
invite_webusers_step1_title=Step One - Invite Users
invite_webusers_step1_desc=Select users and their roles.
invite_webusers_step2_title=Step Two - Notify Users
invite_webusers_step2_desc=Notify the invited users.
invite_webusers_finish_instruction=To close the wizard and create the user sandboxes click Finish. To review or change your selections click Back.
invite_webusers_summary_users=Users and Roles
# Delete Website Dialog messages # Delete Website Dialog messages
delete_website=Delete Web Project delete_website=Delete Web Project
delete_website_info=To remove this web project and all associated user sandboxes, click OK. delete_website_info=To remove this web project and all associated user sandboxes, click OK.

View File

@@ -187,6 +187,21 @@
</params> </params>
</action> </action>
<!-- Invite Website Users -->
<action id="invite_website_users">
<permissions>
<permission allow="true">ChangePermissions</permission>
</permissions>
<label-id>invite_website_users</label-id>
<image>/images/icons/invite.gif</image>
<action>wizard:inviteWebUsers</action>
<!-- TODO: change this to setup avmstore prop on wizard -->
<action-listener>#{BrowseBean.setupSpaceAction}</action-listener>
<params>
<param name="id">#{actionContext.id}</param>
</params>
</action>
<!-- Actions for a file in the AVM Browse screen --> <!-- Actions for a file in the AVM Browse screen -->
<action-group id="avm_file_browse"> <action-group id="avm_file_browse">
@@ -269,6 +284,7 @@
<action idref="copy_node" /> <action idref="copy_node" />
<action idref="delete_space" /> <action idref="delete_space" />
<action idref="take_ownership_space" /> <action idref="take_ownership_space" />
<action idref="invite_website_users" />
<action idref="run_action" /> <action idref="run_action" />
</action-group> </action-group>
@@ -276,7 +292,7 @@
<action-group id="browse_website_menu"> <action-group id="browse_website_menu">
<action idref="details_space" /> <action idref="details_space" />
<action idref="delete_space" /> <action idref="delete_space" />
<!--<action idref="manage_space_users" />--> <action idref="invite_website_users" />
</action-group> </action-group>
</actions> </actions>

View File

@@ -1,12 +1,12 @@
<alfresco-config> <alfresco-config>
<config> <config>
<wizard-container>/jsp/wizard/container.jsp</wizard-container> <wizard-container>/jsp/wizard/container.jsp</wizard-container>
<wizards> <wizards>
<!-- Definition of a create website wizard --> <!-- Definition of a create website wizard -->
<wizard name="createWebsite" managed-bean="CreateWebsiteWizard" <wizard name="createWebsite" managed-bean="CreateWebsiteWizard"
title-id="create_website_title" description-id="create_website_desc" title-id="create_website_title" description-id="create_website_desc"
icon="/images/icons/create_website_large.gif"> icon="/images/icons/create_website_large.gif">
<step name="details" title-id="website_details" description-id="create_website_step1_desc"> <step name="details" title-id="website_details" description-id="create_website_step1_desc">
@@ -47,7 +47,31 @@
</step> </step>
</wizard> </wizard>
<!-- Definition of an advanced space wizard --> <!-- Definition of a Invite Website Users wizard -->
<wizard name="inviteWebUsers" managed-bean="InviteWebsiteUsersWizard"
title-id="invite_webusers_title" description-id="invite_webusers_desc"
icon="/images/icons/users_large.gif">
<step name="invite" title-id="website_invite" description-id="invite_webusers_step1_desc">
<page path="/jsp/wcm/create-website-wizard/invite.jsp"
title-id="invite_webusers_step1_title"
description-id="invite_webusers_step1_desc"
instruction-id="default_instruction" />
</step>
<step name="notify" title-id="website_notify" description-id="invite_webusers_step2_desc">
<page path="/jsp/wcm/create-website-wizard/notify.jsp"
title-id="invite_webusers_step2_title"
description-id="invite_webusers_step2_desc"
instruction-id="default_instruction" />
</step>
<step name="summary" title-id="summary" description-id="summary_step_description">
<page path="/jsp/wizard/summary.jsp"
title-id="summary"
description-id="summary_desc"
instruction-id="invite_webusers_finish_instruction" />
</step>
</wizard>
<!-- Definition of an advanced space wizard -->
<wizard name="createSpace" managed-bean="CreateSpaceWizard" <wizard name="createSpace" managed-bean="CreateSpaceWizard"
title-id="create_space_title" description-id="create_space_desc" title-id="create_space_title" description-id="create_space_desc"
icon="/images/icons/create_space_large.gif"> icon="/images/icons/create_space_large.gif">
@@ -238,30 +262,27 @@
</wizard> </wizard>
<!-- Definition of the Create XML Type wizard --> <!-- Definition of the Create XML Type wizard -->
<wizard name="createForm" <wizard name="createForm" managed-bean="CreateFormWizard"
managed-bean="CreateFormWizard" title-id="create_form_title" description-id="create_form_desc"
title-id="create_form_title"
description-id="create_form_desc"
icon="/images/icons/new_content_large.gif"> icon="/images/icons/new_content_large.gif">
<step name="form_details" <step name="form_details" title-id="create_form_form_details_title"
title-id="create_form_form_details_title" description-id="create_form_form_details_desc">
description-id="create_form_form_details_desc">
<page path="/jsp/wcm/create-form-wizard/details.jsp" <page path="/jsp/wcm/create-form-wizard/details.jsp"
title-id="create_form_form_details_title" title-id="create_form_form_details_title"
description-id="create_form_form_details_desc" description-id="create_form_form_details_desc"
instruction-id="default_instruction" /> instruction-id="default_instruction" />
</step> </step>
<step name="configure_rendering_engine_templates" <step name="configure_rendering_engine_templates"
title-id="create_form_configure_rendering_engine_templates_title" title-id="create_form_configure_rendering_engine_templates_title"
description-id="create_form_configure_rendering_engine_templates_desc"> description-id="create_form_configure_rendering_engine_templates_desc">
<page path="/jsp/wcm/create-form-wizard/configure-rendering-engines.jsp" <page path="/jsp/wcm/create-form-wizard/configure-rendering-engines.jsp"
title-id="create_form_configure_rendering_engine_templates_title" title-id="create_form_configure_rendering_engine_templates_title"
description-id="create_form_configure_rendering_engine_templates_desc" description-id="create_form_configure_rendering_engine_templates_desc"
instruction-id="default_instruction" /> instruction-id="default_instruction" />
</step> </step>
<step name="select_default_workflow" <step name="select_default_workflow"
title-id="create_form_select_default_workflow_title" title-id="create_form_select_default_workflow_title"
description-id="create_form_select_default_workflow_desc"> description-id="create_form_select_default_workflow_desc">
<page path="/jsp/wcm/create-form-wizard/select-default-workflow.jsp" <page path="/jsp/wcm/create-form-wizard/select-default-workflow.jsp"
title-id="create_form_select_default_workflow_title" title-id="create_form_select_default_workflow_title"
description-id="create_form_select_default_workflow_desc" description-id="create_form_select_default_workflow_desc"

View File

@@ -36,21 +36,16 @@ import javax.faces.model.ListDataModel;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.workflow.WorkflowDefinition; import org.alfresco.service.cmr.workflow.WorkflowDefinition;
import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
import org.alfresco.web.app.AlfrescoNavigationHandler; import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.app.Application; import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.FacesHelper; import org.alfresco.web.app.servlet.FacesHelper;
@@ -68,6 +63,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
/** /**
* Backing bean for the Create Web Project wizard.
*
* @author Kevin Roast * @author Kevin Roast
*/ */
public class CreateWebsiteWizard extends BaseWizardBean public class CreateWebsiteWizard extends BaseWizardBean
@@ -80,8 +77,6 @@ public class CreateWebsiteWizard extends BaseWizardBean
private static final String MSG_FORM_SUMMARY = "website_form_summary"; private static final String MSG_FORM_SUMMARY = "website_form_summary";
private static final String MSG_NONE = "value_not_set"; private static final String MSG_NONE = "value_not_set";
private static final String ROLE_CONTENT_MANAGER = "ContentManager";
private static final String WEBAPP_DEFAULT = "ROOT"; private static final String WEBAPP_DEFAULT = "ROOT";
private static Log logger = LogFactory.getLog(CreateWebsiteWizard.class); private static Log logger = LogFactory.getLog(CreateWebsiteWizard.class);
@@ -95,7 +90,6 @@ public class CreateWebsiteWizard extends BaseWizardBean
private String websitesFolderId = null; private String websitesFolderId = null;
protected AVMService avmService; protected AVMService avmService;
protected PermissionService permissionService;
protected WorkflowService workflowService; protected WorkflowService workflowService;
/** datamodel for table of selected forms */ /** datamodel for table of selected forms */
@@ -144,7 +138,7 @@ public class CreateWebsiteWizard extends BaseWizardBean
// init the dependant bean we are using for the invite users pages // init the dependant bean we are using for the invite users pages
InviteWebsiteUsersWizard wiz = getInviteUsersWizard(); InviteWebsiteUsersWizard wiz = getInviteUsersWizard();
wiz.init(); wiz.init(null);
} }
/** /**
@@ -177,58 +171,18 @@ public class CreateWebsiteWizard extends BaseWizardBean
String webapp = (this.webapp != null && this.webapp.length() != 0) ? this.webapp : WEBAPP_DEFAULT; String webapp = (this.webapp != null && this.webapp.length() != 0) ? this.webapp : WEBAPP_DEFAULT;
this.nodeService.setProperty(nodeRef, ContentModel.PROP_DEFAULTWEBAPP, webapp); this.nodeService.setProperty(nodeRef, ContentModel.PROP_DEFAULTWEBAPP, webapp);
// call the delegate wizard bean to provide invite user functionality // call a delegate wizard bean to provide invite user functionality
InviteWebsiteUsersWizard wiz = getInviteUsersWizard(); InviteWebsiteUsersWizard wiz = getInviteUsersWizard();
wiz.setNode(new Node(nodeRef)); wiz.setNode(new Node(nodeRef));
wiz.setAvmStore(avmStore);
wiz.setStandalone(false);
// the wizard is responsible for notifying the invited users, setting the appropriate
// node permissions and also for creating user sandboxes and associations to the web folder node
outcome = wiz.finish(); outcome = wiz.finish();
if (outcome != null) if (outcome != null)
{ {
// create a sandbox for each user appropriately with permissions based on role
// build a list of managers who will have full permissions on ALL staging areas
List<String> managers = new ArrayList<String>(4);
boolean foundCurrentUser = false;
List<UserGroupRole> invitedUserRoles = (List<UserGroupRole>)wiz.getUserRolesDataModel().getWrappedData();
String currentUser = Application.getCurrentUser(context).getUserName();
for (UserGroupRole userRole : invitedUserRoles)
{
String authority = userRole.getAuthority();
if (currentUser.equals(authority))
{
foundCurrentUser = true;
}
if (ROLE_CONTENT_MANAGER.equals(userRole.getRole()))
{
managers.add(authority);
}
}
if (foundCurrentUser == false)
{
invitedUserRoles.add(new UserGroupRole(currentUser, ROLE_CONTENT_MANAGER, null));
managers.add(currentUser);
}
// build the sandboxes now we have the manager list and complete user list
for (UserGroupRole userRole : invitedUserRoles)
{
createUserSandbox(avmStore, managers, userRole.getAuthority(), userRole.getRole());
}
// create the AVM stores to represent the newly created location website // create the AVM stores to represent the newly created location website
createStagingSandbox(avmStore, managers); SandboxFactory.createStagingSandbox(avmStore, wiz.getManagers());
// save the list of invited users against the store
for (UserGroupRole userRole : invitedUserRoles)
{
// create an app:webuser instance for each authority and assoc to the website node
Map<QName, Serializable> props = new HashMap<QName, Serializable>(2, 1.0f);
props.put(ContentModel.PROP_WEBUSERNAME, userRole.getAuthority());
props.put(ContentModel.PROP_WEBUSERROLE, userRole.getRole());
this.nodeService.createNode(nodeRef,
ContentModel.ASSOC_WEBUSER,
ContentModel.ASSOC_WEBUSER,
ContentModel.TYPE_WEBUSER,
props);
}
// set the property on the node to reference the AVM store // set the property on the node to reference the AVM store
this.nodeService.setProperty(nodeRef, ContentModel.PROP_AVMSTORE, avmStore); this.nodeService.setProperty(nodeRef, ContentModel.PROP_AVMSTORE, avmStore);
@@ -383,14 +337,6 @@ public class CreateWebsiteWizard extends BaseWizardBean
this.avmService = avmService; this.avmService = avmService;
} }
/**
* @param permissionService The permissionService to set.
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/** /**
* @param workflowService The WorkflowService to set. * @param workflowService The WorkflowService to set.
*/ */
@@ -508,7 +454,8 @@ public class CreateWebsiteWizard extends BaseWizardBean
} }
if (foundCurrentUser == false) if (foundCurrentUser == false)
{ {
buf.append(getInviteUsersWizard().buildLabelForUserAuthorityRole(currentUser, ROLE_CONTENT_MANAGER)); buf.append(getInviteUsersWizard().buildLabelForUserAuthorityRole(
currentUser, SandboxFactory.ROLE_CONTENT_MANAGER));
} }
return buildSummary( return buildSummary(
@@ -686,7 +633,7 @@ public class CreateWebsiteWizard extends BaseWizardBean
for (WorkflowDefinition workflowDef : workflowDefs) for (WorkflowDefinition workflowDef : workflowDefs)
{ {
UIListItem item = new UIListItem(); UIListItem item = new UIListItem();
item.setValue(workflowDef.id); item.setValue(workflowDef);
item.setLabel(workflowDef.title); item.setLabel(workflowDef.title);
item.setDescription(workflowDef.description); item.setDescription(workflowDef.description);
item.setImage(WebResources.IMAGE_WORKFLOW_32); item.setImage(WebResources.IMAGE_WORKFLOW_32);
@@ -705,8 +652,8 @@ public class CreateWebsiteWizard extends BaseWizardBean
int index = selectList.getRowIndex(); int index = selectList.getRowIndex();
if (index != -1) if (index != -1)
{ {
String workflow = (String)this.workflowsList.get(index).getValue(); WorkflowDefinition workflow = (WorkflowDefinition)this.workflowsList.get(index).getValue();
this.workflows.add(this.new WorkflowWrapper(workflow)); this.workflows.add(new WorkflowWrapper(workflow.getId(), workflow.getTitle()));
} }
} }
@@ -770,237 +717,6 @@ public class CreateWebsiteWizard extends BaseWizardBean
return this.websitesFolderId; return this.websitesFolderId;
} }
/**
* Create the staging sandbox for the named store.
*
* A staging sandbox is comprised of two stores, the first named 'storename-staging' with a
* preview store named 'storename-preview' layered over the staging store.
*
* Various store meta-data properties are set including:
* Identifier for store-types: .sandbox.staging.main and .sandbox.staging.preview
* Store-id: .sandbox-id.<guid> (unique across all stores in the sandbox)
* DNS: .dns.<store> = <path-to-webapps-root>
* Website Name: .website.name = website name
*
* @param name The store name to create the sandbox for
* @param managers The list of authorities who have ContentManager role in the website
*/
private void createStagingSandbox(String name, List<String> managers)
{
// create the 'staging' store for the website
String stagingStore = AVMConstants.buildAVMStagingStoreName(name);
this.avmService.createAVMStore(stagingStore);
if (logger.isDebugEnabled())
logger.debug("Created staging sandbox store: " + stagingStore);
// create the system directories 'appBase' and 'avm_webapps'
String path = stagingStore + ":/";
//this.fileFolderService.create(AVMNodeConverter.ToNodeRef(-1, path), AVMConstants.DIR_APPBASE, ContentModel.TYPE_AVM_PLAIN_FOLDER);
this.avmService.createDirectory(path, AVMConstants.DIR_APPBASE);
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, path + '/' + AVMConstants.DIR_APPBASE);
for (String manager : managers)
{
this.permissionService.setPermission(dirRef, manager, ROLE_CONTENT_MANAGER, true);
}
path += AVMConstants.DIR_APPBASE;
//this.fileFolderService.create(AVMNodeConverter.ToNodeRef(-1, path), AVMConstants.DIR_WEBAPPS, ContentModel.TYPE_AVM_PLAIN_FOLDER);
this.avmService.createDirectory(path, AVMConstants.DIR_WEBAPPS);
// tag the store with the store type
this.avmService.setStoreProperty(stagingStore,
QName.createQName(null, AVMConstants.PROP_SANDBOX_STAGING_MAIN),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the DNS name property
tagStoreDNSPath(stagingStore, name, "staging");
// snapshot the store
this.avmService.createSnapshot(stagingStore, null, null);
// create the 'preview' store for the website
String previewStore = AVMConstants.buildAVMStagingPreviewStoreName(name);
this.avmService.createAVMStore(previewStore);
if (logger.isDebugEnabled())
logger.debug("Created staging sandbox store: " + previewStore);
// create a layered directory pointing to 'appBase' in the staging area
path = previewStore + ":/";
String targetPath = name + AVMConstants.STORE_STAGING + ":/" + AVMConstants.DIR_APPBASE;
//this.fileFolderService.create(AVMNodeConverter.ToNodeRef(-1, path), AVMConstants.DIR_APPBASE, ContentModel.TYPE_AVM_PLAIN_FOLDER);
this.avmService.createLayeredDirectory(targetPath, path, AVMConstants.DIR_APPBASE);
dirRef = AVMNodeConverter.ToNodeRef(-1, path + '/' + AVMConstants.DIR_APPBASE);
for (String manager : managers)
{
this.permissionService.setPermission(dirRef, manager, ROLE_CONTENT_MANAGER, true);
}
// tag the store with the store type
this.avmService.setStoreProperty(previewStore,
QName.createQName(null, AVMConstants.PROP_SANDBOX_STAGING_PREVIEW),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the DNS name property
tagStoreDNSPath(previewStore, name, "preview");
// snapshot the store
this.avmService.createSnapshot(previewStore, null, null);
// tag all related stores to indicate that they are part of a single sandbox
String sandboxIdProp = AVMConstants.PROP_SANDBOXID + GUID.generate();
this.avmService.setStoreProperty(stagingStore,
QName.createQName(null, sandboxIdProp),
new PropertyValue(DataTypeDefinition.TEXT, null));
this.avmService.setStoreProperty(previewStore,
QName.createQName(null, sandboxIdProp),
new PropertyValue(DataTypeDefinition.TEXT, null));
if (logger.isDebugEnabled())
{
dumpStoreProperties(stagingStore);
dumpStoreProperties(previewStore);
}
}
/**
* Create a user sandbox for the named store.
*
* A user sandbox is comprised of two stores, the first named 'storename-username-main' layered
* over the staging store with a preview store named 'storename-username-preview' layered over
* the main store.
*
* Various store meta-data properties are set including:
* Identifier for store-types: .sandbox.author.main and .sandbox.author.preview
* Store-id: .sandbox-id.<guid> (unique across all stores in the sandbox)
* DNS: .dns.<store> = <path-to-webapps-root>
* Website Name: .website.name = website name
*
* @param name The store name to create the sandbox for
* @param managers The list of authorities who have ContentManager role in the website
* @param username Username of the user to create the sandbox for
* @param role Role permission for the user
*/
private void createUserSandbox(String name, List<String> managers, String username, String role)
{
// create the user 'main' store
String userStore = AVMConstants.buildAVMUserMainStoreName(name, username);
this.avmService.createAVMStore(userStore);
if (logger.isDebugEnabled())
logger.debug("Created staging sandbox store: " + userStore);
// create a layered directory pointing to 'appBase' in the staging area
String path = userStore + ":/";
String targetPath = name + AVMConstants.STORE_STAGING + ":/" + AVMConstants.DIR_APPBASE;
this.avmService.createLayeredDirectory(targetPath, path, AVMConstants.DIR_APPBASE);
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, path + '/' + AVMConstants.DIR_APPBASE);
this.permissionService.setPermission(dirRef, username, role, true);
for (String manager : managers)
{
this.permissionService.setPermission(dirRef, manager, ROLE_CONTENT_MANAGER, true);
}
// tag the store with the store type
this.avmService.setStoreProperty(userStore,
QName.createQName(null, AVMConstants.PROP_SANDBOX_AUTHOR_MAIN),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the base name of the website so that corresponding
// staging areas can be found.
this.avmService.setStoreProperty(userStore,
QName.createQName(null, AVMConstants.PROP_WEBSITE_NAME),
new PropertyValue(DataTypeDefinition.TEXT, name));
// tag the store, oddly enough, with its own store name for querying.
// when will the madness end.
this.avmService.setStoreProperty(userStore,
QName.createQName(null, AVMConstants.PROP_SANDBOX_STORE_PREFIX + userStore),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the DNS name property
tagStoreDNSPath(userStore, name, username);
// snapshot the store
this.avmService.createSnapshot(userStore, null, null);
// create the user 'preview' store
String previewStore = AVMConstants.buildAVMUserPreviewStoreName(name, username);
this.avmService.createAVMStore(previewStore);
if (logger.isDebugEnabled())
logger.debug("Created staging sandbox store: " + previewStore);
// create a layered directory pointing to 'appBase' in the user 'main' store
path = previewStore + ":/";
targetPath = userStore + ":/" + AVMConstants.DIR_APPBASE;
this.avmService.createLayeredDirectory(targetPath, path, AVMConstants.DIR_APPBASE);
dirRef = AVMNodeConverter.ToNodeRef(-1, path + '/' + AVMConstants.DIR_APPBASE);
this.permissionService.setPermission(dirRef, username, role, true);
for (String manager : managers)
{
this.permissionService.setPermission(dirRef, manager, ROLE_CONTENT_MANAGER, true);
}
// tag the store with the store type
this.avmService.setStoreProperty(previewStore,
QName.createQName(null, AVMConstants.PROP_SANDBOX_AUTHOR_PREVIEW),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with its own store name for querying.
this.avmService.setStoreProperty(previewStore,
QName.createQName(null, AVMConstants.PROP_SANDBOX_STORE_PREFIX + previewStore),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the DNS name property
tagStoreDNSPath(previewStore, name, username, "preview");
// snapshot the store
this.avmService.createSnapshot(previewStore, null, null);
// tag all related stores to indicate that they are part of a single sandbox
String sandboxIdProp = AVMConstants.PROP_SANDBOXID + GUID.generate();
this.avmService.setStoreProperty(userStore, QName.createQName(null, sandboxIdProp),
new PropertyValue(DataTypeDefinition.TEXT, null));
this.avmService.setStoreProperty(previewStore, QName.createQName(null, sandboxIdProp),
new PropertyValue(DataTypeDefinition.TEXT, null));
if (logger.isDebugEnabled())
{
dumpStoreProperties(userStore);
dumpStoreProperties(previewStore);
}
}
/**
* Tag a named store with a DNS path meta-data attribute.
* The DNS meta-data attribute is set to the system path 'store:/appBase/avm_webapps'
*
* @param store Name of the store to tag
*/
private void tagStoreDNSPath(String store, String... components)
{
String path = store + ":/" + AVMConstants.DIR_APPBASE + '/' + AVMConstants.DIR_WEBAPPS;
// DNS name mangle the property name - can only contain value DNS characters!
String dnsProp = AVMConstants.PROP_DNS + DNSNameMangler.MakeDNSName(components);
this.avmService.setStoreProperty(store, QName.createQName(null, dnsProp),
new PropertyValue(DataTypeDefinition.TEXT, path));
}
/**
* Debug helper method to dump the properties of a store
*
* @param store Store name to dump properties for
*/
private void dumpStoreProperties(String store)
{
Map<QName, PropertyValue> props = avmService.getStoreProperties(store);
for (QName name : props.keySet())
{
logger.debug(" " + name + ": " + props.get(name));
}
}
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
// Inner classes // Inner classes
@@ -1061,7 +777,7 @@ public class CreateWebsiteWizard extends BaseWizardBean
WorkflowDefinition wf = this.form.getDefaultWorkflow(); WorkflowDefinition wf = this.form.getDefaultWorkflow();
if (this.workflow == null && wf != null) if (this.workflow == null && wf != null)
{ {
this.workflow = CreateWebsiteWizard.this.new WorkflowWrapper(wf.getId()); this.workflow = new WorkflowWrapper(wf.id, wf.getTitle());
} }
return this.workflow; return this.workflow;
} }
@@ -1126,9 +842,9 @@ public class CreateWebsiteWizard extends BaseWizardBean
{ {
String none = '<' + Application.getMessage(FacesContext.getCurrentInstance(), MSG_NONE) + '>'; String none = '<' + Application.getMessage(FacesContext.getCurrentInstance(), MSG_NONE) + '>';
return MessageFormat.format(Application.getMessage(FacesContext.getCurrentInstance(), MSG_FORM_SUMMARY), return MessageFormat.format(Application.getMessage(FacesContext.getCurrentInstance(), MSG_FORM_SUMMARY),
getWorkflow() != null ? this.workflow.getName() : none, getWorkflow() != null ? this.workflow.title : none,
getFilenamePattern() != null ? this.filenamePattern : none, getFilenamePattern() != null ? this.filenamePattern : none,
getTemplates() != null ? this.templates.size() : 0); getTemplates() != null ? this.templates.size() : 0);
} }
} }
@@ -1197,24 +913,21 @@ public class CreateWebsiteWizard extends BaseWizardBean
} }
} }
public WorkflowWrapper getWorkflowWrapper(String id)
{
return this.new WorkflowWrapper(id);
}
/** /**
* Class to represent a single configured Workflow instance * Class to represent a single configured Workflow instance
*/ */
public class WorkflowWrapper public static class WorkflowWrapper
{ {
private String id; private String id;
private String title;
private String filenamePattern; private String filenamePattern;
private QName type; private QName type;
private Map<QName, Serializable> params; private Map<QName, Serializable> params;
public WorkflowWrapper(String id) public WorkflowWrapper(String id, String title)
{ {
this.id = id; this.id = id;
this.title = title;
this.filenamePattern = filenamePattern; this.filenamePattern = filenamePattern;
} }
@@ -1229,9 +942,17 @@ public class CreateWebsiteWizard extends BaseWizardBean
/** /**
* @return Returns the name of the workflow. * @return Returns the name of the workflow.
*/ */
public String getName() //public String getName()
//{
// return workflowService.getDefinitionById(this.getId()).getName();
//}
/**
* @return the display label of the workflow.
*/
public String getTitle()
{ {
return workflowService.getDefinitionById(this.getId()).getName(); return this.title;
} }
/** /**

View File

@@ -231,7 +231,8 @@ public class FormDetailsDialog extends BaseDialogBean
} }
if (this.workflowSelectedValue != null && this.workflowSelectedValue.length != 0) if (this.workflowSelectedValue != null && this.workflowSelectedValue.length != 0)
{ {
form.setWorkflow(websiteWizard.getWorkflowWrapper(this.workflowSelectedValue[0])); WorkflowDefinition def = this.workflowService.getDefinitionById(this.workflowSelectedValue[0]);
form.setWorkflow(new CreateWebsiteWizard.WorkflowWrapper(def.getId(), def.getTitle()));
} }
return outcome; return outcome;
} }

View File

@@ -1,64 +1,191 @@
package org.alfresco.web.bean.wcm; package org.alfresco.web.bean.wcm;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.faces.context.FacesContext; import javax.faces.context.FacesContext;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.web.app.Application; import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.wizard.InviteUsersWizard; import org.alfresco.web.bean.wizard.InviteUsersWizard;
import org.alfresco.web.bean.wizard.InviteUsersWizard.UserGroupRole;
/** /**
* Concrete implementation providing the ability to invite users to a space. * Bean providing the ability to invite users to a web project space.
* *
* @author gavinc * @author kevinr
*/ */
public class InviteWebsiteUsersWizard extends InviteUsersWizard public class InviteWebsiteUsersWizard extends InviteUsersWizard
{ {
private static final String WIZARD_TITLE_ID = "invite_title"; private static final String MSG_USERROLES = "invite_webusers_summary_users";
private static final String WIZARD_DESC_ID = "invite_desc";
private static final String STEP1_DESCRIPTION_ID = "invite_step1_desc";
/** Cache of available folder permissions */ /** Cache of available folder permissions */
Set<String> folderPermissions = null; Set<String> folderPermissions = null;
/** the node representing the website */
private Node website; private Node website;
/** list of authorities with the Content Manager role */
private List<String> managers;
/** root AVM store the users are invited into */
private String avmStore;
/** assume we are launching the wizard standalone */
private boolean standalone = true;
/** /**
* @see org.alfresco.web.bean.wizard.InviteUsersWizard#init() * @see org.alfresco.web.bean.wizard.InviteUsersWizard#init(java.util.Map)
*/ */
@Override @Override
public void init() public void init(Map<String, String> parameters)
{ {
super.init(); super.init(parameters);
// only allow one selection per authority // only allow one selection per authority
allowDuplicateAuthorities = false; this.allowDuplicateAuthorities = false;
this.website = null;
this.managers = null;
this.avmStore = null;
this.standalone = true;
} }
/** /**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardDescription() * @see org.alfresco.web.bean.wizard.InviteUsersWizard#finishImpl(javax.faces.context.FacesContext, java.lang.String)
*/ */
public String getWizardDescription()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_DESC_ID);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardTitle()
*/
public String getWizardTitle()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_TITLE_ID);
}
@Override @Override
protected String getStep1DescriptionText() protected String finishImpl(FacesContext context, String outcome) throws Exception
{ {
return STEP1_DESCRIPTION_ID; super.finishImpl(context, outcome);
// create a sandbox for each user appropriately with permissions based on role
// build a list of managers who will have full permissions on ALL staging areas
this.managers = new ArrayList<String>(4);
Set<String> excludeUsers = new HashSet(4);
if (isStandalone() == false)
{
// no website created yet - so we need to build the list of managers from the
// invited users and the power user who is executing the create web project wizard
boolean foundCurrentUser = false;
String currentUser = Application.getCurrentUser(context).getUserName();
for (UserGroupRole userRole : this.userGroupRoles)
{
String authority = userRole.getAuthority();
if (currentUser.equals(authority))
{
foundCurrentUser = true;
}
if (SandboxFactory.ROLE_CONTENT_MANAGER.equals(userRole.getRole()))
{
this.managers.add(authority);
}
}
if (foundCurrentUser == false)
{
this.userGroupRoles.add(new UserGroupRole(currentUser, SandboxFactory.ROLE_CONTENT_MANAGER, null));
this.managers.add(currentUser);
}
}
else
{
// website already exists - we are only adding to the existing sandboxes
// so retrieve the list of managers from the existing users and the selected invitees
for (UserGroupRole userRole : this.userGroupRoles)
{
if (SandboxFactory.ROLE_CONTENT_MANAGER.equals(userRole.getRole()))
{
this.managers.add(userRole.getAuthority());
}
}
List<ChildAssociationRef> userInfoRefs = this.nodeService.getChildAssocs(
getNode().getNodeRef(), ContentModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
String username = (String)nodeService.getProperty(userInfoRef, ContentModel.PROP_WEBUSERNAME);
String userrole = (String)nodeService.getProperty(userInfoRef, ContentModel.PROP_WEBUSERROLE);
if (SandboxFactory.ROLE_CONTENT_MANAGER.equals(userrole) &&
this.managers.contains(username) == false)
{
this.managers.add(username);
}
// add each existing user to the exclude this - we cannot add them more than once!
excludeUsers.add(username);
}
}
// build the sandboxes now we have the manager list and complete user list
for (UserGroupRole userRole : this.userGroupRoles)
{
String authority = userRole.getAuthority();
if (excludeUsers.contains(authority) == false)
{
SandboxFactory.createUserSandbox(
getAvmStore(), this.managers, userRole.getAuthority(), userRole.getRole());
}
}
// save the list of invited users against the store
for (UserGroupRole userRole : this.userGroupRoles)
{
String authority = userRole.getAuthority();
if (excludeUsers.contains(authority) == false)
{
// create an app:webuser instance for each authority and assoc to the website node
Map<QName, Serializable> props = new HashMap<QName, Serializable>(2, 1.0f);
props.put(ContentModel.PROP_WEBUSERNAME, authority);
props.put(ContentModel.PROP_WEBUSERROLE, userRole.getRole());
this.nodeService.createNode(getNode().getNodeRef(),
ContentModel.ASSOC_WEBUSER,
ContentModel.ASSOC_WEBUSER,
ContentModel.TYPE_WEBUSER,
props);
}
}
return outcome;
} }
/**
* @return summary text for the wizard
*/
public String getSummary()
{
FacesContext fc = FacesContext.getCurrentInstance();
// build a summary section to list the invited users and there roles
StringBuilder buf = new StringBuilder(128);
String currentUser = Application.getCurrentUser(fc).getUserName();
boolean foundCurrentUser = false;
for (UserGroupRole userRole : this.userGroupRoles)
{
if (currentUser.equals(userRole.getAuthority()))
{
foundCurrentUser = true;
}
buf.append(userRole.getLabel());
buf.append("<br>");
}
if (foundCurrentUser == false)
{
buf.append(buildLabelForUserAuthorityRole(
currentUser, SandboxFactory.ROLE_CONTENT_MANAGER));
}
return buildSummary(
new String[] {Application.getMessage(fc, MSG_USERROLES)},
new String[] {buf.toString()});
}
@Override @Override
protected Set<String> getPermissionsForType() protected Set<String> getPermissionsForType()
{ {
@@ -79,6 +206,57 @@ public class InviteWebsiteUsersWizard extends InviteUsersWizard
@Override @Override
protected Node getNode() protected Node getNode()
{ {
return this.website; if (this.website != null)
{
return this.website;
}
else
{
return this.browseBean.getActionSpace();
}
}
/**
* @return List of authorities with the Content Manager role
*/
public List<String> getManagers()
{
return this.managers;
}
/**
* @return Returns the root AVM store.
*/
public String getAvmStore()
{
if (this.avmStore == null)
{
this.avmStore = (String)getNode().getProperties().get(ContentModel.PROP_AVMSTORE);
}
return this.avmStore;
}
/**
* @param avmStore The root AVM store to set.
*/
public void setAvmStore(String avmStore)
{
this.avmStore = avmStore;
}
/**
* @return Returns the edit mode.
*/
public boolean isStandalone()
{
return this.standalone;
}
/**
* @param editMode The edit mode to set.
*/
public void setStandalone(boolean editMode)
{
this.standalone = editMode;
} }
} }

View File

@@ -0,0 +1,300 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.bean.wcm;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
import org.alfresco.web.bean.repository.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Helper factory to create AVM sandbox structures.
*
* @author Kevin Roast
*/
public final class SandboxFactory
{
private static Log logger = LogFactory.getLog(SandboxFactory.class);
public static final String ROLE_CONTENT_MANAGER = "ContentManager";
/**
* Private constructor
*/
private SandboxFactory()
{
}
/**
* Create the staging sandbox for the named store.
*
* A staging sandbox is comprised of two stores, the first named 'storename-staging' with a
* preview store named 'storename-preview' layered over the staging store.
*
* Various store meta-data properties are set including:
* Identifier for store-types: .sandbox.staging.main and .sandbox.staging.preview
* Store-id: .sandbox-id.<guid> (unique across all stores in the sandbox)
* DNS: .dns.<store> = <path-to-webapps-root>
* Website Name: .website.name = website name
*
* @param name The store name to create the sandbox for
* @param managers The list of authorities who have ContentManager role in the website
*/
public static void createStagingSandbox(String name, List<String> managers)
{
ServiceRegistry services = Repository.getServiceRegistry(FacesContext.getCurrentInstance());
AVMService avmService = services.getAVMService();
PermissionService permissionService = services.getPermissionService();
// create the 'staging' store for the website
String stagingStore = AVMConstants.buildAVMStagingStoreName(name);
avmService.createAVMStore(stagingStore);
if (logger.isDebugEnabled())
logger.debug("Created staging sandbox store: " + stagingStore);
// create the system directories 'appBase' and 'avm_webapps'
String path = stagingStore + ":/";
//this.fileFolderService.create(AVMNodeConverter.ToNodeRef(-1, path), AVMConstants.DIR_APPBASE, ContentModel.TYPE_AVM_PLAIN_FOLDER);
avmService.createDirectory(path, AVMConstants.DIR_APPBASE);
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, path + '/' + AVMConstants.DIR_APPBASE);
for (String manager : managers)
{
permissionService.setPermission(dirRef, manager, ROLE_CONTENT_MANAGER, true);
}
path += AVMConstants.DIR_APPBASE;
//this.fileFolderService.create(AVMNodeConverter.ToNodeRef(-1, path), AVMConstants.DIR_WEBAPPS, ContentModel.TYPE_AVM_PLAIN_FOLDER);
avmService.createDirectory(path, AVMConstants.DIR_WEBAPPS);
// tag the store with the store type
avmService.setStoreProperty(stagingStore,
QName.createQName(null, AVMConstants.PROP_SANDBOX_STAGING_MAIN),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the DNS name property
tagStoreDNSPath(avmService, stagingStore, name, "staging");
// snapshot the store
avmService.createSnapshot(stagingStore, null, null);
// create the 'preview' store for the website
String previewStore = AVMConstants.buildAVMStagingPreviewStoreName(name);
avmService.createAVMStore(previewStore);
if (logger.isDebugEnabled())
logger.debug("Created staging sandbox store: " + previewStore);
// create a layered directory pointing to 'appBase' in the staging area
path = previewStore + ":/";
String targetPath = name + AVMConstants.STORE_STAGING + ":/" + AVMConstants.DIR_APPBASE;
//this.fileFolderService.create(AVMNodeConverter.ToNodeRef(-1, path), AVMConstants.DIR_APPBASE, ContentModel.TYPE_AVM_PLAIN_FOLDER);
avmService.createLayeredDirectory(targetPath, path, AVMConstants.DIR_APPBASE);
dirRef = AVMNodeConverter.ToNodeRef(-1, path + '/' + AVMConstants.DIR_APPBASE);
for (String manager : managers)
{
permissionService.setPermission(dirRef, manager, ROLE_CONTENT_MANAGER, true);
}
// tag the store with the store type
avmService.setStoreProperty(previewStore,
QName.createQName(null, AVMConstants.PROP_SANDBOX_STAGING_PREVIEW),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the DNS name property
tagStoreDNSPath(avmService, previewStore, name, "preview");
// snapshot the store
avmService.createSnapshot(previewStore, null, null);
// tag all related stores to indicate that they are part of a single sandbox
String sandboxIdProp = AVMConstants.PROP_SANDBOXID + GUID.generate();
avmService.setStoreProperty(stagingStore,
QName.createQName(null, sandboxIdProp),
new PropertyValue(DataTypeDefinition.TEXT, null));
avmService.setStoreProperty(previewStore,
QName.createQName(null, sandboxIdProp),
new PropertyValue(DataTypeDefinition.TEXT, null));
if (logger.isDebugEnabled())
{
dumpStoreProperties(avmService, stagingStore);
dumpStoreProperties(avmService, previewStore);
}
}
/**
* Create a user sandbox for the named store.
*
* A user sandbox is comprised of two stores, the first named 'storename-username-main' layered
* over the staging store with a preview store named 'storename-username-preview' layered over
* the main store.
*
* Various store meta-data properties are set including:
* Identifier for store-types: .sandbox.author.main and .sandbox.author.preview
* Store-id: .sandbox-id.<guid> (unique across all stores in the sandbox)
* DNS: .dns.<store> = <path-to-webapps-root>
* Website Name: .website.name = website name
*
* @param name The store name to create the sandbox for
* @param managers The list of authorities who have ContentManager role in the website
* @param username Username of the user to create the sandbox for
* @param role Role permission for the user
*/
public static void createUserSandbox(String name, List<String> managers, String username, String role)
{
ServiceRegistry services = Repository.getServiceRegistry(FacesContext.getCurrentInstance());
AVMService avmService = services.getAVMService();
PermissionService permissionService = services.getPermissionService();
// create the user 'main' store
String userStore = AVMConstants.buildAVMUserMainStoreName(name, username);
if (avmService.getAVMStore(userStore) == null)
{
avmService.createAVMStore(userStore);
if (logger.isDebugEnabled())
logger.debug("Created user sandbox store: " + userStore);
// create a layered directory pointing to 'appBase' in the staging area
String path = userStore + ":/";
String targetPath = name + AVMConstants.STORE_STAGING + ":/" + AVMConstants.DIR_APPBASE;
avmService.createLayeredDirectory(targetPath, path, AVMConstants.DIR_APPBASE);
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, path + '/' + AVMConstants.DIR_APPBASE);
permissionService.setPermission(dirRef, username, role, true);
for (String manager : managers)
{
permissionService.setPermission(dirRef, manager, ROLE_CONTENT_MANAGER, true);
}
// tag the store with the store type
avmService.setStoreProperty(userStore,
QName.createQName(null, AVMConstants.PROP_SANDBOX_AUTHOR_MAIN),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the base name of the website so that corresponding
// staging areas can be found.
avmService.setStoreProperty(userStore,
QName.createQName(null, AVMConstants.PROP_WEBSITE_NAME),
new PropertyValue(DataTypeDefinition.TEXT, name));
// tag the store, oddly enough, with its own store name for querying.
// when will the madness end.
avmService.setStoreProperty(userStore,
QName.createQName(null, AVMConstants.PROP_SANDBOX_STORE_PREFIX + userStore),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the DNS name property
tagStoreDNSPath(avmService, userStore, name, username);
// snapshot the store
avmService.createSnapshot(userStore, null, null);
// create the user 'preview' store
String previewStore = AVMConstants.buildAVMUserPreviewStoreName(name, username);
avmService.createAVMStore(previewStore);
if (logger.isDebugEnabled())
logger.debug("Created user sandbox store: " + previewStore);
// create a layered directory pointing to 'appBase' in the user 'main' store
path = previewStore + ":/";
targetPath = userStore + ":/" + AVMConstants.DIR_APPBASE;
avmService.createLayeredDirectory(targetPath, path, AVMConstants.DIR_APPBASE);
dirRef = AVMNodeConverter.ToNodeRef(-1, path + '/' + AVMConstants.DIR_APPBASE);
permissionService.setPermission(dirRef, username, role, true);
for (String manager : managers)
{
permissionService.setPermission(dirRef, manager, ROLE_CONTENT_MANAGER, true);
}
// tag the store with the store type
avmService.setStoreProperty(previewStore,
QName.createQName(null, AVMConstants.PROP_SANDBOX_AUTHOR_PREVIEW),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with its own store name for querying.
avmService.setStoreProperty(previewStore,
QName.createQName(null, AVMConstants.PROP_SANDBOX_STORE_PREFIX + previewStore),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the DNS name property
tagStoreDNSPath(avmService, previewStore, name, username, "preview");
// snapshot the store
avmService.createSnapshot(previewStore, null, null);
// tag all related stores to indicate that they are part of a single sandbox
String sandboxIdProp = AVMConstants.PROP_SANDBOXID + GUID.generate();
avmService.setStoreProperty(userStore, QName.createQName(null, sandboxIdProp),
new PropertyValue(DataTypeDefinition.TEXT, null));
avmService.setStoreProperty(previewStore, QName.createQName(null, sandboxIdProp),
new PropertyValue(DataTypeDefinition.TEXT, null));
if (logger.isDebugEnabled())
{
dumpStoreProperties(avmService, userStore);
dumpStoreProperties(avmService, previewStore);
}
}
else if (logger.isDebugEnabled())
{
logger.debug("Not creating as store already exists: " + userStore);
}
}
/**
* Tag a named store with a DNS path meta-data attribute.
* The DNS meta-data attribute is set to the system path 'store:/appBase/avm_webapps'
*
* @param store Name of the store to tag
*/
private static void tagStoreDNSPath(AVMService avmService, String store, String... components)
{
String path = store + ":/" + AVMConstants.DIR_APPBASE + '/' + AVMConstants.DIR_WEBAPPS;
// DNS name mangle the property name - can only contain value DNS characters!
String dnsProp = AVMConstants.PROP_DNS + DNSNameMangler.MakeDNSName(components);
avmService.setStoreProperty(store, QName.createQName(null, dnsProp),
new PropertyValue(DataTypeDefinition.TEXT, path));
}
/**
* Debug helper method to dump the properties of a store
*
* @param store Store name to dump properties for
*/
private static void dumpStoreProperties(AVMService avmService, String store)
{
Map<QName, PropertyValue> props = avmService.getStoreProperties(store);
for (QName name : props.keySet())
{
logger.debug(" " + name + ": " + props.get(name));
}
}
}

View File

@@ -2,10 +2,7 @@ package org.alfresco.web.bean.wizard;
import java.util.Set; import java.util.Set;
import javax.faces.context.FacesContext;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Node;
/** /**
@@ -15,35 +12,9 @@ import org.alfresco.web.bean.repository.Node;
*/ */
public class InviteContentUsersWizard extends InviteUsersWizard public class InviteContentUsersWizard extends InviteUsersWizard
{ {
private static final String WIZARD_TITLE_ID = "invite_content_title";
private static final String WIZARD_DESC_ID = "invite_content_desc";
private static final String STEP1_DESCRIPTION_ID = "invite_content_step1_desc";
/** Cache of available content permissions */ /** Cache of available content permissions */
Set<String> contentPermissions = null; Set<String> contentPermissions = null;
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardDescription()
*/
public String getWizardDescription()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_DESC_ID);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardTitle()
*/
public String getWizardTitle()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_TITLE_ID);
}
@Override
protected String getStep1DescriptionText()
{
return STEP1_DESCRIPTION_ID;
}
@Override @Override
protected Set<String> getPermissionsForType() protected Set<String> getPermissionsForType()
{ {

View File

@@ -2,10 +2,7 @@ package org.alfresco.web.bean.wizard;
import java.util.Set; import java.util.Set;
import javax.faces.context.FacesContext;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Node;
/** /**
@@ -15,35 +12,9 @@ import org.alfresco.web.bean.repository.Node;
*/ */
public class InviteSpaceUsersWizard extends InviteUsersWizard public class InviteSpaceUsersWizard extends InviteUsersWizard
{ {
private static final String WIZARD_TITLE_ID = "invite_title";
private static final String WIZARD_DESC_ID = "invite_desc";
private static final String STEP1_DESCRIPTION_ID = "invite_step1_desc";
/** Cache of available folder permissions */ /** Cache of available folder permissions */
Set<String> folderPermissions = null; Set<String> folderPermissions = null;
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardDescription()
*/
public String getWizardDescription()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_DESC_ID);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardTitle()
*/
public String getWizardTitle()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_TITLE_ID);
}
@Override
protected String getStep1DescriptionText()
{
return STEP1_DESCRIPTION_ID;
}
@Override @Override
protected Set<String> getPermissionsForType() protected Set<String> getPermissionsForType()
{ {

View File

@@ -20,6 +20,7 @@ import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.Set; import java.util.Set;
@@ -39,7 +40,6 @@ import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.web.app.Application; import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.bean.TemplateMailHelperBean; import org.alfresco.web.bean.TemplateMailHelperBean;
import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.bean.repository.Repository;
@@ -52,9 +52,11 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.JavaMailSender;
/** /**
* Backing bean for the Invite Users wizard(s)
*
* @author Kevin Roast * @author Kevin Roast
*/ */
public abstract class InviteUsersWizard extends AbstractWizardBean public abstract class InviteUsersWizard extends BaseWizardBean
{ {
private static Log logger = LogFactory.getLog(InviteUsersWizard.class); private static Log logger = LogFactory.getLog(InviteUsersWizard.class);
@@ -63,10 +65,6 @@ public abstract class InviteUsersWizard extends AbstractWizardBean
private static final String MSG_GROUPS = "groups"; private static final String MSG_GROUPS = "groups";
private static final String MSG_INVITED_TO = "invited_to"; private static final String MSG_INVITED_TO = "invited_to";
private static final String MSG_INVITED_ROLE = "invite_role"; private static final String MSG_INVITED_ROLE = "invite_role";
private static final String STEP1_TITLE_ID = "invite_step1_title";
private static final String STEP2_TITLE_ID = "invite_step2_title";
private static final String STEP2_DESCRIPTION_ID = "invite_step2_desc";
private static final String FINISH_INSTRUCTION_ID = "invite_finish_instruction";
private static final String NOTIFY_YES = "yes"; private static final String NOTIFY_YES = "yes";
@@ -89,10 +87,10 @@ public abstract class InviteUsersWizard extends AbstractWizardBean
protected TemplateMailHelperBean mailHelper; protected TemplateMailHelperBean mailHelper;
/** datamodel for table of roles for users */ /** datamodel for table of roles for users */
private DataModel userRolesDataModel = null; protected DataModel userRolesDataModel = null;
/** list of user/group role wrapper objects */ /** list of user/group role wrapper objects */
private List<UserGroupRole> userGroupRoles = null; protected List<UserGroupRole> userGroupRoles = null;
/** True to allow duplicate authorities (with a different role) */ /** True to allow duplicate authorities (with a different role) */
protected boolean allowDuplicateAuthorities = true; protected boolean allowDuplicateAuthorities = true;
@@ -110,11 +108,6 @@ public abstract class InviteUsersWizard extends AbstractWizardBean
*/ */
protected abstract Node getNode(); protected abstract Node getNode();
/**
* @return The text to use for the description of step 1 (depends on the type being dealt with)
*/
protected abstract String getStep1DescriptionText();
/** /**
* @param namespaceService The NamespaceService to set. * @param namespaceService The NamespaceService to set.
*/ */
@@ -158,9 +151,10 @@ public abstract class InviteUsersWizard extends AbstractWizardBean
/** /**
* Initialises the wizard * Initialises the wizard
*/ */
public void init() @Override
public void init(Map<String, String> parameters)
{ {
super.init(); super.init(parameters);
notify = NOTIFY_YES; notify = NOTIFY_YES;
userGroupRoles = new ArrayList<UserGroupRole>(8); userGroupRoles = new ArrayList<UserGroupRole>(8);
@@ -170,94 +164,70 @@ public abstract class InviteUsersWizard extends AbstractWizardBean
} }
/** /**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#finish() * @see org.alfresco.web.bean.dialog.BaseDialogBean#finishImpl(javax.faces.context.FacesContext, java.lang.String)
*/ */
public String finish() @Override
protected String finishImpl(FacesContext context, String outcome) throws Exception
{ {
String outcome = FINISH_OUTCOME; User user = Application.getCurrentUser(context);
String from = (String)this.nodeService.getProperty(user.getPerson(), ContentModel.PROP_EMAIL);
UserTransaction tx = null; if (from == null || from.length() == 0)
try
{ {
FacesContext context = FacesContext.getCurrentInstance(); // if the user does not have an email address get the default one from the config service
from = Application.getClientConfig(context).getFromEmailAddress();
}
// get the Space to apply changes too
NodeRef nodeRef = this.getNode().getNodeRef();
// set permissions for each user and send them a mail
for (int i=0; i<this.userGroupRoles.size(); i++)
{
UserGroupRole userGroupRole = this.userGroupRoles.get(i);
String authority = userGroupRole.getAuthority();
tx = Repository.getUserTransaction(context); // find the selected permission ref from it's name and apply for the specified user
tx.begin(); Set<String> perms = getPermissionsForType();
for (String permission : perms)
User user = Application.getCurrentUser(context);
String from = (String)this.nodeService.getProperty(user.getPerson(), ContentModel.PROP_EMAIL);
if (from == null || from.length() == 0)
{ {
// if the user does not have an email address get the default one from the config service if (userGroupRole.getRole().equals(permission))
from = Application.getClientConfig(context).getFromEmailAddress(); {
this.permissionService.setPermission(
nodeRef,
authority,
permission,
true);
break;
}
} }
// get the Space to apply changes too // Create the mail message for sending to each User
NodeRef nodeRef = this.getNode().getNodeRef(); if (NOTIFY_YES.equals(this.notify))
// set permissions for each user and send them a mail
for (int i=0; i<this.userGroupRoles.size(); i++)
{ {
UserGroupRole userGroupRole = this.userGroupRoles.get(i); // if User, email then, else if Group get all members and email them
String authority = userGroupRole.getAuthority(); AuthorityType authType = AuthorityType.getAuthorityType(authority);
if (authType.equals(AuthorityType.USER))
// find the selected permission ref from it's name and apply for the specified user
Set<String> perms = getPermissionsForType();
for (String permission : perms)
{ {
if (userGroupRole.getRole().equals(permission)) if (this.personService.personExists(authority) == true)
{ {
this.permissionService.setPermission( this.mailHelper.notifyUser(
nodeRef, this.personService.getPerson(authority), nodeRef, from, userGroupRole.getRole());
authority,
permission,
true);
break;
} }
} }
else if (authType.equals(AuthorityType.GROUP))
// Create the mail message for sending to each User
if (NOTIFY_YES.equals(this.notify))
{ {
// if User, email then, else if Group get all members and email them // else notify all members of the group
AuthorityType authType = AuthorityType.getAuthorityType(authority); Set<String> users = this.authorityService.getContainedAuthorities(AuthorityType.USER, authority, false);
if (authType.equals(AuthorityType.USER)) for (String userAuth : users)
{ {
if (this.personService.personExists(authority) == true) if (this.personService.personExists(userAuth) == true)
{ {
this.mailHelper.notifyUser( this.mailHelper.notifyUser(
this.personService.getPerson(authority), nodeRef, from, userGroupRole.getRole()); this.personService.getPerson(userAuth), nodeRef, from, userGroupRole.getRole());
}
}
else if (authType.equals(AuthorityType.GROUP))
{
// else notify all members of the group
Set<String> users = this.authorityService.getContainedAuthorities(AuthorityType.USER, authority, false);
for (String userAuth : users)
{
if (this.personService.personExists(userAuth) == true)
{
this.mailHelper.notifyUser(
this.personService.getPerson(userAuth), nodeRef, from, userGroupRole.getRole());
}
} }
} }
} }
} }
// commit the transaction
tx.commit();
UIContextService.getInstance(context).notifyBeans();
}
catch (Throwable e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), e.getMessage()), e);
outcome = null;
} }
return outcome; return outcome;
@@ -486,100 +456,19 @@ public abstract class InviteUsersWizard extends AbstractWizardBean
this.notify = notify; this.notify = notify;
} }
/** @Override
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepDescription()
*/
public String getStepDescription()
{
String stepDesc = null;
switch (this.currentStep)
{
case 1:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), getStep1DescriptionText());
break;
}
case 2:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), STEP2_DESCRIPTION_ID);
break;
}
default:
{
stepDesc = "";
}
}
return stepDesc;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepTitle()
*/
public String getStepTitle()
{
String stepTitle = null;
switch (this.currentStep)
{
case 1:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP1_TITLE_ID);
break;
}
case 2:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP2_TITLE_ID);
break;
}
default:
{
stepTitle = "";
}
}
return stepTitle;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepInstructions()
*/
public String getStepInstructions()
{
String stepInstruction = null;
switch (this.currentStep)
{
case 2:
{
stepInstruction = Application.getMessage(FacesContext.getCurrentInstance(), FINISH_INSTRUCTION_ID);
break;
}
default:
{
stepInstruction = Application.getMessage(FacesContext.getCurrentInstance(), DEFAULT_INSTRUCTION_ID);
}
}
return stepInstruction;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#next()
*/
public String next() public String next()
{ {
String outcome = super.next(); String stepName = Application.getWizardManager().getCurrentStepName();
if (outcome.equals("notify")) if (stepName.equals("notify"))
{ {
FacesContext context = FacesContext.getCurrentInstance(); FacesContext context = FacesContext.getCurrentInstance();
// prepare automatic text for email and display // prepare automatic text for email and display
StringBuilder buf = new StringBuilder(256); StringBuilder buf = new StringBuilder(256);
String personName = Application.getCurrentUser(context).getFullName(getNodeService()); String personName = Application.getCurrentUser(context).getFullName(this.nodeService);
String msgInvitedTo = Application.getMessage(context, MSG_INVITED_TO); String msgInvitedTo = Application.getMessage(context, MSG_INVITED_TO);
Node node = this.getNode(); Node node = this.getNode();
String path = this.nodeService.getPath(node.getNodeRef()).toDisplayPath(this.nodeService); String path = this.nodeService.getPath(node.getNodeRef()).toDisplayPath(this.nodeService);
@@ -612,35 +501,7 @@ public abstract class InviteUsersWizard extends AbstractWizardBean
this.mailHelper.setBody(this.mailHelper.getAutomaticText()); this.mailHelper.setBody(this.mailHelper.getAutomaticText());
} }
return outcome; return null;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#determineOutcomeForStep(int)
*/
protected String determineOutcomeForStep(int step)
{
String outcome = null;
switch(step)
{
case 1:
{
outcome = "invite";
break;
}
case 2:
{
outcome = "notify";
break;
}
default:
{
outcome = CANCEL_OUTCOME;
}
}
return outcome;
} }
/** /**

View File

@@ -33,6 +33,16 @@ public final class WizardManager
private WizardState currentWizardState; private WizardState currentWizardState;
private Map<String, String> paramsToApply; private Map<String, String> paramsToApply;
/**
* Action handler used to setup parameters for the wizard being launched
*
* @param params The parameters
*/
public void setupParameters(Map<String, String> params)
{
this.paramsToApply = params;
}
/** /**
* Action handler used to setup parameters for the wizard being launched * Action handler used to setup parameters for the wizard being launched
* *
@@ -45,7 +55,7 @@ public final class WizardManager
if (component instanceof UIActionLink) if (component instanceof UIActionLink)
{ {
// store the parameters // store the parameters
this.paramsToApply = ((UIActionLink)component).getParameterMap(); setupParameters( ((UIActionLink)component).getParameterMap() );
} }
} }

View File

@@ -2156,10 +2156,6 @@
<property-name>avmService</property-name> <property-name>avmService</property-name>
<value>#{AVMService}</value> <value>#{AVMService}</value>
</managed-property> </managed-property>
<managed-property>
<property-name>permissionService</property-name>
<value>#{PermissionService}</value>
</managed-property>
<managed-property> <managed-property>
<property-name>workflowService</property-name> <property-name>workflowService</property-name>
<value>#{WorkflowService}</value> <value>#{WorkflowService}</value>

View File

@@ -46,7 +46,7 @@
<f:facet name="header"> <f:facet name="header">
<h:outputText value="#{msg.name}" /> <h:outputText value="#{msg.name}" />
</f:facet> </f:facet>
<h:outputText value="#{row.name}" /> <h:outputText value="#{row.title}" />
</h:column> </h:column>
<h:column> <h:column>
<f:facet name="header"> <f:facet name="header">