mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V3.2 to HEAD
18052: Merged DEV/REPO-DOCLIB to V3.2 17653: Checkpoint Repo DocLib prototype work 17741: Repo DocLib checkpoint. Forms tag picker support for "create new tag". Data webscripts to also support create tag. Object picker appears in YUI panel rather than inline. Edit metadata dialog now uses Forms runtime. Document & Folder details pages working in non-site mode (but not actions). Added new Share form config file. RM fixes based on DocLib refactoring. Numerous other fixes throughout to support Repository mode. 17742: Merged V3.2 to DEV/REPO-DOCLIB 17633-17741: Latest V3.2 fixes 17761: Repo DocLib checkpoint. New category code & visuals. Path fixes. Object picker fixes. New "locate" action. 17783: Merged DEV/GAV/FORMS-33 to DEV/REPO-DOCLIB 17673: First cut of rich text form control (tinymce) 17691: Wrapped the Alfresco.util.RichEditor object as a Share JavaScript component (Alfresco.RichTextControl) Updated rich text control FTL to instantiate new Alfresco.RichTextControl component 17699: Created separate controls for 'richtext' and 'content', both use same underlying JavaScript object though content control displays appropriate control or completely hides field depending on content's mimetype Added ability to persist content properties (now able to create new instance of cm:content from test form) Error message is now displayed when form fails to submit successfully 17707: Mimetype of created content can now be controlled via form field 17713: Content control now retrieves content so inline editing of textual content is now possible 17810: Repo DocLib checkpoint. Create content 17817: Fixed code path where mimetype for created content does not get set and thus defaults to octet-stream 17979: Repo DocLib checkpoint. DocLib History manager (& YUI bugfix) and cross-Share filter handling refactor. 18027: Repo DocLib checkpoint: Records Management DocLib refactor to new extension pattern. New config to show/hide Repository link in header (hidden by default). "Company Home" renamed to "Repository" to allow arbitrary nodeRefs as root (draft impl.) 18035: Merged V3.2 to DEV/REPO-DOCLIB 17743-18030: Latest V3.2 fixes git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18296 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -76,6 +76,7 @@
|
||||
<property name="fileFolderService" ref="FileFolderService" />
|
||||
<property name="dictionaryService" ref="DictionaryService" />
|
||||
<property name="namespaceService" ref="NamespaceService" />
|
||||
<property name="contentService" ref="ContentService" />
|
||||
<property name="matchPattern">
|
||||
<value>node</value>
|
||||
</property>
|
||||
@@ -89,6 +90,7 @@
|
||||
<property name="fileFolderService" ref="FileFolderService" />
|
||||
<property name="dictionaryService" ref="DictionaryService" />
|
||||
<property name="namespaceService" ref="NamespaceService" />
|
||||
<property name="contentService" ref="ContentService" />
|
||||
<property name="matchPattern">
|
||||
<value>type</value>
|
||||
</property>
|
||||
|
@@ -41,6 +41,7 @@ import org.alfresco.repo.forms.processor.node.TypeFormProcessor;
|
||||
import org.alfresco.repo.jscript.ClasspathScriptLocation;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -954,6 +955,51 @@ public class FormServiceImplTest extends BaseAlfrescoSpringTest
|
||||
assertNotNull("Expected new node to be created using itemId " + ContentModel.TYPE_CONTENT.toString(), newNode);
|
||||
}
|
||||
|
||||
public void testContentCreateForm() throws Exception
|
||||
{
|
||||
// create FormData object containing the values to update
|
||||
FormData data = new FormData();
|
||||
|
||||
// supply the name
|
||||
String name = "created-" + this.documentName;
|
||||
data.addFieldData("prop_cm_name", name);
|
||||
|
||||
// supply the title property
|
||||
String title = "This is the title property";
|
||||
data.addFieldData("prop_cm_title", title);
|
||||
|
||||
// specify the mimetype property
|
||||
String mimetype = "text/html";
|
||||
data.addFieldData("prop_mimetype", mimetype);
|
||||
|
||||
// supply the content property
|
||||
String content = "This is the content.";
|
||||
data.addFieldData("prop_cm_content", content);
|
||||
|
||||
// supply the destination
|
||||
data.addFieldData(TypeFormProcessor.DESTINATION, this.folder.toString());
|
||||
|
||||
// persist the data
|
||||
NodeRef newNode = (NodeRef)this.formService.saveForm(new Item(TYPE_FORM_ITEM_KIND, "cm:content"), data);
|
||||
|
||||
// retrieve the data directly from the node service to ensure its there
|
||||
Map<QName, Serializable> props = this.nodeService.getProperties(newNode);
|
||||
String newName = (String)props.get(ContentModel.PROP_NAME);
|
||||
String newTitle = (String)props.get(ContentModel.PROP_TITLE);
|
||||
assertEquals(name, newName);
|
||||
assertEquals(title, newTitle);
|
||||
|
||||
ContentData contentData = (ContentData) this.nodeService.getProperty(newNode, ContentModel.PROP_CONTENT);
|
||||
assertNotNull(contentData);
|
||||
String newMimetype = contentData.getMimetype();
|
||||
assertEquals(mimetype, newMimetype);
|
||||
|
||||
ContentReader reader = this.contentService.getReader(newNode, ContentModel.PROP_CONTENT);
|
||||
assertNotNull(reader);
|
||||
String newContent = reader.getContentString();
|
||||
assertEquals(content, newContent);
|
||||
}
|
||||
|
||||
public void testNoForm() throws Exception
|
||||
{
|
||||
// test that a form can not be retrieved for a non-existent item
|
||||
|
@@ -40,6 +40,8 @@ import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||
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.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.Period;
|
||||
@@ -85,6 +87,8 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
|
||||
public static final String TRANSIENT_ENCODING = "encoding";
|
||||
|
||||
/** Protected constants */
|
||||
protected static final String DEFAULT_CONTENT_MIMETYPE = "text/plain";
|
||||
|
||||
protected static final String MSG_MIMETYPE_LABEL = "form_service.mimetype.label";
|
||||
|
||||
protected static final String MSG_MIMETYPE_DESC = "form_service.mimetype.description";
|
||||
@@ -105,6 +109,8 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
|
||||
protected DictionaryService dictionaryService;
|
||||
|
||||
protected NamespaceService namespaceService;
|
||||
|
||||
protected ContentService contentService;
|
||||
|
||||
/**
|
||||
* A regular expression which can be used to match property names. These
|
||||
@@ -167,6 +173,16 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content service
|
||||
*
|
||||
* @param contentService The ContentService instance
|
||||
*/
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a field definition for the given property.
|
||||
@@ -586,26 +602,27 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
|
||||
if (TRANSIENT_MIMETYPE.equals(fieldName) || TRANSIENT_ENCODING.equals(fieldName)
|
||||
|| TRANSIENT_SIZE.equals(fieldName))
|
||||
{
|
||||
// if the node type is content or sublcass thereof generate
|
||||
// appropriate field
|
||||
if (nodeRef != null && this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT))
|
||||
// if the node type is content or sublcass thereof generate appropriate field
|
||||
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT))
|
||||
{
|
||||
ContentData content = (ContentData) this.nodeService.getProperty(nodeRef,
|
||||
ContentModel.PROP_CONTENT);
|
||||
if (content != null)
|
||||
ContentData content = null;
|
||||
|
||||
if (nodeRef != null)
|
||||
{
|
||||
if (TRANSIENT_MIMETYPE.equals(fieldName))
|
||||
{
|
||||
generateMimetypePropertyField(content, form);
|
||||
}
|
||||
else if (TRANSIENT_ENCODING.equals(fieldName))
|
||||
{
|
||||
generateEncodingPropertyField(content, form);
|
||||
}
|
||||
else if (TRANSIENT_SIZE.equals(fieldName))
|
||||
{
|
||||
generateSizePropertyField(content, form);
|
||||
}
|
||||
content = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
|
||||
}
|
||||
|
||||
if (TRANSIENT_MIMETYPE.equals(fieldName))
|
||||
{
|
||||
generateMimetypePropertyField(content, form);
|
||||
}
|
||||
else if (TRANSIENT_ENCODING.equals(fieldName))
|
||||
{
|
||||
generateEncodingPropertyField(content, form);
|
||||
}
|
||||
else if (TRANSIENT_SIZE.equals(fieldName))
|
||||
{
|
||||
generateSizePropertyField(content, form);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -875,7 +892,7 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
|
||||
|
||||
if (fieldName.startsWith(PROP_DATA_PREFIX))
|
||||
{
|
||||
processPropertyPersist(nodeRef, propDefs, fieldData, propsToPersist);
|
||||
processPropertyPersist(nodeRef, propDefs, fieldData, propsToPersist, data);
|
||||
}
|
||||
else if (fieldName.startsWith(ASSOC_DATA_PREFIX))
|
||||
{
|
||||
@@ -912,9 +929,10 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
|
||||
* @param propDefs Map of PropertyDefinition's for the node being persisted
|
||||
* @param fieldData Data to persist for the property
|
||||
* @param propsToPersist Map of properties to be persisted
|
||||
* @param data The FormData to persist
|
||||
*/
|
||||
protected void processPropertyPersist(NodeRef nodeRef, Map<QName, PropertyDefinition> propDefs,
|
||||
FieldData fieldData, Map<QName, Serializable> propsToPersist)
|
||||
FieldData fieldData, Map<QName, Serializable> propsToPersist, FormData data)
|
||||
{
|
||||
if (getLogger().isDebugEnabled())
|
||||
getLogger().debug("Processing field " + fieldData + " for property persistence");
|
||||
@@ -946,6 +964,10 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
|
||||
{
|
||||
processNamePropertyPersist(nodeRef, fieldData);
|
||||
}
|
||||
else if (propDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))
|
||||
{
|
||||
processContentPropertyPersist(nodeRef, fieldData, propsToPersist, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Object value = fieldData.getValue();
|
||||
@@ -1264,6 +1286,84 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
|
||||
propsToPersist.put(ContentModel.PROP_CONTENT, contentData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the given field data as the content
|
||||
*
|
||||
* @param nodeRef The NodeRef to update the content for
|
||||
* @param fieldData The data representing the new content
|
||||
* @param propsToPersist Map of properties to be persisted
|
||||
* @param data The form data being persisted
|
||||
*/
|
||||
protected void processContentPropertyPersist(NodeRef nodeRef, FieldData fieldData,
|
||||
Map<QName, Serializable> propsToPersist, FormData data)
|
||||
{
|
||||
ContentWriter writer = this.contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
|
||||
|
||||
if (writer != null)
|
||||
{
|
||||
// determine whether there is any content for the node yet i.e. it's a create
|
||||
boolean defaultMimetypeRequired = (this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT) == null);
|
||||
|
||||
// write the content
|
||||
writer.putContent((String)fieldData.getValue());
|
||||
|
||||
// if there was no content set a sensible default mimetype if necessary
|
||||
if (defaultMimetypeRequired)
|
||||
{
|
||||
// if the transient mimetype property has already set the mimetype don't do anything
|
||||
ContentData contentData = (ContentData) propsToPersist.get(ContentModel.PROP_CONTENT);
|
||||
if (contentData != null)
|
||||
{
|
||||
String mimetype = contentData.getMimetype();
|
||||
if (mimetype == null)
|
||||
{
|
||||
contentData = ContentData.setMimetype(contentData, determineDefaultMimetype(data));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// content data has not been persisted yet so get it from the node
|
||||
contentData = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
|
||||
if (contentData != null)
|
||||
{
|
||||
contentData = ContentData.setMimetype(contentData, determineDefaultMimetype(data));
|
||||
}
|
||||
}
|
||||
|
||||
// add the potentially changed content data object back to property map for persistence
|
||||
propsToPersist.put(ContentModel.PROP_CONTENT, contentData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks through the form data for the 'mimetype' transient field
|
||||
* and returns it's value if found, otherwise the default 'text/plain'
|
||||
* is returned
|
||||
*
|
||||
* @param data Form data being persisted
|
||||
* @return The default mimetype
|
||||
*/
|
||||
protected String determineDefaultMimetype(FormData data)
|
||||
{
|
||||
String mimetype = DEFAULT_CONTENT_MIMETYPE;
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
FieldData mimetypeField = data.getFieldData(PROP + DATA_KEY_SEPARATOR + TRANSIENT_MIMETYPE);
|
||||
if (mimetypeField != null)
|
||||
{
|
||||
String mimetypeFieldValue = (String)mimetypeField.getValue();
|
||||
if (mimetypeFieldValue != null && mimetypeFieldValue.length() > 0)
|
||||
{
|
||||
mimetype = mimetypeFieldValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mimetype;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -205,15 +205,16 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.tagging.TaggingService#createTag(java.lang.String)
|
||||
*/
|
||||
public void createTag(StoreRef storeRef, String tag)
|
||||
public NodeRef createTag(StoreRef storeRef, String tag)
|
||||
{
|
||||
// Lower the case of the tag
|
||||
tag = tag.toLowerCase();
|
||||
|
||||
if (isTag(storeRef, tag) == false)
|
||||
{
|
||||
this.categoryService.createRootCategory(storeRef, ContentModel.ASPECT_TAGGABLE, tag);
|
||||
}
|
||||
return this.categoryService.createRootCategory(storeRef, ContentModel.ASPECT_TAGGABLE, tag);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -326,7 +327,7 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
* @param tag tag
|
||||
* @return NodeRef tag node reference or null not exist
|
||||
*/
|
||||
private NodeRef getTagNodeRef(StoreRef storeRef, String tag)
|
||||
public NodeRef getTagNodeRef(StoreRef storeRef, String tag)
|
||||
{
|
||||
NodeRef tagNodeRef = null;
|
||||
String query = "+PATH:\"cm:taggable/cm:" + ISO9075.encode(tag) + "\"";
|
||||
|
@@ -27,7 +27,9 @@ package org.alfresco.repo.tagging.script;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.jscript.BaseScopableProcessorExtension;
|
||||
import org.alfresco.repo.jscript.ScriptNode;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
|
||||
|
||||
@@ -78,4 +80,39 @@ public class ScriptTaggingService extends BaseScopableProcessorExtension
|
||||
return (String[])result.toArray(new String[result.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a tag by name if available in a store
|
||||
*
|
||||
* @param store store reference
|
||||
* @param tag tag name
|
||||
* @return ScriptNode tag node, or null if not found
|
||||
*/
|
||||
public ScriptNode getTag(String store, String tag)
|
||||
{
|
||||
StoreRef storeRef = new StoreRef(store);
|
||||
NodeRef result = this.serviceRegistry.getTaggingService().getTagNodeRef(storeRef, tag);
|
||||
if (result != null)
|
||||
{
|
||||
return new ScriptNode(result, this.serviceRegistry);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tag in a given store
|
||||
*
|
||||
* @param store store reference
|
||||
* @param tag tag name
|
||||
* @return ScriptNode newly created tag node, or null if unable to create
|
||||
*/
|
||||
public ScriptNode createTag(String store, String tag)
|
||||
{
|
||||
StoreRef storeRef = new StoreRef(store);
|
||||
NodeRef result = this.serviceRegistry.getTaggingService().createTag(storeRef, tag);
|
||||
if (result != null)
|
||||
{
|
||||
return new ScriptNode(result, this.serviceRegistry);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -67,7 +67,7 @@ public interface TaggingService
|
||||
* @param storeRef store reference
|
||||
* @param tag tag name
|
||||
*/
|
||||
void createTag(StoreRef storeRef, String tag);
|
||||
NodeRef createTag(StoreRef storeRef, String tag);
|
||||
|
||||
/**
|
||||
* Delete an existing tag
|
||||
@@ -84,7 +84,18 @@ public interface TaggingService
|
||||
* @param tag tag name
|
||||
*/
|
||||
void addTag(NodeRef nodeRef, String tag);
|
||||
|
||||
|
||||
/**
|
||||
* Gets the node reference for a given tag.
|
||||
* <p>
|
||||
* Returns null if tag is not present.
|
||||
*
|
||||
* @param storeRef store reference
|
||||
* @param tag tag
|
||||
* @return NodeRef tag node reference or null not exist
|
||||
*/
|
||||
NodeRef getTagNodeRef(StoreRef storeRef, String tag);
|
||||
|
||||
/**
|
||||
* Adds a list of tags to a node.
|
||||
* <p>
|
||||
|
Reference in New Issue
Block a user