Exploring the woods

In the past couple of months, I’ve come to realize that having a template for a script that shows how to do walks around the tree that is the Alfresco repository is a really useful thing.  So, as a first go, I wrote a simple javascript that dumped as much as it could find about a node and all the nodes below it.  It was an incredibly useful exercise.  Before I did this, I didn’t really know that (as of 3.4EE, at least):

  • Comments on a document and forum threads are really the same thing, just with different sorts of objects forming their root node.  Each comment/forum post is its own node in the repository.
  • Tags are their own separate nodes in the repository.  Each item only stores a link to the tag it’s associated with, not the actual tag text.
  • Something that appears to be as simple as a word processing document or a JPEG image can also be a container, containing preview images, comment threads, workflows, etc.

It’s also allowed me to write several subsidiary scripts, including one that allows me to dump metadata to a tab-delimited text file, suitable for importing into something like Excel.  Others take advantage of the results of a lucene search rather than a brute-force approach to find what nodes to examine. I’ll post the most basic one tonight, and some of the more interesting derivatives later.

This script simply walks the tree and follows every node  link to see what’s on the other side.  The output is quite verbose, and not formatted to be machine-readable.  As you can see, though, it is pretty easy to rework the script to select the fields you really want and format them in whatever way.

Here’s what you do with the code when you get it:

  1. Save it as a .js file
  2. Put that file within /Company Home/Data Dictionary/Scripts on your Alfresco instance
  3. Log into the Alfresco Explore interface
  4. Navigate to the node where you want to start dumping the node information.  I’d STRONGLY recommend only choosing a single fairly small site or user home to start with–the output can get pretty lengthy.
  5. Click into the details screen of that node, then click “Run Action”
  6. Choose “Execute Script” from the pop-up, and then select the .js file you uploaded.
  7. A file with your metadata in it will be dumped to your User Home folder after a few seconds.

So, on to the code:

/*
walk-tree.js
version of 6/8/2011
by Ian Crew, icrew@berkeley.edu

A script for Alfresco Enterprise Edition that walks throigh the entire repository and dumps as much information about each node as posoible.

This script has only been tested on Alfresco EE 3.3.4 and 3.4.0. 

Legalese
This script is copyright 2011 by the Regents of the University of California.
No warranties are expressed or implied.  Use at your own risk.  This script may be
freely distributed and modified so long as this copyright notice is included in
all derivative versions.
*/

var rootFolder = document.properties["name"];

var destinationEmail = person.properties["email"];

//find out where we're really starting from
var parentPathdoc=document;
var parentPath="/"+rootFolder;
while ((parentPathdoc.getParent() != null)) {
	
	 parentPathdoc = parentPathdoc.getParent();
	 parentPath = "/" + parentPathdoc.properties["name"] + parentPath;
	 
	 if (parentPathdoc.properties["name"] == "Company Home") {
	 	break;	
	 }
}

var folderProps = "Dumping all metadata starting at " + parentPath + "\n";

var path = "";
folderProps += dumpEntireNode(document, path);


sendMail (destinationEmail, "Metadata for " + parentPath, folderProps, document);

//logger.log("---------------------");


//dump the entire node, for debugging
function dumpEntireNode (node, path) {
	nodeName = node.properties["name"];

	path += "/" + nodeName;

	
	var nodeData = "\n=========================\nNode data for "+path+"\n-------------------------\n";
	nodeData += "\nProperties:\n";
	for (var childProperty in node.properties)
	{
		//logger.log(childProperty +"\t"+node.properties[childProperty]);
		if (childProperty == '{http://www.alfresco.org/model/webdav/1.0}sharedLockTokens') {
			nodeData += childProperty + ":\n" + dump(node.properties[childProperty],1);
		}
		else {
			nodeData += "\t'" + childProperty + "' => \"" + node.properties[childProperty] + "\"\n";
		}
	}

	nodeData += "\nTags:\n";
	var tags = "";
	var tags = node.properties["taggable"];
	if (tags != "") {
		for(var item in tags) {
			var tag = tags[item];
			if (typeof(tag.properties) != 'undefined') {
				nodeData += "\t'" + item + "' => | "+ tag.properties["name"] + " | "  + tag.typeShort + " | "  + tag.nodeRef +" |\n";
			}
			else {
				nodeData += "\t'" + item + "' => \"" + tag + "\"\n";
			}	
		}
	}


	nodeData += "\nInfo:\n";
	// BOOLEAN:
	nodeData += "\tisContainer:\t" + node.isContainer + "\n";
	nodeData += "\tisDocument:\t" + node.isDocument + "\n";
	nodeData += "\tisCategory:\t" + node.isCategory + "\n";
	//nodeData += "\tboolean isScriptContent(object obj):\t" + node.boolean isScriptContent(object obj) + "\n";

	// STRING
	nodeData += "\turl:\t" + node.url + "\n";
	nodeData += "\tdownloadUrl:\t" + node.downloadUrl + "\n";
	nodeData += "\twebdavUrl:\t" + node.webdavUrl + "\n";
	nodeData += "\tmimetype:\t" + node.mimetype + "\n";
	nodeData += "\tsize:\t" + node.size + "\n";
	nodeData += "\tdisplayPath:\t" + node.displayPath + "\n";
	nodeData += "\tqnamePath:\t" + node.qnamePath + "\n";
	nodeData += "\ticon16:\t" + node.icon16 + "\n";
	nodeData += "\ticon32:\t" + node.icon32 + "\n";
	nodeData += "\tisLocked:\t" + node.isLocked + "\n";
	nodeData += "\tid:\t" + node.id + "\n";
	nodeData += "\tnodeRef:\t" + node.nodeRef + "\n";
	nodeData += "\tname:\t" + node.name + "\n";
	nodeData += "\ttype:\t" + node.type + "\n";
	nodeData += "\ttypeShort:\t" + node.typeShort + "\n";
	
	if (typeof(node.parent.properties) != 'undefined') {
		nodeData += "\tparent:\t | " + node.parent.properties["name"] + " | "  + node.parent.typeShort + " | "  + node.parent.nodeRef +" |\n";
	}
	else {
		nodeData += "\tparent:\t" + node.parent + "\n";
	}	
	nodeData += "\tisVersioned:\t" + node.isVersioned + "\n";
	
	
	
	// ARRAYS:
	nodeData += "\n";  //for formatting
	if (node.isVersioned) {
		nodeData += "Versions:\n";
		for(var item in node.versionHistory) {
			var version = node.versionHistory[item];
			nodeData += "\t'" + item + "' => | "+ version.label + " | "  + version.createdDate + " | "  + version.creator + " | "  + version.node.nodeRef +" |\n";
			/*if (typeof(version.label) != 'undefined') {
				nodeData += "\t'" + item + "' => \n";
				nodeData += "\t\tLabel:\t" + version.label + "\n";
				nodeData += "\t\tCreatedDate:\t" + version.createdDate + "\n";
				nodeData += "\t\tCreator:\t" + version.creator + "\n";
				nodeData += "\t\tType:\t" + version.type + "\n";
				nodeData += "\t\tVersion Description:\t" + version.description + "\n";
				//if (typeof(version.node.properties) != 'undefined') {
				//	nodeData += "\t\tNode:\t | " + version.node.properties["name"] + " | "  + version.node.typeShort + " | "  + version.node.nodeRef +" |\n";
				//}
				nodeData += "\t\tNode Reference:\t" + version.nodeRef + "\n";
			}
			else {
				nodeData += "\t'" + item + "' => \"" + version + "\"\n";
			}	*/
		}
		nodeData += "\n";  //for formatting
	}
	nodeData += "Permissions:\n" + dump (node.getPermissions())+ "\n";
	nodeData += "Aspects:\n" + dump (node.aspects) + "\n";
	nodeData += "Associations:\n" + dump (node.assocs) + "\n";
	nodeData += "Source Associations:\n" + dump (node.sourceAssocs) + "\n";
	nodeData += "Children:\n" + dump (node.children) + "\n";
	nodeData += "Child Associations:\n" + dump (node.childAssocs) + "\n";
	nodeData += "Parents:\n" + dump (node.parents) + "\n";
	nodeData += "Parent Associations:\n" + dump (node.parentAssocs) + "\n";
	nodeData += "Active Workflows:\n" + dump (node.activeWorkflows) + "\n";
	

	// CONTENT
	if (parseInt(node.size) == 0) {  //Don't show content for nodes with size 0
		//nodeData += "Content:\t[No content]\n";
	}
	else if (node.mimetype.indexOf("text") != 0) {  //Don't show the binary documents, because that's ugly in an email
		nodeData += "Content:\t[Binary Document: Not shown]\n";
	}
	else {
		nodeData += "Content:\n\t--\n" + node.content + "\n\t--\n";
	}
	//nodeData += node.getSiteShortName();
	//nodeData += "=========================\n";

	//RECURSE DOWN THE TREE
	for(var child in node.children) {
		nodeData += dumpEntireNode(node.children[child], path);
	}
	
	return nodeData;
}


/**
 * Function : dump()
 * Arguments: The data - array,hash(associative array),object
 *    The level - OPTIONAL
 * Returns  : The textual representation of the array.
 * This function was inspired by the print_r function of PHP.
 * This will accept some data as the argument and return a
 * text that will be a more readable version of the
 * array/hash/object that is given.
 * Docs: http://www.openjs.com/scripts/others/dump_function_php_print_r.php
 */
function dump(arr,level) {
	var dumped_text = "";
	if(!level) level = 0;
	
	//The padding given at the beginning of the line.
	var level_padding = "";
	for(var j=0;j<level+1;j++) level_padding += "\t";
	
	if(typeof(arr) == 'object') { //Array/Hashes/Objects 
		for(var item in arr) {
			var value = arr[item];
			
			//if(typeof(value) == 'object') { //If it is an array,
			//	dumped_text += level_padding + "'" + item + "' ...\n";
			//	dumped_text += dump(value,level+1);
			// } else {
			if ( (level == 0) && (!/^\d+$/.test(item)) ) {  //if this is not just an array, but some sort of object, go down another level, but only once.  Can't use typeof here for some reason.  Sigh.
				dumped_text += level_padding + item + ":\n" + dump (value,level+1);
			}
			else if (typeof(value.properties) != 'undefined') {
				dumped_text += level_padding + "'" + item + "' => | " + value.properties["name"] + " | "  + value.typeShort + " | "  + value.nodeRef +" |\n";
			}
			else {
				dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
			}
		}
	} else { //Stings/Chars/Numbers etc.
		dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
	}
	return dumped_text;
}


//send off the email
function sendMail (recipient, subject, contents, node) {
	//send email to the specified recipients


/*	

See http://savicprvoslav.blogspot.com/2010/10/send-html-email-from-alfresco-33-with.html to send html email someday

var htmlContents =
'Mime-Version: 1.0\
Content-Type: multipart/alternative; \
	boundary="----=_Part_2665_1854048590.1224718126252"\
\
X-Content-Type-Outer-Envelope: multipart/alternative; boundary=Apple-Mail-1--549697194\
\
\
X-Content-Type-Message-Body: text/plain;\
	charset=US-ASCII;\
	format=flowed;\
	delsp=yes\
\
------=_Part_2665_1854048590.1224718126252\
Content-Type: text/html ; charset=ISO-8859-1\
Content-Transfer-Encoding: quoted-printable\
\
\
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"\
    "http://www.w3.org/TR/html4/loose.dtd">\
<html>\
<head>\
  <meta content="text/html;charset=utf-8"\
 http-equiv="Content-Type">\
 <title>HTML MESSAGE</title>\
</head>\
<body bgcolor="#ffffff" text="#000000">\
\
' + contents + '\
\
</body></html>\
\
------=_Part_2665_1854048590.1224718126252--\
\
';

*/

	
	// create mail action
	var mail = actions.create("mail");
	mail.parameters.to = recipient;
	mail.parameters.subject = subject;
	mail.parameters.from = "foo@bar.com";
	mail.parameters.template = null;
	mail.parameters.text = contents;
	// execute action against a document		
	mail.execute(node);
}
Advertisements
This entry was posted in Scripts. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s