[daisy] Create new site from wiki interface

Parisi, Lou Lou.Parisi at photomask.com
Tue Sep 11 23:51:51 CDT 2007


Thank you for your reply.  I have made some progress on this.  My choice
is to have an admin site where there is a form to enter project
information and then when the form is submitted a new site will be
created and a predefined set of documents created.  This is currently
implemented as a daisy extension using cocoon forms and flowscript.  I
have one flow.js that is the main driver and it uses another javascript
file for each document that is created.  In the end I have a new site
with its own navigation tree and all predefined documents (although I
have not completed writing the code that creates all documents).  I have
attached the main flow.js and the javascript that creates the site
directory and configuration files.  I have a few more questions about
this approach.

1. I currently have the path to the sites directory hard-coded in my
javascript relative to the jetty directory.  Is there a way to get this
directory programmatically?  I look at the daisy.getDaisyContextPath()
but this is not to the wikidata directory.  My fallback is to create a
site variable to hold this value or if you have a better idea I would
love to hear it.

2. What is the best way to write to the log from the flowscript?  I
tried cocoon.log.info("msg") but this did not seem to work.  I ended up
using org.apache.commons.logging.LogFactory.getLog and then calling
standard logger message calls.  Is there a better way?

3. Most importantly, creating all of these documents is a lot of
javascript.  I would prefer to create java code compiled into a jar and
call that from my flowscript.  Where would I put this in WEB-INF/lib?
Will changes to any external jars be seen if they are updated (hot
deploy) or will the repository have to be restarted for the updated jars
to be read?

Thanks for your help.  Daisy seems very flexible but it is a little hard
to get started without any cocoon background.

-----Original Message-----
From: daisy-bounces at lists.cocoondev.org
[mailto:daisy-bounces at lists.cocoondev.org] On Behalf Of Marc Portier
Sent: Tuesday, September 11, 2007 1:53 AM
To: open source CMS - general mailinglist
Subject: Re: [daisy] Create new site from wiki interface



Parisi, Lou wrote:
> I am working on a proof of concept for a project management CMS using 
> daisy.  When a new project is started, I have a defined set of
documents 
> I want to populate into a new site.  I have been able to generate the 
> documents in an existing site but now I want to create a project 
> management site where one of the tasks that can be performed is to 
> create a new site with the populated blank documents using a form to 
> collect the information necessary to create the site.  I have been 
> working on this and am using the repository manager to create a new 
> collection and this works but the collection is not visible in the
daisy 
> home site list.  I have also looked at the code for 
> org.outerj.daisy.install.DaisyWikiAddSite.  It seems the main
difference 
> between what DaisyWikiAddSite code does and what I am doing is to
create 
> the site directory and add the siteconf.xml to the directory.
> 
>  

good observation

> 
> I am still new to Daisy and have a few questions about this.
> 
>  
> 
> Question 1: It seems there is a distinction between a collection and a

> site.  It appears the difference is that a site has a site directory
but 
> a collection does not.  Is this correct?  If so, how is a collection 
> used if it is not a site?
> 

collections live on the repository side and are to be seen as some tag 
on your document grouping them together somewhat (You manage them 
through the collection-manager, you assign them to documents)

You can use these in any way you like: editors are to assign to which 
collection a document belongs and all sorts of queries and stuff can be 
taking that into account. (e.g. ACL does, search does, ...)


a 'site' however is a concept that is not known on the repository (e.g. 
you cannot have a query looking for documents belonging to a site) but 
only exist at the level of the wiki-frontend. (These are indeed created 
by having a directory with siteconf.xml in the dsy-wiki/sites )


There is a subtle link between the two: the siteconf.xml points to a 
default collection for that 'site', the effect of this is:
- new documents created through this site will be automatically in this 
collection
- full-text-search results (and similar lookups in the editor-dialogs) 
will be automatically limited to the site's collection
- ... etc

So again: above describes how the wiki (=just a repository-client) uses 
the repository concept of 'collection' inside its own wiki-concept
'site'


This usage suggests a one on one between site and collection (And 
confirmed by the init-site procedure you've been looking into, since 
that creates both at once.)

Note however that this no must: e.g. in multilingual setups you would 
have one site per language and _all_ of them keeping documents in the 
same collection.


So for you're case you are actually free to choose:

- will you keep all documents on all projects in one repository and let 
all 'sites' use that common collection.  In which case you'll probably 
need to introduce some other field to link it to the correct projects. 
By making that field multivalue or not you can control of documents can 
be linked to more then one project or not.

- or will you indeed create separate collections and use that to group 
documents of certain projects together (note: here you have no choice: 
collections _are_ multi-value tags on documents, so you'll always be 
able to store on document in multiple collections)

- you might even consider not to make multiple sites... but structure 
the info all on one 'site' and play around with subnavigations and stuff

- ....

pretty timtowdi as you seen, one of the approaches is likely to have 
natural fit with your case...

>  
> 
> Question 2: Is it possible to create a full-fledged site using 
> javascript through the wiki front-end or does this have to be done by
an 
> external script calling a java class?  If it can't be done through 
> javascript through daisy, is it possible to accomplish the same thing
by 
> creating a Servlet that the form called to write to the filesystem or 
> possibly an applet embedded in a document?
> 

the 'site' being a daisy-wiki feature I would go for hosting the code 
for creating that directory as a daisy-wiki extension... (that will have

access to ths dsy-wiki directory where the action is to happen)


- applets run on the client: unlikely you can reach dsy-wiki directory
there
- daisy.js scripts pretty much have the same issue (although you could 
execute those on the server as well, they keep being 'client' apps)

- servlets are the best candidates from your list, but you might find 
that writing a cocoon-based flowscript extension (javascript again) for 
this is a far easier approach

from the same script you'll be able to create the collection and all 
necessary documents

you'ld want to read up on this:
http://cocoondev.org/daisydocs-2_1/374-cd/60-cd.html
(and sections below)


good luck, and please report back
(my guess is this is useful for more people that might be willing to 
chime in, or at least just snatch your results :-))


regards,
-marc=
_______________________________________________
daisy community mailing list
Professional Daisy support:
http://outerthought.org/site/services/daisy/daisysupport.html
mail to: daisy at lists.cocoondev.org
list information: http://lists.cocoondev.org/mailman/listinfo/daisy
-------------- next part --------------
function createSiteConf(siteURL, collId, navDocId, homeDocId) {

	// create site directory
	var sitepath = "../../../daisywikidata/sites/";		
	var siteDir = new java.io.File(sitepath + siteURL);
	var result = siteDir.mkdir();	
	if (!result) {
		return false;
	}
	
	// create siteconf.xml file	
	var CR = java.lang.System.getProperty("line.separator");	
	try{				
		var file1 = new java.io.File(siteDir, "siteconf.xml");
		var fstream1 = new java.io.FileWriter(file1);
        var out1 = new java.io.BufferedWriter(fstream1);
		out1.write("<siteconf xmlns=\"http://outerx.org/daisy/1.0#siteconf\">" + CR);
		out1.write("  <title>" + siteURL + "</title>" + CR);
		out1.write("  <description>The " + siteURL + " site</description>" + CR);
		out1.write("  <skin>default</skin>" + CR);
		out1.write("  <navigationDocId>" + navDocId + "</navigationDocId>" + CR);
		out1.write("  <homepageDocId>" + homeDocId + "</homepageDocId>" + CR);
		out1.write("  <collectionId>" + collId + "</collectionId>" + CR);
		out1.write("  <contextualizedTree>false</contextualizedTree>" + CR);
		out1.write("  <branch>main</branch>" + CR);
		out1.write("  <language>default</language>" + CR);
		out1.write("  <defaultDocumentType>SimpleDocument</defaultDocumentType>" + CR);
		out1.write("  <newVersionStateDefault>publish</newVersionStateDefault>" + CR);
		out1.write("  <locking>" + CR);
		out1.write("    <automatic lockType='pessimistic' defaultTime='15' autoExtend='true'/>" + CR);
		out1.write("  </locking>" + CR);
		out1.write("</siteconf>");	
    }catch (e) {  
		return false;
	} finally {
		if (out1) {
			out1.close();
		}
	}
	
	//create cocoon directory and sitemap.xmap
	var cocoonDir = new java.io.File(siteDir, "cocoon");
	result = cocoonDir.mkdir();
	if (!result) {
		return false;
	}
	
	try {				
		var file2 = new java.io.File(cocoonDir, "sitemap.xmap");
		var fstream = new java.io.FileWriter(file2);
        var out2 = new java.io.BufferedWriter(fstream2);
		out2.write("<?xml version=\"1.0\"?>" + CR);		
		out2.write("<map:sitemap xmlns:map=\"http://apache.org/cocoon/sitemap/1.0\">" + CR);
		out2.write(CR);
		out2.write(" <map:components>" + CR);
		out2.write(" </map:components>" + CR);
		out2.write(CR);
		out2.write(" <map:views>" + CR);
		out2.write(" </map:views>" + CR);
		out2.write(CR);
		out2.write(" <map:resources>" + CR);
		out2.write(" </map:resources>" + CR);
		out2.write(CR);
		out2.write(" <map:pipelines>" + CR);
		out2.write(CR);
		out2.write("   <map:pipeline internal-only=\"true\" type=\"noncaching\">" + CR);
		out2.write("   </map:pipeline>" + CR);
		out2.write(CR);
		out2.write("   <map:pipeline type=\"noncaching\">" + CR);
		out2.write("     <map:parameter name=\"outputBufferSize\" value=\"8192\"/>" + CR);
		out2.write("   </map:pipeline>" + CR);
		out2.write(CR);
		out2.write(" </map:pipelines>" + CR);
		out2.write(CR);
		out2.write("</map:sitemap>");		
	} catch (e) {     
		return false;
	} finally {
		if (out2) {
			out2.close();
		}
	}
	
	return true;
}
-------------- next part --------------
cocoon.load("resource://org/apache/cocoon/forms/flow/javascript/Form.js");
cocoon.load("resource://org/outerj/daisy/frontend/util/daisy-util.js");
cocoon.load("HomeDocumentFactory.js");
cocoon.load("ProposalDocumentFactory.js");
cocoon.load("SiteConfFactory.js");
cocoon.load("NavigationDocumentFactory.js");

/**
 * The guestbook code. Note that this code is designed to be stateless, it doesn't
 * use continuations or the session.
 */
function createsite() {
    var daisy = getDaisy();
    var repositoryUser = "admin";
    var repositoryPassword = "admin";

	// this does not work
	//cocoon.log.info("started createsite method");
	
	var log = org.apache.commons.logging.LogFactory.getLog("createsite");
	log.info("started createsite method");

    //
    // Get the Daisy Repository client for the current user (or guest user if not logged in)
    //
    var repository = daisy.getRepository();

    //
    // Get some other contextual data
    //

    // siteConf is an object holding the configuration information for the current DaisyWiki site
    var siteConf = daisy.getSiteConf();    
    var locale = daisy.getLocale();

    //
    // Get the hierarchical navigation tree
    //
    var navigationData = new Packages.org.apache.cocoon.xml.SaxBuffer();
    var navigationManager = repository.getExtension("NavigationManager");
    var navigationParams = new Packages.org.outerj.daisy.navigation.NavigationParams(siteConf.getNavigationDoc(),
                                                                                     "/createsite", 
                                                                                     siteConf.contextualizedTree());
    navigationManager.generateNavigationTree(navigationData, navigationParams, null, true);


    // create form to enter site information
    var form = new Form("createsite_form_definition.xml");
    var finished = false;

    // POST = form was submitted, so process it
    if (cocoon.request.getMethod() == "POST") {
        var formContext = new Packages.org.apache.cocoon.forms.FormContext(cocoon.request, locale);
        finished = form.form.process(formContext);
    }

    if (finished) {
        // The form has been correctly completed, now we can do whatever we like
        // to do with the entered data: send it as an email to someone, insert
        // it in a database, or as illustrated here, create a document in the Daisy
        // repository
        var projectName = form.getChild("projectname").getValue();
		var projectDesc = form.getChild("projectdesc").getValue();
        var siteName = form.getChild("sitename").getValue();
        var projectLeader = form.getChild("projectleader").getValue();

        // Retrieve the repository client object for the user that is authorized to create these guest book entries
        // (assuming other users, especially guest users, aren't allowed to do this)
        var repository = daisy.getRepository(repositoryUser, repositoryPassword);
		var collectionManager = repository.getCollectionManager();				
		
		// check if site already exists
		try {
			collectionManager.getCollection(siteName, false);
			//alert("The site " + siteName + " already exists.  Please choose a new site name.");
			//reshowForm(daisy, form, siteConf, locale, navigationData);
			//return;
		} catch (e) {
			// do nothing because the collection should not exist
		}						
		
		//create new site
		var newCollection = collectionManager.createCollection(siteName);
		newCollection.save();
		
		if (!newCollection) {
			showResult(daisy, locale, navigationData, "The project " + projectName + " was not created because the site " + siteName + " collection could not be created.");
			return;
		}
		
		//create home document - uses HomeDocumentFactory.js
        var homeDocument = createHomeDocument(repository, projectName, projectLeader);
		if (!homeDocument) {
			showResult(daisy, locale, navigationData, "The project " + projectName + " was not created because the home document could not be created.");			
			return;
		}
		homeDocument.save();
		var homeDocId = homeDocument.getId();
		
		//create proposal document - uses ProposalDocumentFactory.js
        var proposalDocument = createProposalDocument(repository, projectName, projectDesc, projectLeader);
		if (!proposalDocument) {
			showResult(daisy, locale, navigationData, "The project " + projectName + " was not created because the proposal document could not be created.");			
			return;
		}
		proposalDocument.save();
		var proposalDocId = proposalDocument.getId();
		
		//create navigation document - uses NavigationDocumentFactory.js
		var navigationDoc = createNavigationDocument(repository, siteName, homeDocId, proposalDocId);
		if (!navigationDoc) {
			showResult(daisy, locale, navigationData, "The project " + projectName + " was not created because the navigation document could not be created.");			
			return;
		}
		navigationDoc.save();
		var navDocId = navigationDoc.getId();
		
		// wait until have all documents then save collection and documents
		newCollection.save();
		homeDocument.addToCollection(newCollection);
		homeDocument.save();
		proposalDocument.addToCollection(newCollection);
		proposalDocument.save();
		navigationDoc.addToCollection(newCollection);
		navigationDoc.save();		
						
		var collId = newCollection.getId();
		// creates the siteconf.xml and cocoon directory with sitemap - uses SiteConfFactory.js
		createSiteConf(siteName, collId, navDocId, homeDocId);
		newCollection.save();
		
        // show confirmation page
		// link to home page is of the form  /testsite_1/86-DSY.html
		var homeLink = "/" + siteName + "/" + homeDocId + ".html"
		var message = "The project " + projectName + " was successfully created.";
        showResult(daisy, locale, navigationData, message, homeLink);

        // Note about the above: /daisy/GenericMessagePipe is a pipeline we reuse from the main
        // Daisy sitemap. The template read by the JX generator is specified using the 'template'
        // key in the viewData. The resolve() funtion is used to resolve the path relative to
        // the current extension sitemap.
    } else {
        reshowForm(daisy, form, siteConf, locale, navigationData);        
    }
}

function reshowForm(daisy, form, siteConf, locale, navigationData) {
	// mountPoint is where in the URI space the daisy sitemap is mounted (usually /daisy)
    var mountPoint = daisy.getMountPoint();
	
	var viewData = new Object();
    viewData["CocoonFormsInstance"] = form.form;
    viewData["pageContext"] = daisy.getPageContext();
    viewData["submitPath"] = mountPoint + "/" + siteConf.getName() + "/ext/createsite/forms/createsite";
    viewData["locale"] = locale;
    viewData["navigationTree"] = navigationData;
    viewData["formTemplate"] = daisy.resolve("createsite_form_template.xml");
    cocoon.sendPage(daisy.getDaisyCocoonPath() + "/GenericFormPipe", viewData);
}

function showResult(daisy, locale, navigationData, message, sitelink) {
	var viewData = new Object();
    viewData["createresult"] = message;
	viewData["sitelink"] = sitelink;
    viewData["pageContext"] = daisy.getPageContext();
    viewData["locale"] = locale;
    viewData["navigationTree"] = navigationData;
    viewData["template"] = daisy.resolve("createsite_confirm.xml");
    cocoon.sendPage(daisy.getDaisyCocoonPath() + "/GenericMessagePipe", viewData);	
}

/**
 * Escapes characters disallowed in XML, change newlines to <br> tags.
 */
function encodeToHTML(text) {
    // the first statement is to be sure the text is a javascript string, it might be a java string
    // if the value was obtained from a form.
    text = "" + text;
    text = text.replace(/</g, "&lt;");
    text = text.replace(/>/g, "&gt;");
    text = text.replace(/'/g, "&apos;");
    text = text.replace(/"/g, "&quot;");
    text = text.replace(/\n/g, "<br/>");
    return text;
}


More information about the daisy mailing list