Derek Hulley f2eab4d8d9 Merged DEV/SWIFT to HEAD
28029: Added more tests for PublishingEventHelper and PublishingQueueImpl. Also added WebPublishingTestSuite.
   28034: Support for ALF-8792: RSOLR 036: SOLR APIs to support index integrity checking
          - ACL and ACLTX support
   28036: WCM QS ML UI tweaks for marking something as the initial translation
   28038: ALF-8548: WPUB: F165: Foundation API: Cancel a scheduled publishing event
          - Code and initial test cases
   28051: Fix for ALF-8836: No permission checks for SolrJSONResultSet
   28057: WCM QS ML support for claiming intermediate non-translated folders when translating documents, with tests
   28058: ML-WQS: Slight refactoring to remove RootNavInterceptor.
          This functionality has been brought into the ApplicationDataInterceptor.
		  The effective root section is now made available to templates and components in the model.
   28059: ALF-8499. SVC 10: Action Forms.
          This checkin adds an ActionFormProcessor which supports the generation and persistence of Forms based on
          Alfresco spring-injected action beans. The form processor produces a form field for each defined action parameter
          as well as the ubiquitous executeAsynchronously boolean for action execution.
          There is no styling of configuration of these forms and therefore NodeRef parameters will allow selection of any
		  cm:cmobject nodes and action constraints like ac-aspects will return every aspect defined in the system.
          To expose these forms in the product, we would need to add form configuration for the built-in actions in order to manage and control such data.
   28064: Fix for ALF-8857: Fix SOLR query caching to respect locale for ordering
   28067: ALF-8846 : Intermittent: DMDeploymentTargetTest
          added more debug logging and throw an explicit exception on trying to create a duplicate directory.
   28068: Publishing: Tidy-up (javadoc and removal of a few unnecessary operations) prior to sprint 1 demo.
   28069: Implemented EnvironmentImpl.checkStatus() method. Also created an AbstractWebPublishingIntegrationTest
          and extended many of the web publishing tests from htis class.
   28076: Publishing: More javadoc
   28078: RINF 11: Canned queries
          - minor: rename CannedQuery "query" to "queryAndFilter" and update/fix related JavaDoc (ALF-8827)
          - update PagingRequest - precursor to merge with (Script) PagingDetails (ALF-8855)
   28079: RINF 40: Lucene Removal: PersonService API (ALF-8805) - W.I.P.
          - add GetChildren CQ support for (initially string) property filtering, including unit tests
          - update GetChildren CQ to allow up to three filter and/or sort props
          - add GetChildren CQ unit test for existing DB-based filtering of child types
          - fix GetChildren CQ sorting, for spoofed referenceable props (including missing name)
   28083: Fix for ALF-8858: Fix cache bugs (TX and ACLTX docs not tracked)
   28097: Fix hard-coded checks for aspect counts following sys:localized changes
   28126: Build/test fix (GetChildrenCannedQueryTest.testPropertyStringFiltering)
   28147: RINF 40: Lucene Removal: PersonService API
          - initial impl w/ unit tests
          - note: separate task required to update JavaScript API (People.getPeople)
   28157: RINF 40: Lucene Removal: PersonService API (ALF-8805)
          - fix People.getPeople - put back FTS option (pending ALF-8924)
   28162: Added PublishWebContentJbpmTest to test the Jbpm publish web content process definiion.
   28178: Build fix. Removing a trailing comma that my ant build objects to.
   28180: Preventing a NPE within TikaCharsetFinder. Was observed as part of tests for ALF-3757.
   28182: RSOLR 037: Integrate CMIS Dictionary into SOLR engine
   28183: ALF-8846 - fix DMDeploymentTarget(Test)
          - make system auth explicit
          - minor: fixup debug logging
   28187: Fix for ALF-7308. The imgpreview thumbnail ... scale up small images...
          I've exposed an ImageMagick configuration option ('>') as a new ImageRenderingEngine parameter, "allowEnlargement".
          It's not mandatory, defaults to true, and is set to false for doclib and imgpreview thumbnails.
          The net result is that doclib and imgpreview thumbnails of small graphics files (e.g. icons) will never have sizes exceeding their original size.
   28191: RINF 09: Update FileFolderService (ALF-7168)
          - minor: clean-up debug/trace logging
   28192: Fix MT for GetChildren CQ
          - FileFolderService -> list (ALF-7168)
          - PersonService -> getPeople (ALF-8805)
   28194: RINF 09: CMIS getChildren sorting fixes (part of ALF-7168)
          - fix sorting by cmis:contentStreamMimeType and/or cmis:contentStreamLength
          - add warning + debug (if some orderBy sort props need to be ignored - eg. too many or unknown)
          - reviewed w/ Florian
   28195: ALF-8910: RSOLR 037: Integrate CMIS Query Parser into SOLR engine
   28211: Changes for ALF-8646: "RINF 38: Text data encryption"
   28227: Changes for ALF-8646: "RINF 38: Text data encryption"
          o fix build issue relating to missing property definition
   28232: ALF-8928 - Performance degradation when loading documents from RepoStore
   28233: Attempt to resolve OOM hangs in SWIFT builds
          - Set mem.size.max=2048m
   28234: Implementation of ALF-8986. Add support for transformation of Apple iWorks files.
             A new transformer transforms (pages, numbers, keynote) iWorks 09 files to image or SWF for doclib & webpreview thumbnailing.
             This transformer extracts an embedded JPEG or PDF file from a well-known location within the iWorks zip structure & uses that
			 to create Alfresco thumbnails. If these zip entries are not present for whatever reason, then the transformation fails in the usual way.
             All of our iWorks 09 test files have an embedded JPEG and more than half have embedded PDFs.
   28243: Init/refresh repo webscripts in single txn
          - found whilst investigating ALF-8928
   28268: Started implementing PublishEventAction. Also updated mapping of nodes from source to live environment to use associations.
   28308: PublishEventAction now supports updating of nodes that have already been published.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28321 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2011-06-10 00:21:55 +00:00

987 lines
37 KiB
Java

/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.jscript;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.alfresco.model.ContentModel;
import org.alfresco.query.PagingRequest;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.UserNameGenerator;
import org.alfresco.repo.security.authority.AuthorityDAO;
import org.alfresco.repo.security.person.PersonServiceImpl;
import org.alfresco.repo.security.sync.UserRegistrySynchronizer;
import org.alfresco.repo.tenant.TenantDomainMismatchException;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.LimitBy;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.usage.ContentUsageService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyMap;
import org.alfresco.util.ValueDerivingMapFactory;
import org.alfresco.util.ValueDerivingMapFactory.ValueDeriver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
* Scripted People service for describing and executing actions against People & Groups.
*
* @author davidc
* @author kevinr
*/
public final class People extends BaseScopableProcessorExtension implements InitializingBean
{
private static Log logger = LogFactory.getLog(People.class);
/** Repository Service Registry */
private ServiceRegistry services;
private AuthorityDAO authorityDAO;
private AuthorityService authorityService;
private PersonService personService;
private NamespaceService namespaceService;
private MutableAuthenticationService authenticationService;
private ContentUsageService contentUsageService;
private TenantService tenantService;
private UserNameGenerator usernameGenerator;
private UserRegistrySynchronizer userRegistrySynchronizer;
private StoreRef storeRef;
private ValueDerivingMapFactory<ScriptNode, String, Boolean> valueDerivingMapFactory;
private int numRetries = 10;
public void afterPropertiesSet() throws Exception
{
Map <String, ValueDeriver<ScriptNode, Boolean>> capabilityTesters = new HashMap<String, ValueDeriver<ScriptNode, Boolean>>(5);
capabilityTesters.put("isAdmin", new ValueDeriver<ScriptNode, Boolean>()
{
public Boolean deriveValue(ScriptNode source)
{
return isAdmin(source);
}
});
capabilityTesters.put("isGuest", new ValueDeriver<ScriptNode, Boolean>()
{
public Boolean deriveValue(ScriptNode source)
{
return isGuest(source);
}
});
capabilityTesters.put("isMutable", new ValueDeriver<ScriptNode, Boolean>()
{
public Boolean deriveValue(ScriptNode source)
{
// Check whether the account is mutable according to the authentication service
String sourceUser = (String) source.getProperties().get(ContentModel.PROP_USERNAME);
if (!authenticationService.isAuthenticationMutable(sourceUser))
{
return false;
}
// Only allow non-admin users to mutate their own accounts
String currentUser = authenticationService.getCurrentUserName();
if (currentUser.equals(sourceUser) || authorityService.isAdminAuthority(currentUser))
{
return true;
}
return false;
}
});
this.valueDerivingMapFactory = new ValueDerivingMapFactory<ScriptNode, String, Boolean>(capabilityTesters);
}
/**
* Set the default store reference
*
* @param storeRef the default store reference
*/
public void setStoreUrl(String storeRef)
{
// ensure this is not set again by a script instance
if (this.storeRef != null)
{
throw new IllegalStateException("Default store URL can only be set once.");
}
this.storeRef = new StoreRef(storeRef);
}
/**
* Sets the authentication service.
*
* @param authenticationService
* the authentication service
*/
public void setAuthenticationService(MutableAuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
/**
* Set the service registry
*
* @param serviceRegistry the service registry
*/
public void setServiceRegistry(ServiceRegistry serviceRegistry)
{
this.services = serviceRegistry;
}
/**
* Set the authority DAO
*
* @param authorityDAO authority dao
*/
public void setAuthorityDAO(AuthorityDAO authorityDAO)
{
this.authorityDAO = authorityDAO;
}
/**
* Set the authority service
*
* @param authorityService The authorityService to set.
*/
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
/**
* Set the person service
*
* @param personService The personService to set.
*/
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param contentUsageService the ContentUsageService to set
*/
public void setContentUsageService(ContentUsageService contentUsageService)
{
this.contentUsageService = contentUsageService;
}
/**
* @param tenantService the tenantService to set
*/
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
/**
* Set the user name generator service
*
* @param userNameGenerator the user name generator
*/
public void setUserNameGenerator(UserNameGenerator userNameGenerator)
{
this.usernameGenerator = userNameGenerator;
}
/**
* Set the UserRegistrySynchronizer
*
* @param userRegistrySynchronizer
*/
public void setUserRegistrySynchronizer(UserRegistrySynchronizer userRegistrySynchronizer)
{
this.userRegistrySynchronizer = userRegistrySynchronizer;
}
/**
* Delete a Person with the given username
*
* @param username the username of the person to delete
*/
public void deletePerson(String username)
{
personService.deletePerson(username);
}
/**
* Create a Person with an optionally generated user name.
* This version doesn't notify them.
*
* @param userName userName or null for a generated user name
* @param firstName firstName
* @param lastName lastName
* @param emailAddress emailAddress
* @param password if not null creates a new authenticator with the given password.
* @param setAccountEnabled
* set to 'true' to create enabled user account, or 'false' to
* create disabled user account for created person.
* @return the person node (type cm:person) created or null if the person
* could not be created
*/
public ScriptNode createPerson(String userName, String firstName, String lastName, String emailAddress, String password, boolean setAccountEnabled)
{
return createPerson(userName, firstName, lastName, emailAddress, password, setAccountEnabled, false);
}
/**
* Create a Person with an optionally generated user name
*
* @param userName userName or null for a generated user name
* @param firstName firstName
* @param lastName lastName
* @param emailAddress emailAddress
* @param password if not null creates a new authenticator with the given password.
* @param setAccountEnabled
* set to 'true' to create enabled user account, or 'false' to
* create disabled user account for created person.
* @param notifyByEmail
* set to 'true' to have the new user emailed to let them know
* their account details. Only applies if a username and
* password were supplied.
* @return the person node (type cm:person) created or null if the person
* could not be created
*/
public ScriptNode createPerson(String userName, String firstName, String lastName, String emailAddress,
String password, boolean setAccountEnabled, boolean notifyByEmail)
{
ParameterCheck.mandatory("firstName", firstName);
ParameterCheck.mandatory("lastName", lastName);
ParameterCheck.mandatory("emailAddress", emailAddress);
ScriptNode person = null;
// generate user name if not supplied
if (userName == null)
{
for (int i=0; i < numRetries; i++)
{
userName = usernameGenerator.generateUserName(firstName, lastName, emailAddress, i);
// create person if user name does not already exist
if (!personService.personExists(userName))
{
break;
}
}
}
if (userName != null)
{
try
{
userName = PersonServiceImpl.updateUsernameForTenancy(userName, tenantService);
}
catch (TenantDomainMismatchException re)
{
throw new AuthenticationException("User must belong to same domain as admin: " + re.getTenantA());
}
person = createPerson(userName, firstName, lastName, emailAddress);
if (person != null && password != null)
{
// create account for person with the userName and password
authenticationService.createAuthentication(userName, password.toCharArray());
authenticationService.setAuthenticationEnabled(userName, setAccountEnabled);
person.save();
if(notifyByEmail)
{
personService.notifyPerson(userName, password);
}
}
}
return person;
}
/**
* Enable user account. Can only be called by an Admin authority.
*
* @param userName user name for which to enable user account
*/
public void enableAccount(String userName)
{
if (this.authorityService.isAdminAuthority(AuthenticationUtil.getFullyAuthenticatedUser()))
{
this.authenticationService.setAuthenticationEnabled(userName, true);
}
}
/**
* Disable user account. Can only be called by an Admin authority.
*
* @param userName user name for which to disable user account
*/
public void disableAccount(String userName)
{
if (this.authorityService.isAdminAuthority(AuthenticationUtil.getFullyAuthenticatedUser()))
{
this.authenticationService.setAuthenticationEnabled(userName, false);
}
}
/**
* Return true if the specified user account is enabled.
*
* @param userName user name to test account
*
* @return true if account enabled, false if disabled
*/
public boolean isAccountEnabled(String userName)
{
return this.authenticationService.getAuthenticationEnabled(userName);
}
/**
* Change the password for the currently logged in user.
* Old password must be supplied.
*
* @param oldPassword Old user password
* @param newPassword New user password
*/
public void changePassword(String oldPassword, String newPassword)
{
ParameterCheck.mandatoryString("oldPassword", oldPassword);
ParameterCheck.mandatoryString("newPassword", newPassword);
this.services.getAuthenticationService().updateAuthentication(
AuthenticationUtil.getFullyAuthenticatedUser(), oldPassword.toCharArray(), newPassword.toCharArray());
}
/**
* Set a password for the given user. Note that only an administrator
* can perform this action, otherwise it will be ignored.
*
* @param userName Username to change password for
* @param password Password to set
*/
public void setPassword(String userName, String password)
{
ParameterCheck.mandatoryString("userName", userName);
ParameterCheck.mandatoryString("password", password);
MutableAuthenticationService authService = this.services.getAuthenticationService();
if (this.authorityService.hasAdminAuthority() && (userName.equalsIgnoreCase(authService.getCurrentUserName()) == false))
{
authService.setAuthentication(userName, password.toCharArray());
}
}
/**
* Create a Person with the given user name
*
* @param userName the user name of the person to create
* @return the person node (type cm:person) created or null if the user name already exists
*/
public ScriptNode createPerson(String userName)
{
ParameterCheck.mandatoryString("userName", userName);
ScriptNode person = null;
PropertyMap properties = new PropertyMap();
properties.put(ContentModel.PROP_USERNAME, userName);
if (!personService.personExists(userName))
{
NodeRef personRef = personService.createPerson(properties);
person = new ScriptNode(personRef, services, getScope());
}
return person;
}
/**
* Create a Person with the given user name, firstName, lastName and emailAddress
*
* @param userName the user name of the person to create
* @return the person node (type cm:person) created or null if the user name already exists
*/
public ScriptNode createPerson(String userName, String firstName, String lastName, String emailAddress)
{
ParameterCheck.mandatoryString("userName", userName);
ParameterCheck.mandatoryString("firstName", firstName);
ParameterCheck.mandatoryString("lastName", lastName);
ParameterCheck.mandatoryString("emailAddress", emailAddress);
ScriptNode person = null;
PropertyMap properties = new PropertyMap();
properties.put(ContentModel.PROP_USERNAME, userName);
properties.put(ContentModel.PROP_FIRSTNAME, firstName);
properties.put(ContentModel.PROP_LASTNAME, lastName);
properties.put(ContentModel.PROP_EMAIL, emailAddress);
if (!personService.personExists(userName))
{
NodeRef personRef = personService.createPerson(properties);
person = new ScriptNode(personRef, services, getScope());
}
return person;
}
/**
* Set the content quota in bytes for a person.
* Only the admin authority can set this value.
*
* @param person Person to set quota against.
* @param quota As a string, in bytes, a value of "-1" means no quota is set
*/
public void setQuota(ScriptNode person, String quota)
{
if (this.authorityService.isAdminAuthority(AuthenticationUtil.getFullyAuthenticatedUser()))
{
this.contentUsageService.setUserQuota((String)person.getProperties().get(ContentModel.PROP_USERNAME), Long.parseLong(quota));
}
}
/**
* Get the collection of people stored in the repository.
* An optional filter query may be provided by which to filter the people collection.
* Space separate the query terms i.e. "john bob" will find all users who's first or
* second names contain the strings "john" or "bob".
*
* @param filter filter query string by which to filter the collection of people.
* If <pre>null</pre> then all people stored in the repository are returned
*
* @deprecate see getPeople(filter, maxResults)
*
* @return people collection as a JavaScript array
*/
public Scriptable getPeople(String filter)
{
return getPeople(filter, 0);
}
/**
* Get the collection of people stored in the repository.
* An optional filter query may be provided by which to filter the people collection.
* Space separate the query terms i.e. "john bob" will find all users who's first or
* second names contain the strings "john" or "bob".
*
* @param filter filter query string by which to filter the collection of people.
* If <pre>null</pre> then all people stored in the repository are returned
* @param maxResults maximum results to return or all if <= 0
*
* @return people collection as a JavaScript array
*/
public Scriptable getPeople(String filter, int maxResults)
{
Object[] people = null;
// TODO - remove open-ended query (eg cutoff at default/configurable max, eg. 5000 people)
if (maxResults <= 0)
{
maxResults = Integer.MAX_VALUE;
}
if (filter == null || filter.length() == 0)
{
PagingRequest pagingRequest = new PagingRequest(maxResults, null);
people = personService.getPeople(null, true, null, pagingRequest).getPage().toArray();
}
else
{
filter = filter.trim();
if (filter.length() != 0)
{
String term = filter.replace("\\", "").replace("\"", "");
StringTokenizer t = new StringTokenizer(term, " ");
int propIndex = term.indexOf(':');
if ((t.countTokens() == 1) && (propIndex == -1))
{
// simple non-FTS filter: firstname or lastname or username starting with term (ignoring case)
String propVal = term;
List<Pair<QName, String>> filterProps = new ArrayList<Pair<QName, String>>(3);
filterProps.add(new Pair<QName, String>(ContentModel.PROP_FIRSTNAME, propVal));
filterProps.add(new Pair<QName, String>(ContentModel.PROP_LASTNAME, propVal));
filterProps.add(new Pair<QName, String>(ContentModel.PROP_USERNAME, propVal));
PagingRequest pagingRequest = new PagingRequest(maxResults, null);
people = personService.getPeople(filterProps, true, null, pagingRequest).getPage().toArray();
}
else
{
SearchParameters params = new SearchParameters();
StringBuilder query = new StringBuilder(256);
query.append("TYPE:\"").append(ContentModel.TYPE_PERSON).append("\" AND (");
if (t.countTokens() == 1)
{
// fts-alfresco property search i.e. location:"maidenhead"
query.append(term.substring(0, propIndex+1))
.append('"')
.append(term.substring(propIndex+1))
.append('"');
}
else
{
// scan for non-fts-alfresco property search tokens
int nonFtsTokens = 0;
while (t.hasMoreTokens())
{
if (t.nextToken().indexOf(':') == -1) nonFtsTokens++;
}
t = new StringTokenizer(term, " ");
// multiple terms supplied - look for first and second name etc.
// assume first term is first name, any more are second i.e. "Fraun van de Wiels"
// also allow fts-alfresco property search to reduce results
params.setDefaultOperator(SearchParameters.Operator.AND);
boolean firstToken = true;
boolean tokenSurname = false;
boolean propertySearch = false;
while (t.hasMoreTokens())
{
term = t.nextToken();
if (!propertySearch && term.indexOf(':') == -1)
{
if (nonFtsTokens == 1)
{
// simple search: first name, last name and username starting with term
query.append("(firstName:\"");
query.append(term);
query.append("*\" OR lastName:\"");
query.append(term);
query.append("*\" OR userName:\"");
query.append(term);
query.append("*\") ");
}
else
{
if (firstToken)
{
query.append("firstName:\"");
query.append(term);
query.append("*\" ");
firstToken = false;
}
else
{
if (tokenSurname)
{
query.append("OR ");
}
query.append("lastName:\"");
query.append(term);
query.append("*\" ");
tokenSurname = true;
}
}
}
else
{
// fts-alfresco property search i.e. "location:maidenhead"
propIndex = term.indexOf(':');
query.append(term.substring(0, propIndex+1))
.append('"')
.append(term.substring(propIndex+1))
.append('"');
propertySearch = true;
}
}
}
query.append(")");
// define the search parameters
params.setLanguage(SearchService.LANGUAGE_FTS_ALFRESCO);
params.addStore(this.storeRef);
params.setQuery(query.toString());
if (maxResults > 0)
{
params.setLimitBy(LimitBy.FINAL_SIZE);
params.setLimit(maxResults);
}
ResultSet results = null;
try
{
results = services.getSearchService().query(params);
people = results.getNodeRefs().toArray();
}
catch (Throwable err)
{
// hide query parse error from users
if (logger.isDebugEnabled())
logger.debug("Failed to execute people search: " + query.toString(), err);
}
finally
{
if (results != null)
{
results.close();
}
}
}
}
}
if (people == null)
{
people = new Object[0];
}
return Context.getCurrentContext().newArray(getScope(), people);
}
/**
* Gets the Person given the username
*
* @param username the username of the person to get
* @return the person node (type cm:person) or null if no such person exists
*/
public ScriptNode getPerson(String username)
{
ParameterCheck.mandatoryString("Username", username);
ScriptNode person = null;
if (personService.personExists(username))
{
NodeRef personRef = personService.getPerson(username);
person = new ScriptNode(personRef, services, getScope());
}
return person;
}
/**
* Gets the Group given the group name
*
* @param groupName name of group to get
* @return the group node (type usr:authorityContainer) or null if no such group exists
*/
public ScriptNode getGroup(String groupName)
{
ParameterCheck.mandatoryString("GroupName", groupName);
ScriptNode group = null;
NodeRef groupRef = authorityDAO.getAuthorityNodeRefOrNull(groupName);
if (groupRef != null)
{
group = new ScriptNode(groupRef, services, getScope());
}
return group;
}
/**
* Deletes a group from the system.
*
* @param group The group to delete
*/
public void deleteGroup(ScriptNode group)
{
ParameterCheck.mandatory("Group", group);
if (group.getQNameType().equals(ContentModel.TYPE_AUTHORITY_CONTAINER))
{
String groupName = (String)group.getProperties().get(ContentModel.PROP_AUTHORITY_NAME);
authorityService.deleteAuthority(groupName);
}
}
/**
* Create a new root level group with the specified unique name
*
* @param groupName The unique group name to create - NOTE: do not prefix with "GROUP_"
*
* @return the group reference if successful or null if failed
*/
public ScriptNode createGroup(String groupName)
{
return createGroup(null, groupName);
}
/**
* Create a new group with the specified unique name
*
* @param parentGroup The parent group node - can be null for a root level group
* @param groupName The unique group name to create - NOTE: do not prefix with "GROUP_"
*
* @return the group reference if successful or null if failed
*/
public ScriptNode createGroup(ScriptNode parentGroup, String groupName)
{
ParameterCheck.mandatoryString("GroupName", groupName);
ScriptNode group = null;
String actualName = services.getAuthorityService().getName(AuthorityType.GROUP, groupName);
if (authorityService.authorityExists(actualName) == false)
{
String result = authorityService.createAuthority(AuthorityType.GROUP, groupName);
if (parentGroup != null)
{
String parentGroupName = (String)parentGroup.getProperties().get(ContentModel.PROP_AUTHORITY_NAME);
if (parentGroupName != null)
{
authorityService.addAuthority(parentGroupName, actualName);
}
}
group = getGroup(result);
}
return group;
}
/**
* Add an authority (a user or group) to a group container as a new child
*
* @param parentGroup The parent container group
* @param authority The authority (user or group) to add
*/
public void addAuthority(ScriptNode parentGroup, ScriptNode authority)
{
ParameterCheck.mandatory("Authority", authority);
ParameterCheck.mandatory("ParentGroup", parentGroup);
if (parentGroup.getQNameType().equals(ContentModel.TYPE_AUTHORITY_CONTAINER))
{
String parentGroupName = (String)parentGroup.getProperties().get(ContentModel.PROP_AUTHORITY_NAME);
String authorityName;
if (authority.getQNameType().equals(ContentModel.TYPE_AUTHORITY_CONTAINER))
{
authorityName = (String)authority.getProperties().get(ContentModel.PROP_AUTHORITY_NAME);
}
else
{
authorityName = (String)authority.getProperties().get(ContentModel.PROP_USERNAME);
}
authorityService.addAuthority(parentGroupName, authorityName);
}
}
/**
* Remove an authority (a user or group) from a group
*
* @param parentGroup The parent container group
* @param authority The authority (user or group) to remove
*/
public void removeAuthority(ScriptNode parentGroup, ScriptNode authority)
{
ParameterCheck.mandatory("Authority", authority);
ParameterCheck.mandatory("ParentGroup", parentGroup);
if (parentGroup.getQNameType().equals(ContentModel.TYPE_AUTHORITY_CONTAINER))
{
String parentGroupName = (String)parentGroup.getProperties().get(ContentModel.PROP_AUTHORITY_NAME);
String authorityName;
if (authority.getQNameType().equals(ContentModel.TYPE_AUTHORITY_CONTAINER))
{
authorityName = (String)authority.getProperties().get(ContentModel.PROP_AUTHORITY_NAME);
}
else
{
authorityName = (String)authority.getProperties().get(ContentModel.PROP_USERNAME);
}
authorityService.removeAuthority(parentGroupName, authorityName);
}
}
/**
* Gets the members (people) of a group (including all sub-groups)
*
* @param group the group to retrieve members for
* @param recurse recurse into sub-groups
*
* @return members of the group as a JavaScript array
*/
public Scriptable getMembers(ScriptNode group)
{
ParameterCheck.mandatory("Group", group);
Object[] members = getContainedAuthorities(group, AuthorityType.USER, true);
return Context.getCurrentContext().newArray(getScope(), members);
}
/**
* Gets the members (people) of a group
*
* @param group the group to retrieve members for
* @param recurse recurse into sub-groups
*
* @return the members of the group as a JavaScript array
*/
public Scriptable getMembers(ScriptNode group, boolean recurse)
{
ParameterCheck.mandatory("Group", group);
Object[] members = getContainedAuthorities(group, AuthorityType.USER, recurse);
return Context.getCurrentContext().newArray(getScope(), members);
}
/**
* Gets the groups that contain the specified authority
*
* @param person the user (cm:person) to get the containing groups for
*
* @return the containing groups as a JavaScript array
*/
public Scriptable getContainerGroups(ScriptNode person)
{
ParameterCheck.mandatory("Person", person);
Object[] parents = null;
Set<String> authorities = this.authorityService.getContainingAuthorities(
AuthorityType.GROUP,
(String)person.getProperties().get(ContentModel.PROP_USERNAME),
false);
parents = new Object[authorities.size()];
int i = 0;
for (String authority : authorities)
{
ScriptNode group = getGroup(authority);
if (group != null)
{
parents[i++] = group;
}
}
return Context.getCurrentContext().newArray(getScope(), parents);
}
/**
* Return true if the specified user is an Administrator authority.
*
* @param person to test
*
* @return true if an admin, false otherwise
*/
public boolean isAdmin(ScriptNode person)
{
ParameterCheck.mandatory("Person", person);
return this.authorityService.isAdminAuthority((String)person.getProperties().get(ContentModel.PROP_USERNAME));
}
/**
* Return true if the specified user is an guest authority.
*
* @param person to test
*
* @return true if an admin, false otherwise
*/
public boolean isGuest(ScriptNode person)
{
ParameterCheck.mandatory("Person", person);
return this.authorityService.isGuestAuthority((String) person.getProperties().get(ContentModel.PROP_USERNAME));
}
/**
* Gets a map of capabilities (boolean assertions) for the given person.
*
* @param person
* the person
* @return the capability map
*/
public Map<String, Boolean> getCapabilities(final ScriptNode person)
{
ParameterCheck.mandatory("Person", person);
Map<String,Boolean> retVal = new ScriptableHashMap<String, Boolean>();
retVal.putAll(this.valueDerivingMapFactory.getMap(person));
return retVal;
}
/**
* Return a map of the Person properties that are marked as immutable for the given user.
* This enables a script to interogate which properties are dealt with by an external
* system such as LDAP and should not be mutable in any client UI.
*
* @param username
*
* @return ScriptableHashMap
*/
public ScriptableHashMap getImmutableProperties(String username)
{
Set<QName> props = userRegistrySynchronizer.getPersonMappedProperties(username);
ScriptableHashMap propMap = new ScriptableHashMap();
for (QName prop : props)
{
propMap.put(prop.toString(), Boolean.TRUE);
}
return propMap;
}
/**
* Get Contained Authorities
*
* @param container authority containers
* @param type authority type to filter by
* @param recurse recurse into sub-containers
*
* @return contained authorities
*/
private Object[] getContainedAuthorities(ScriptNode container, AuthorityType type, boolean recurse)
{
Object[] members = null;
if (container.getQNameType().equals(ContentModel.TYPE_AUTHORITY_CONTAINER))
{
String groupName = (String)container.getProperties().get(ContentModel.PROP_AUTHORITY_NAME);
Set<String> authorities = authorityService.getContainedAuthorities(type, groupName, !recurse);
members = new Object[authorities.size()];
int i = 0;
for (String authority : authorities)
{
AuthorityType authorityType = AuthorityType.getAuthorityType(authority);
if (authorityType.equals(AuthorityType.GROUP))
{
ScriptNode group = getGroup(authority);
if (group != null)
{
members[i++] = group;
}
}
else if (authorityType.equals(AuthorityType.USER))
{
ScriptNode person = getPerson(authority);
if (person != null)
{
members[i++] = person;
}
}
}
}
return members != null ? members : new Object[0];
}
}