Merge branch 'feature/REPO-1851_get_avatar' into 'develop'

Avatars: retrieve, update and delete

See merge request !23
This commit is contained in:
Alex Mukha
2017-08-23 11:25:47 +01:00
parent 3550c00a32
commit 6fed14733c
10 changed files with 794 additions and 71 deletions

View File

@@ -25,15 +25,18 @@
*/ */
package org.alfresco.rest.api; package org.alfresco.rest.api;
import java.io.InputStream;
import java.util.List;
import org.alfresco.rest.api.model.PasswordReset; import org.alfresco.rest.api.model.PasswordReset;
import org.alfresco.rest.api.model.Person; import org.alfresco.rest.api.model.Person;
import org.alfresco.rest.framework.resource.content.BasicContentInfo;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.NoSuchPersonException; import org.alfresco.service.cmr.security.NoSuchPersonException;
import java.util.List;
public interface People public interface People
{ {
String DEFAULT_USER = "-me-"; String DEFAULT_USER = "-me-";
@@ -102,4 +105,28 @@ public interface People
* @param passwordReset the password reset details * @param passwordReset the password reset details
*/ */
void resetPassword(String personId, PasswordReset passwordReset); void resetPassword(String personId, PasswordReset passwordReset);
/**
*
* @param personId
* @param parameters
* @return
*/
BinaryResource downloadAvatarContent(String personId, Parameters parameters);
/**
*
* @param personId
* @param contentInfo
* @param stream
* @param parameters
* @return
*/
Person uploadAvatarContent(String personId, BasicContentInfo contentInfo, InputStream stream, Parameters parameters);
/**
*
* @param personId
*/
void deleteAvatarContent(String personId);
} }

View File

@@ -30,7 +30,7 @@ import org.alfresco.rest.api.model.Rendition;
import org.alfresco.rest.framework.resource.content.BinaryResource; import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
/** /**
* Renditions API * Renditions API
@@ -39,8 +39,8 @@ import org.alfresco.service.cmr.repository.NodeRef;
*/ */
public interface Renditions public interface Renditions
{ {
String PARAM_STATUS = "status"; String PARAM_STATUS = "status";
/** /**
* Lists all available renditions includes those that have been created and those that are yet to be created. * Lists all available renditions includes those that have been created and those that are yet to be created.
* *
@@ -70,6 +70,16 @@ public interface Renditions
*/ */
void createRendition(String nodeId, Rendition rendition, Parameters parameters); void createRendition(String nodeId, Rendition rendition, Parameters parameters);
/**
* Creates a rendition for the given node - either async r sync
*
* @param nodeId
* @param rendition
* @param executeAsync
* @param parameters
*/
void createRendition(String nodeId, Rendition rendition, boolean executeAsync, Parameters parameters);
/** /**
* Downloads rendition. * Downloads rendition.
* *
@@ -80,14 +90,14 @@ public interface Renditions
*/ */
BinaryResource getContent(String nodeId, String renditionId, Parameters parameters); BinaryResource getContent(String nodeId, String renditionId, Parameters parameters);
/** /**
* Downloads rendition. * Downloads rendition.
* *
* @param sourceNodeRef the source nodeRef * @param sourceNodeRef the source nodeRef
* @param renditionId the rendition id * @param renditionId the rendition id
* @param parameters the {@link Parameters} object to get the parameters passed into the request * @param parameters the {@link Parameters} object to get the parameters passed into the request
* @return the rendition stream * @return the rendition stream
*/ */
BinaryResource getContent(NodeRef sourceNodeRef, String renditionId, Parameters parameters); BinaryResource getContent(NodeRef sourceNodeRef, String renditionId, Parameters parameters);
} }

View File

@@ -37,18 +37,25 @@ import org.alfresco.repo.security.authentication.ResetPasswordServiceImpl.ResetP
import org.alfresco.repo.security.authentication.ResetPasswordServiceImpl.ResetPasswordWorkflowInvalidUserException; import org.alfresco.repo.security.authentication.ResetPasswordServiceImpl.ResetPasswordWorkflowInvalidUserException;
import org.alfresco.rest.api.Nodes; import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.People; import org.alfresco.rest.api.People;
import org.alfresco.rest.api.Renditions;
import org.alfresco.rest.api.Sites; import org.alfresco.rest.api.Sites;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.PasswordReset; import org.alfresco.rest.api.model.PasswordReset;
import org.alfresco.rest.api.model.Person; import org.alfresco.rest.api.model.Person;
import org.alfresco.rest.api.model.Rendition;
import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException; import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException;
import org.alfresco.rest.framework.core.exceptions.DisabledServiceException;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException; import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.content.BasicContentInfo;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging; import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.framework.resource.parameters.SortColumn; import org.alfresco.rest.framework.resource.parameters.SortColumn;
import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
@@ -65,6 +72,7 @@ import org.alfresco.util.Pair;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import java.io.InputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.AbstractList; import java.util.AbstractList;
import java.util.ArrayList; import java.util.ArrayList;
@@ -97,9 +105,9 @@ public class PeopleImpl implements People
PermissionService.GROUP_PREFIX, PermissionService.GROUP_PREFIX,
PermissionService.ROLE_PREFIX PermissionService.ROLE_PREFIX
}; };
protected Nodes nodes; protected Nodes nodes;
protected Sites sites; protected Sites sites;
protected SiteService siteService; protected SiteService siteService;
protected NodeService nodeService; protected NodeService nodeService;
protected PersonService personService; protected PersonService personService;
@@ -109,6 +117,7 @@ public class PeopleImpl implements People
protected ContentService contentService; protected ContentService contentService;
protected ThumbnailService thumbnailService; protected ThumbnailService thumbnailService;
protected ResetPasswordService resetPasswordService; protected ResetPasswordService resetPasswordService;
protected Renditions renditions;
private final static Map<String, QName> sort_params_to_qnames; private final static Map<String, QName> sort_params_to_qnames;
static static
@@ -175,6 +184,12 @@ public class PeopleImpl implements People
this.resetPasswordService = resetPasswordService; this.resetPasswordService = resetPasswordService;
} }
public void setRenditions(Renditions renditions)
{
this.renditions = renditions;
}
/** /**
* Validate, perform -me- substitution and canonicalize the person ID. * Validate, perform -me- substitution and canonicalize the person ID.
* *
@@ -257,53 +272,134 @@ public class PeopleImpl implements People
public boolean hasAvatar(NodeRef personNodeRef) public boolean hasAvatar(NodeRef personNodeRef)
{ {
if(personNodeRef != null) return (getAvatarOriginal(personNodeRef) != null);
{
List<AssociationRef> avatorAssocs = nodeService.getTargetAssocs(personNodeRef, ContentModel.ASSOC_AVATAR);
return(avatorAssocs.size() > 0);
}
else
{
return false;
}
} }
@Override @Override
public NodeRef getAvatar(String personId) public NodeRef getAvatar(String personId)
{ {
NodeRef avatar = null; NodeRef avatar = null;
personId = validatePerson(personId); personId = validatePerson(personId);
NodeRef personNode = personService.getPerson(personId); NodeRef personNode = personService.getPerson(personId);
if(personNode != null) if(personNode != null)
{ {
List<AssociationRef> avatorAssocs = nodeService.getTargetAssocs(personNode, ContentModel.ASSOC_AVATAR); NodeRef avatarOrig = getAvatarOriginal(personNode);
if(avatorAssocs.size() > 0) avatar = thumbnailService.getThumbnailByName(avatarOrig, ContentModel.PROP_CONTENT, "avatar");
{
AssociationRef ref = avatorAssocs.get(0);
NodeRef thumbnailNodeRef = thumbnailService.getThumbnailByName(ref.getTargetRef(), ContentModel.PROP_CONTENT, "avatar");
if(thumbnailNodeRef != null)
{
avatar = thumbnailNodeRef;
}
else
{
throw new EntityNotFoundException("avatar");
}
}
else
{
throw new EntityNotFoundException("avatar");
}
} }
else
if (avatar == null)
{ {
throw new EntityNotFoundException(personId); throw new EntityNotFoundException(personId);
} }
return avatar; return avatar;
} }
private NodeRef getAvatarOriginal(NodeRef personNode)
{
NodeRef avatarOrigNodeRef = null;
List<ChildAssociationRef> avatarChildAssocs = nodeService.getChildAssocs(personNode, Collections.singleton(ContentModel.ASSOC_PREFERENCE_IMAGE));
if (avatarChildAssocs.size() > 0)
{
ChildAssociationRef ref = avatarChildAssocs.get(0);
avatarOrigNodeRef = ref.getChildRef();
}
else
{
// TODO do we still need this ? - backward compatible with JSF web-client avatar
List<AssociationRef> avatorAssocs = nodeService.getTargetAssocs(personNode, ContentModel.ASSOC_AVATAR);
if (avatorAssocs.size() > 0)
{
AssociationRef ref = avatorAssocs.get(0);
avatarOrigNodeRef = ref.getTargetRef();
}
}
return avatarOrigNodeRef;
}
@Override
public BinaryResource downloadAvatarContent(String personId, Parameters parameters)
{
personId = validatePerson(personId);
NodeRef personNode = personService.getPerson(personId);
NodeRef avatarNodeRef = getAvatarOriginal(personNode);
return renditions.getContent(avatarNodeRef, "avatar", parameters);
}
@Override
public Person uploadAvatarContent(String personId, BasicContentInfo contentInfo, InputStream stream, Parameters parameters)
{
if (!thumbnailService.getThumbnailsEnabled())
{
throw new DisabledServiceException("Thumbnail generation has been disabled.");
}
personId = validatePerson(personId);
checkCurrentUserOrAdmin(personId);
NodeRef personNode = personService.getPerson(personId);
NodeRef avatarOrigNodeRef = getAvatarOriginal(personNode);
if (avatarOrigNodeRef != null)
{
deleteAvatar(avatarOrigNodeRef);
}
QName origAvatarQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "origAvatar");
nodeService.addAspect(personNode, ContentModel.ASPECT_PREFERENCES, null);
ChildAssociationRef assoc = nodeService.createNode(personNode, ContentModel.ASSOC_PREFERENCE_IMAGE, origAvatarQName,
ContentModel.TYPE_CONTENT);
NodeRef avatar = assoc.getChildRef();
String avatarOriginalNodeId = avatar.getId();
// TODO do we still need this ? - backward compatible with JSF web-client avatar
nodeService.createAssociation(personNode, avatar, ContentModel.ASSOC_AVATAR);
Node n = nodes.updateContent(avatarOriginalNodeId, contentInfo, stream, parameters);
String mimeType = n.getContent().getMimeType();
if (mimeType.indexOf("image/") != 0)
{
throw new InvalidArgumentException(
"Uploaded content must be an image (content type determined to be '"+mimeType+"')");
}
// create thumbnail synchronously
Rendition avatarR = new Rendition();
avatarR.setId("avatar");
renditions.createRendition(avatarOriginalNodeId, avatarR, false, parameters);
List<String> include = Arrays.asList(
PARAM_INCLUDE_ASPECTNAMES,
PARAM_INCLUDE_PROPERTIES);
return getPersonWithProperties(personId, include);
}
@Override
public void deleteAvatarContent(String personId)
{
personId = validatePerson(personId);
checkCurrentUserOrAdmin(personId);
NodeRef personNode = personService.getPerson(personId);
NodeRef avatarOrigNodeRef = getAvatarOriginal(personNode);
if (avatarOrigNodeRef != null)
{
deleteAvatar(avatarOrigNodeRef);
}
}
private void deleteAvatar(NodeRef avatarOrigNodeRef)
{
// Set as temporary to permanently delete node (instead of archiving)
nodeService.addAspect(avatarOrigNodeRef, ContentModel.ASPECT_TEMPORARY, null);
nodeService.deleteNode(avatarOrigNodeRef);
}
/** /**
* Get a full representation of a person. * Get a full representation of a person.
* *
@@ -612,14 +708,8 @@ public class PeopleImpl implements People
personId = validatePerson(personId); personId = validatePerson(personId);
validateUpdatePersonData(person); validateUpdatePersonData(person);
boolean isAdmin = isAdminAuthority(); // Check if user updating *their own* details or is an admin
boolean isAdmin = checkCurrentUserOrAdmin(personId);
String currentUserId = AuthenticationUtil.getFullyAuthenticatedUser();
if (!isAdmin && !currentUserId.equalsIgnoreCase(personId))
{
// The user is not an admin user and is not attempting to update *their own* details.
throw new PermissionDeniedException();
}
final String personIdToUpdate = validatePerson(personId); final String personIdToUpdate = validatePerson(personId);
final Map<QName, Serializable> properties = person.toProperties(); final Map<QName, Serializable> properties = person.toProperties();
@@ -675,6 +765,19 @@ public class PeopleImpl implements People
return getPerson(personId); return getPerson(personId);
} }
private boolean checkCurrentUserOrAdmin(String personId)
{
boolean isAdmin = isAdminAuthority();
String currentUserId = AuthenticationUtil.getFullyAuthenticatedUser();
if (!isAdmin && !currentUserId.equalsIgnoreCase(personId))
{
throw new PermissionDeniedException();
}
return isAdmin;
}
private void validateUpdatePersonData(Person person) private void validateUpdatePersonData(Person person)
{ {
validateNamespaces(person.getAspectNames(), person.getProperties()); validateNamespaces(person.getAspectNames(), person.getProperties());

View File

@@ -260,6 +260,12 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
@Override @Override
public void createRendition(String nodeId, Rendition rendition, Parameters parameters) public void createRendition(String nodeId, Rendition rendition, Parameters parameters)
{
createRendition(nodeId, rendition, true, parameters);
}
@Override
public void createRendition(String nodeId, Rendition rendition, boolean executeAsync, Parameters parameters)
{ {
// If thumbnail generation has been configured off, then don't bother. // If thumbnail generation has been configured off, then don't bother.
if (!thumbnailService.getThumbnailsEnabled()) if (!thumbnailService.getThumbnailsEnabled())
@@ -292,8 +298,9 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
} }
Action action = ThumbnailHelper.createCreateThumbnailAction(thumbnailDefinition, serviceRegistry); Action action = ThumbnailHelper.createCreateThumbnailAction(thumbnailDefinition, serviceRegistry);
// Queue async creation of thumbnail
actionService.executeAction(action, sourceNodeRef, true, true); // Create thumbnail - or else queue for async creation
actionService.executeAction(action, sourceNodeRef, true, executeAsync);
} }
@Override @Override
@@ -324,7 +331,15 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
{ {
throw new NotFoundException("Thumbnail was not found for [" + renditionId + ']'); throw new NotFoundException("Thumbnail was not found for [" + renditionId + ']');
} }
String sourceNodeMimeType = getMimeType(sourceNodeRef); String sourceNodeMimeType = null;
try
{
sourceNodeMimeType = (sourceNodeRef != null ? getMimeType(sourceNodeRef) : null);
}
catch (InvalidArgumentException e)
{
// No content for node, e.g. ASSOC_AVATAR rather than ASSOC_PREFERENCE_IMAGE
}
// resource based on the content's mimeType and rendition id // resource based on the content's mimeType and rendition id
String phPath = scriptThumbnailService.getMimeAwarePlaceHolderResourcePath(renditionId, sourceNodeMimeType); String phPath = scriptThumbnailService.getMimeAwarePlaceHolderResourcePath(renditionId, sourceNodeMimeType);
if (phPath == null) if (phPath == null)
@@ -388,6 +403,11 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
protected NodeRef getRenditionByName(NodeRef nodeRef, String renditionId, Parameters parameters) protected NodeRef getRenditionByName(NodeRef nodeRef, String renditionId, Parameters parameters)
{ {
if (nodeRef == null)
{
return null;
}
if (StringUtils.isEmpty(renditionId)) if (StringUtils.isEmpty(renditionId))
{ {
throw new InvalidArgumentException("renditionId can't be null or empty."); throw new InvalidArgumentException("renditionId can't be null or empty.");

View File

@@ -25,19 +25,30 @@
*/ */
package org.alfresco.rest.api.people; package org.alfresco.rest.api.people;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.rest.api.People; import org.alfresco.rest.api.People;
import org.alfresco.rest.api.model.Client; import org.alfresco.rest.api.model.Client;
import org.alfresco.rest.api.model.PasswordReset; import org.alfresco.rest.api.model.PasswordReset;
import org.alfresco.rest.api.model.Person; import org.alfresco.rest.api.model.Person;
import org.alfresco.rest.framework.BinaryProperties;
import org.alfresco.rest.framework.Operation; import org.alfresco.rest.framework.Operation;
import org.alfresco.rest.framework.WebApiDescription; import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.WebApiNoAuth; import org.alfresco.rest.framework.WebApiNoAuth;
import org.alfresco.rest.framework.WebApiParam; import org.alfresco.rest.framework.WebApiParam;
import org.alfresco.rest.framework.core.ResourceParameter; import org.alfresco.rest.framework.core.ResourceParameter;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.EntityResource; import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.actions.interfaces.BinaryResourceAction;
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction; import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
import org.alfresco.rest.framework.resource.content.BasicContentInfo;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.framework.webscripts.WithResponse; import org.alfresco.rest.framework.webscripts.WithResponse;
@@ -46,10 +57,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
/** /**
* An implementation of an Entity Resource for a Person * An implementation of an Entity Resource for a Person
* *
@@ -57,12 +64,15 @@ import java.util.List;
* @author Gethin James * @author Gethin James
*/ */
@EntityResource(name="people", title = "People") @EntityResource(name="people", title = "People")
public class PeopleEntityResource implements EntityResourceAction.ReadById<Person>, EntityResourceAction.Create<Person>, EntityResourceAction.Update<Person>,EntityResourceAction.Read<Person>, InitializingBean public class PeopleEntityResource implements EntityResourceAction.ReadById<Person>, EntityResourceAction.Create<Person>,
EntityResourceAction.Update<Person>,EntityResourceAction.Read<Person>,
BinaryResourceAction.Read, BinaryResourceAction.Update<Person>, BinaryResourceAction.Delete, InitializingBean
{ {
private static Log logger = LogFactory.getLog(PeopleEntityResource.class); private static Log logger = LogFactory.getLog(PeopleEntityResource.class);
private People people; private People people;
public void setPeople(People people) public void setPeople(People people)
{ {
this.people = people; this.people = people;
@@ -169,4 +179,54 @@ public class PeopleEntityResource implements EntityResourceAction.ReadById<Perso
{ {
people.resetPassword(personId, passwordReset); people.resetPassword(personId, passwordReset);
} }
/**
* Download avatar image content
*
* @param personId
* @param parameters {@link Parameters}
* @return
* @throws EntityNotFoundException
*/
@Override
@WebApiDescription(title = "Download avatar", description = "Download avatar")
@BinaryProperties({"avatar"})
public BinaryResource readProperty(String personId, Parameters parameters) throws EntityNotFoundException
{
return people.downloadAvatarContent(personId, parameters);
}
/**
* Upload avatar image content
*
* @param personId
* @param contentInfo Basic information about the content stream
* @param stream An inputstream
* @param parameters
* @return
*/
@Override
@WebApiDescription(title = "Upload avatar", description = "Upload avatar")
@BinaryProperties({"avatar"})
public Person updateProperty(String personId, BasicContentInfo contentInfo, InputStream stream, Parameters parameters)
{
return people.uploadAvatarContent(personId, contentInfo, stream, parameters);
}
/**
* Delete avatar image content
*
* @param personId
* @param parameters
* @return
*/
@Override
@WebApiDescription(title = "Delete avatar image", description = "Delete avatar image")
@BinaryProperties({ "avatar" })
public void deleteProperty(String personId, Parameters parameters)
{
people.deleteAvatarContent(personId);
}
} }

View File

@@ -667,6 +667,7 @@
<bean id="people" class="org.alfresco.rest.api.impl.PeopleImpl"> <bean id="people" class="org.alfresco.rest.api.impl.PeopleImpl">
<property name="nodes" ref="Nodes" /> <property name="nodes" ref="Nodes" />
<property name="sites" ref="sites" /> <property name="sites" ref="sites" />
<property name="renditions" ref="Renditions" />
<property name="siteService" ref="SiteService" /> <property name="siteService" ref="SiteService" />
<property name="nodeService" ref="NodeService" /> <property name="nodeService" ref="NodeService" />
<property name="personService" ref="PersonService" /> <property name="personService" ref="PersonService" />

View File

@@ -26,12 +26,15 @@
package org.alfresco.rest.api.tests; package org.alfresco.rest.api.tests;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.ContentLimitProvider;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.ResetPasswordServiceImpl; import org.alfresco.repo.security.authentication.ResetPasswordServiceImpl;
import org.alfresco.rest.api.Renditions;
import org.alfresco.rest.api.model.Client; import org.alfresco.rest.api.model.Client;
import org.alfresco.rest.api.model.LoginTicket; import org.alfresco.rest.api.model.LoginTicket;
import org.alfresco.rest.api.model.LoginTicketResponse; import org.alfresco.rest.api.model.LoginTicketResponse;
import org.alfresco.rest.api.model.PasswordReset; import org.alfresco.rest.api.model.PasswordReset;
import org.alfresco.rest.api.model.Rendition;
import org.alfresco.rest.api.tests.RepoService.TestNetwork; import org.alfresco.rest.api.tests.RepoService.TestNetwork;
import org.alfresco.rest.api.tests.client.HttpResponse; import org.alfresco.rest.api.tests.client.HttpResponse;
import org.alfresco.rest.api.tests.client.Pair; import org.alfresco.rest.api.tests.client.Pair;
@@ -42,21 +45,32 @@ import org.alfresco.rest.api.tests.client.RequestContext;
import org.alfresco.rest.api.tests.client.data.Company; import org.alfresco.rest.api.tests.client.data.Company;
import org.alfresco.rest.api.tests.client.data.JSONAble; import org.alfresco.rest.api.tests.client.data.JSONAble;
import org.alfresco.rest.api.tests.client.data.Person; import org.alfresco.rest.api.tests.client.data.Person;
import org.alfresco.util.email.EmailUtil;
import org.alfresco.rest.api.tests.util.RestApiUtil; import org.alfresco.rest.api.tests.util.RestApiUtil;
import org.alfresco.service.cmr.preference.PreferenceService; import org.alfresco.service.cmr.preference.PreferenceService;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentService;
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.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
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.util.GUID;
import org.alfresco.util.email.EmailUtil;
import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.HttpStatus;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -69,8 +83,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
import javax.mail.internet.MimeMessage;
import static org.alfresco.repo.security.authentication.ResetPasswordServiceImplTest.getWorkflowIdAndKeyFromUrl; import static org.alfresco.repo.security.authentication.ResetPasswordServiceImplTest.getWorkflowIdAndKeyFromUrl;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@@ -1920,6 +1933,360 @@ public class TestPeople extends AbstractBaseApiTest
return URL_PEOPLE + '/' + userId + "/reset-password"; return URL_PEOPLE + '/' + userId + "/reset-password";
} }
@Test
public void retrieveAvatar() throws Exception
{
final String person1 = account1PersonIt.next();
publicApiClient.setRequestContext(new RequestContext(account1.getId(), person1));
AuthenticationUtil.setFullyAuthenticatedUser(person1);
NodeRef person1Ref = personService.getPerson(person1, false);
// No avatar, but valid person
{
deleteAvatarDirect(person1Ref);
assertNotNull(people.getPerson(person1)); // Pre-condition of test case
people.getAvatar(person1, false, 404);
}
// No avatar, but person exists and placeholder requested
{
assertNotNull(people.getPerson(person1)); // Pre-condition of test case
people.getAvatar(person1, true, 200);
}
// Non-existent person
{
String nonPerson = "i-do-not-exist";
people.getPerson(nonPerson, 404); // Pre-condition of test case
people.getAvatar(nonPerson, false, 404);
}
// Placeholder requested, but non-existent person
{
String nonPerson = "i-do-not-exist";
people.getPerson(nonPerson, 404); // Pre-condition of test case
people.getAvatar(nonPerson, true, 404);
}
// Avatar exists
{
// Create avatar - direct (i.e. not using the API, so that tests for get avatar can be separated from upload)
// There's no significance to the image being used here, it was the most suitable I could find.
ClassPathResource thumbRes = new ClassPathResource("test.jpg");
deleteAvatarDirect(person1Ref);
createAvatarDirect(person1Ref, thumbRes.getFile());
// Get avatar - API call
people.getAvatar(person1, false, 200);
}
// -me- alias
{
people.getAvatar("-me-", false, 200);
}
// If-Modified-Since behaviour
{
HttpResponse response = people.getAvatar(person1, false, 200);
Map<String, String> responseHeaders = response.getHeaders();
// Test 304 response
String lastModified = responseHeaders.get(LAST_MODIFIED_HEADER);
assertNotNull(lastModified);
// Has it been modified since the time it was last modified - no!
people.getAvatar(person1, lastModified, 304);
// Create an updated avatar
waitMillis(2000); // ensure time has passed between updates
ClassPathResource thumbRes = new ClassPathResource("publicapi/upload/quick.jpg");
deleteAvatarDirect(person1Ref);
createAvatarDirect(person1Ref, thumbRes.getFile());
people.getAvatar(person1, lastModified, 200);
}
// Attachment param
{
// No attachment parameter (default true)
Boolean attachmentParam = null;
HttpResponse response = people.getAvatar(person1, attachmentParam, false, null, 200);
Map<String, String> responseHeaders = response.getHeaders();
String contentDisposition = responseHeaders.get("Content-Disposition");
assertNotNull(contentDisposition);
assertTrue(contentDisposition.startsWith("attachment;"));
// attachment=true
attachmentParam = true;
response = people.getAvatar(person1, attachmentParam, false, null, 200);
responseHeaders = response.getHeaders();
contentDisposition = responseHeaders.get("Content-Disposition");
assertNotNull(contentDisposition);
assertTrue(contentDisposition.startsWith("attachment;"));
// attachment=false
attachmentParam = false;
response = people.getAvatar(person1, attachmentParam, false, null, 200);
responseHeaders = response.getHeaders();
contentDisposition = responseHeaders.get("Content-Disposition");
assertNull(contentDisposition);
}
}
private void waitMillis(int requiredDelay)
{
long startTime = System.currentTimeMillis();
long currTime = startTime;
while (currTime < (startTime + requiredDelay))
{
try
{
Thread.sleep(requiredDelay);
}
catch (InterruptedException e)
{
System.out.println(":>>> " + e.getMessage());
}
finally
{
currTime = System.currentTimeMillis();
System.out.println(":>>> waited "+(currTime-startTime) + "ms");
}
}
}
private void deleteAvatarDirect(NodeRef personRef)
{
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(personRef).
stream().
filter(x -> x.getTypeQName().equals(ContentModel.ASSOC_PREFERENCE_IMAGE)).
collect(Collectors.toList());
if (assocs.size() > 0)
{
nodeService.deleteNode(assocs.get(0).getChildRef());
}
// remove old association if it exists
List<AssociationRef> refs = nodeService.getTargetAssocs(personRef, ContentModel.ASSOC_AVATAR);
if (refs.size() == 1)
{
NodeRef existingRef = refs.get(0).getTargetRef();
nodeService.removeAssociation(
personRef, existingRef, ContentModel.ASSOC_AVATAR);
}
if (assocs.size() > 1 || refs.size() > 1)
{
fail(String.format("Pref images: %d, Avatar assocs: %d", assocs.size(), refs.size()));
}
}
private NodeRef createAvatarDirect(NodeRef personRef, File avatarFile)
{
// create new avatar node
nodeService.addAspect(personRef, ContentModel.ASPECT_PREFERENCES, null);
ChildAssociationRef assoc = nodeService.createNode(
personRef,
ContentModel.ASSOC_PREFERENCE_IMAGE,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "origAvatar"),
ContentModel.TYPE_CONTENT);
final NodeRef avatarRef = assoc.getChildRef();
// JSF client compatibility?
nodeService.createAssociation(personRef, avatarRef, ContentModel.ASSOC_AVATAR);
// upload the avatar content
ContentService contentService = applicationContext.getBean("ContentService", ContentService.class);
ContentWriter writer = contentService.getWriter(avatarRef, ContentModel.PROP_CONTENT, true);
writer.guessMimetype(avatarFile.getName());
writer.putContent(avatarFile);
Rendition avatarR = new Rendition();
avatarR.setId("avatar");
Renditions renditions = applicationContext.getBean("Renditions", Renditions.class);
renditions.createRendition(avatarRef.getId(), avatarR, false, null);
return avatarRef;
}
@Test
public void updateAvatar() throws PublicApiException, IOException
{
final String person1 = account1PersonIt.next();
final String person2 = account1PersonIt.next();
publicApiClient.setRequestContext(new RequestContext(account1.getId(), person2));
AuthenticationUtil.setFullyAuthenticatedUser(person2);
// Update allowed when no existing avatar
{
// Pre-condition: no avatar exists
NodeRef personRef = personService.getPerson(person2, false);
deleteAvatarDirect(personRef);
people.getAvatar(person2, false, 404);
// TODO: What do we expect the 200 response body to be? Currently it's the person JSON - doesn't seem right.
ClassPathResource avatar = new ClassPathResource("publicapi/upload/quick.jpg");
HttpResponse response = people.updateAvatar(person2, avatar.getFile(), 200);
// TODO: ideally, this should be a "direct" retrieval to isolate update from get
people.getAvatar(person2, false, 200);
}
// Update existing avatar
{
// Pre-condition: avatar exists
people.getAvatar(person2, false, 200);
ClassPathResource avatar = new ClassPathResource("test.jpg");
HttpResponse response = people.updateAvatar(person2, avatar.getFile(), 200);
people.getAvatar(person2, false, 200);
// -me- alias
people.updateAvatar(person2, avatar.getFile(), 200);
people.getAvatar("-me-", false, 200);
}
// 400: invalid user ID
{
ClassPathResource avatar = new ClassPathResource("publicapi/upload/quick.jpg");
people.updateAvatar("joe@@bloggs.example.com", avatar.getFile(), 404);
}
// 401: authentication failure
{
publicApiClient.setRequestContext(new RequestContext(account1.getId(), account1Admin, "Wr0ngP4ssw0rd!"));
ClassPathResource avatar = new ClassPathResource("publicapi/upload/quick.jpg");
people.updateAvatar(account1Admin, avatar.getFile(), 401);
}
// 403: permission denied
{
publicApiClient.setRequestContext(new RequestContext(account1.getId(), person1));
ClassPathResource avatar = new ClassPathResource("publicapi/upload/quick.jpg");
people.updateAvatar(person2, avatar.getFile(), 403);
// Person can update themself
people.updateAvatar(person1, avatar.getFile(), 200);
// Admin can update someone else
publicApiClient.setRequestContext(new RequestContext(account1.getId(), account1Admin, "admin"));
people.updateAvatar(person1, avatar.getFile(), 200);
}
// 404: non-existent person
{
publicApiClient.setRequestContext(new RequestContext(account1.getId(), person1));
// Pre-condition: non-existent person
String nonPerson = "joebloggs@"+account1.getId();
people.getPerson(nonPerson, 404);
ClassPathResource avatar = new ClassPathResource("publicapi/upload/quick.jpg");
people.updateAvatar(nonPerson, avatar.getFile(), 404);
}
// 413: content exceeds individual file size limit
{
// Test content size limit
final ContentLimitProvider.SimpleFixedLimitProvider limitProvider = applicationContext.
getBean("defaultContentLimitProvider", ContentLimitProvider.SimpleFixedLimitProvider.class);
final long defaultSizeLimit = limitProvider.getSizeLimit();
limitProvider.setSizeLimitString("20000"); //20 KB
try
{
ClassPathResource avatar = new ClassPathResource("publicapi/upload/quick.jpg"); // ~26K
people.updateAvatar(person1, avatar.getFile(), 413);
}
finally
{
limitProvider.setSizeLimitString(Long.toString(defaultSizeLimit));
}
}
// 501: thumbnails disabled
{
ThumbnailService thumbnailService = applicationContext.getBean("thumbnailService", ThumbnailService.class);
// Disable thumbnail generation
thumbnailService.setThumbnailsEnabled(false);
try
{
ClassPathResource avatar = new ClassPathResource("publicapi/upload/quick.jpg");
people.updateAvatar(person1, avatar.getFile(), 501);
}
finally
{
thumbnailService.setThumbnailsEnabled(true);
}
}
}
@Test
public void removeAvatar() throws IOException, PublicApiException{
final String person1 = account1PersonIt.next();
final String person2 = account1PersonIt.next();
publicApiClient.setRequestContext(new RequestContext(account1.getId(), person1));
// Avatar exists
{
AuthenticationUtil.setFullyAuthenticatedUser("admin@"+account1.getId());
// Create avatar - direct (i.e. not using the API, so that tests for get avatar can be separated from upload)
// There's no significance to the image being used here, it was the most suitable I could find.
ClassPathResource thumbRes = new ClassPathResource("publicapi/upload/quick.jpg");
NodeRef personRef = personService.getPerson(person1, false);
deleteAvatarDirect(personRef);
createAvatarDirect(personRef, thumbRes.getFile());
// Get avatar - API call
people.getAvatar(person1, false, 200);
//remove avatar avatar exists
people.deleteAvatarImage(person1,204);
}
// Non-existent person
{
String nonPerson = "i-do-not-exist";
people.getPerson(nonPerson, 404); // Pre-condition of test case
people.deleteAvatarImage(nonPerson, 404);
}
//Authentication failed 401
{
setRequestContext(account1.getId(), networkAdmin, "wrongPassword");
people.deleteAvatarImage(person1,HttpServletResponse.SC_UNAUTHORIZED);
}
//No permission
{
publicApiClient.setRequestContext(new RequestContext(account1.getId(), person1));
AuthenticationUtil.setFullyAuthenticatedUser("admin@"+account1.getId());
// Create avatar - direct (i.e. not using the API, so that tests for get avatar can be separated from upload)
// There's no significance to the image being used here, it was the most suitable I could find.
ClassPathResource thumbRes = new ClassPathResource("test.jpg");
NodeRef personRef = personService.getPerson(person1, false);
deleteAvatarDirect(personRef);
createAvatarDirect(personRef, thumbRes.getFile());
people.deleteAvatarImage(person2, 403);
}
}
@Override @Override
public String getScope() public String getScope()
{ {

View File

@@ -27,6 +27,7 @@ package org.alfresco.rest.api.tests.client;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Serializable; import java.io.Serializable;
@@ -47,7 +48,6 @@ import org.alfresco.rest.api.tests.client.data.AuditEntry;
import org.alfresco.rest.api.model.SiteUpdate; import org.alfresco.rest.api.model.SiteUpdate;
import org.alfresco.rest.api.tests.TestPeople; import org.alfresco.rest.api.tests.TestPeople;
import org.alfresco.rest.api.tests.TestSites; import org.alfresco.rest.api.tests.TestSites;
import org.alfresco.rest.api.tests.client.PublicApiClient.ListResponse;
import org.alfresco.rest.api.tests.client.PublicApiHttpClient.BinaryPayload; import org.alfresco.rest.api.tests.client.PublicApiHttpClient.BinaryPayload;
import org.alfresco.rest.api.tests.client.PublicApiHttpClient.RequestBuilder; import org.alfresco.rest.api.tests.client.PublicApiHttpClient.RequestBuilder;
import org.alfresco.rest.api.tests.client.data.Activities; import org.alfresco.rest.api.tests.client.data.Activities;
@@ -546,15 +546,20 @@ public class PublicApiClient
return response; return response;
} }
public HttpResponse get(String scope, String entityCollectionName, Object entityId, String relationCollectionName, Object relationshipEntityId, Map<String, String> params) throws IOException public HttpResponse get(String scope, String entityCollectionName, Object entityId, String relationCollectionName, Object relationshipEntityId, Map<String, String> params, Map<String, String> headers) throws IOException
{ {
HttpResponse response = client.get(getRequestContext(), scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params); HttpResponse response = client.get(getRequestContext(), scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params, headers);
logger.debug(response.toString()); logger.debug(response.toString());
return response; return response;
} }
public HttpResponse get(String scope, String entityCollectionName, Object entityId, String relationCollectionName, Object relationshipEntityId, Map<String, String> params) throws IOException
{
return get(scope, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params, null);
}
public HttpResponse getWithPassword(String scope, String password, String entityCollectionName, Object entityId, String relationCollectionName, Object relationshipEntityId, Map<String, String> params) throws IOException public HttpResponse getWithPassword(String scope, String password, String entityCollectionName, Object entityId, String relationCollectionName, Object relationshipEntityId, Map<String, String> params) throws IOException
{ {
HttpResponse response = client.get(getRequestContext(), scope, password, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params); HttpResponse response = client.get(getRequestContext(), scope, password, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params);
@@ -728,6 +733,21 @@ public class PublicApiClient
} }
} }
public HttpResponse getSingle(String entityCollectionName, String entityId, String relationCollectionName, String relationId, Map<String, String> params,
Map<String, String> headers, String errorMessage, int expectedStatus) throws PublicApiException
{
try
{
HttpResponse response = get("public", entityCollectionName, entityId, relationCollectionName, relationId, params, headers);
checkStatus(errorMessage, expectedStatus, response);
return response;
}
catch (IOException e)
{
throw new PublicApiException(e);
}
}
public HttpResponse getSingle(String entityCollectionName, String entityId, String relationCollectionName, String relationId, Map<String, String> params, public HttpResponse getSingle(String entityCollectionName, String entityId, String relationCollectionName, String relationId, Map<String, String> params,
String errorMessage, int expectedStatus) throws PublicApiException String errorMessage, int expectedStatus) throws PublicApiException
{ {
@@ -1305,6 +1325,59 @@ public class PublicApiClient
{ {
remove("people", personId, "activities", String.valueOf(activity.getId()), "Failed to remove activity"); remove("people", personId, "activities", String.valueOf(activity.getId()), "Failed to remove activity");
} }
public HttpResponse getAvatar(String personId, boolean placeholder, int expectedStatus) throws PublicApiException
{
return getAvatar(personId, null, placeholder, null, expectedStatus);
}
public HttpResponse getAvatar(String personId, String ifModifiedSince, int expectedStatus) throws PublicApiException
{
return getAvatar(personId, null, false, ifModifiedSince, expectedStatus);
}
public HttpResponse getAvatar(String personId, Boolean attachment, boolean placeholder, String ifModifiedSince, int expectedStatus) throws PublicApiException
{
// Binary response expected
Map<String, String> params = new HashMap<>();
params.put("placeholder", Boolean.toString(placeholder));
// Optional attachment parameter
if (attachment != null)
{
params.put("attachment", attachment.toString());
}
Map<String, String> headers = new HashMap<>();
if (ifModifiedSince != null)
{
headers.put("If-Modified-Since", ifModifiedSince);
}
HttpResponse response = getSingle("people", personId, "avatar", null, params, headers, "Failed to get avatar", expectedStatus);
checkStatus("Unexpected response", expectedStatus, response);
return response;
}
public HttpResponse updateAvatar(String personId, File avatar, int expectedStatus) throws PublicApiException
{
try
{
Map<String, String> params = new HashMap<>();
BinaryPayload payload = new BinaryPayload(avatar);
HttpResponse response = client.putBinary(getRequestContext(), "public", 1, "people", personId, "avatar", null, payload, params);
checkStatus("Unexpected status", expectedStatus, response);
return response;
}
catch(IOException e)
{
throw new PublicApiException(e);
}
}
public void deleteAvatarImage(String personId, int expectedStatus) throws PublicApiException{
remove("people", personId, "avatar", null, null, "Failed to remove avatar image", expectedStatus);
}
} }
public class Comments extends AbstractProxy public class Comments extends AbstractProxy

View File

@@ -34,6 +34,7 @@ import java.io.OutputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@@ -312,17 +313,34 @@ public class PublicApiHttpClient
public HttpResponse get(final RequestContext rq, String scope, final String entityCollectionName, final Object entityId, public HttpResponse get(final RequestContext rq, String scope, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, Map<String, String> params) throws IOException final String relationCollectionName, final Object relationshipEntityId, Map<String, String> params) throws IOException
{ {
return get(rq, scope, 1, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params); return get(rq, scope, 1, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params, null);
}
public HttpResponse get(final RequestContext rq, String scope, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, Map<String, String> params, Map<String, String> headers) throws IOException
{
return get(rq, scope, 1, entityCollectionName, entityId, relationCollectionName, relationshipEntityId, params, headers);
} }
public HttpResponse get(final RequestContext rq, final String scope, final int version, final String entityCollectionName, final Object entityId, public HttpResponse get(final RequestContext rq, final String scope, final int version, final String entityCollectionName, final Object entityId,
final String relationCollectionName, final Object relationshipEntityId, Map<String, String> params) throws IOException final String relationCollectionName, final Object relationshipEntityId, Map<String, String> params, Map<String, String> headers) throws IOException
{ {
if (headers == null)
{
headers = Collections.emptyMap();
}
RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, version, entityCollectionName, entityId, relationCollectionName, RestApiEndpoint endpoint = new RestApiEndpoint(rq.getNetworkId(), scope, version, entityCollectionName, entityId, relationCollectionName,
relationshipEntityId, params); relationshipEntityId, params);
String url = endpoint.getUrl(); String url = endpoint.getUrl();
GetMethod req = new GetMethod(url); GetMethod req = new GetMethod(url);
for (Entry<String, String> header : headers.entrySet())
{
req.addRequestHeader(header.getKey(), header.getValue());
}
return submitRequest(req, rq); return submitRequest(req, rq);
} }

View File

@@ -0,0 +1,44 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* 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/>.
* #L%
*/
package org.alfresco.rest.api.tests.client.data;
import org.json.simple.JSONObject;
import java.io.Serializable;
public class Avatar implements Serializable, ExpectedComparison
{
@Override
public void expected(Object other)
{
}
public static Avatar parseAvatar(JSONObject entry)
{
return new Avatar();
}
}