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:
Mike Hatfield
2010-01-26 11:59:29 +00:00
parent 9436fbb567
commit 7d57899506
6 changed files with 223 additions and 26 deletions

View File

@@ -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>

View File

@@ -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

View File

@@ -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";
@@ -106,6 +110,8 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
protected NamespaceService namespaceService;
protected ContentService contentService;
/**
* A regular expression which can be used to match property names. These
* names will look like <code>"prop_cm_name"</code>. The pattern can also be
@@ -168,6 +174,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.
* <p>
@@ -586,14 +602,16 @@ 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)
{
content = (ContentData) this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
}
if (TRANSIENT_MIMETYPE.equals(fieldName))
{
generateMimetypePropertyField(content, form);
@@ -608,7 +626,6 @@ public abstract class ContentModelFormProcessor<ItemType, PersistType> extends
}
}
}
}
else if (getLogger().isWarnEnabled())
{
getLogger().warn("Ignoring unrecognised field \"" + fieldName + "\"");
@@ -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;
}
}
/**

View File

@@ -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) + "\"";

View File

@@ -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;
}
}

View File

@@ -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
@@ -85,6 +85,17 @@ public interface TaggingService
*/
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>