This section is a work in progress.
This tutorial covers topics which are not essential to creating a minimal working package. Each section can be used independently of all of the others; all sections assume that you've completed the basic tutorial.
How to enforce security so that users can't change other users records
How to use the content management tables so that ... what?
How to change the default stylesheets for Form Builder HTML forms.
How to make your package searchable with OpenFTS/Oracle
How to make your package send email notifications
How to prepare pagelets for inclusion in other pages
How and when to put procedures in a tcl procedure library
How to add general_comments to your pages
More on ad_form - data validation, other stuff. (plan to draw from Jon Griffin's doc)
How and when to implement caching
partialquery in xql
How to use the html/text entry widget to get the "does this look right" confirm page
APM package dependencies
It's time to document. For the tutorial we'll use pre-written documentation. When creating a package from scratch, start by copying the documentation template from /var/lib/aolserver/openacs-dev/packages/acs-core-docs/xml/docs/xml/package-documentation-template.xml to yourpackage/www/docs/xml/index.xml.
You then edit that file with emacs to write the requirements and design sections, generate the html, and start coding. Store any supporting files, like page maps or schema diagrams, in the www/doc/xml directory, and store png or jpg versions of supporting files in the www/doc directory.
For this tutorial, you should instead install the pre-written documentation files for the tutorial app. Log in as service0, create the standard directories, and copy the prepared documentation:
[service0@yourserver service0]$ cd /var/lib/aolserver/service0/packages/samplenote/ [service0@yourserver samplenote]$ mkdir -p www/doc/xml [service0@yourserver samplenote]$ cd www/doc/xml [service0@yourserver xml]$ cp /var/lib/aolserver/service0/packages/acs-core-docs/www/files/samplenote/* . [service0@yourserver xml]$
OpenACS uses DocBook for documentation. DocBook is an XML standard for semantic markup of documentation. That means that the tags you use indicate meaning, not intended appearance. The style sheet will determine appearance. You will edit the text in an xml file, and then process the file into html for reading.
Open the file index.xml in emacs. Examine the file. Find the version history (look for the tag <revhistory>). Add a new record to the document version history. Look for the <authorgroup> tag and add yourself as a second author. Save and exit. For tips on editing SGML files in emacs, see OpenACS Documentation Guide
Process the xml file to create html documentation. The html documentation, including supporting files such as pictures, is stored in the www/docs/ directory. A Makefile is provided to generate html from the xml, and copy all of the supporting files. If Docbook is set up correctly, all you need to do is:
[service0@yourserver xml]$ make cd .. ; /usr/bin/xsltproc ../../../acs-core-docs/www/xml/openacs.xsl xml/index.xml Writing requirements-introduction.html for sect1(requirements-introduction) Writing requirements-overview.html for sect1(requirements-overview) Writing requirements-cases.html for sect1(requirements-cases) Writing sample-data.html for sect1(sample-data) Writing requirements.html for chapter(requirements) Writing design-data-model.html for sect1(design-data-model) Writing design-ui.html for sect1(design-ui) Writing design-config.html for sect1(design-config) Writing design-future.html for sect1(design-future) Writing filename.html for chapter(filename) Writing user-guide.html for chapter(user-guide) Writing admin-guide.html for chapter(admin-guide) Writing bi01.html for bibliography Writing index.html for book [service0@yourserver xml]$
Verify that the documentation was generated and reflects your changes by browsing to http://yoursite:8000/samplenote/doc
Before you do any more work, make sure that your work is protected by putting it all into cvs. The cvs add command is not recursive, so you'll have to traverse the directory tree manually and add as you go. (More on CVS)
[service0@yourserver xml]$ cd ..
[service0@yourserver doc]$ cd ..
[service0@yourserver www]$ cd ..
[service0@yourserver samplenote]$ cd ..
[service0@yourserver packages]$ cvs add samplenote/
Directory /cvsroot/service0/packages/samplenote added to the repository
[service0@yourserver packages]$ cd samplenote/
[service0@yourserver samplenote]$ cvs add www
Directory /cvsroot/service0/packages/samplenote/www added to the repository
[service0@yourserver samplenote]$ cd www
[service0@yourserver www]$ cvs add doc
Directory /cvsroot/service0/packages/samplenote/www/doc added to the repository
[service0@yourserver www]$ cd doc
[service0@yourserver doc]$ cvs add *
cvs add: cannot add special file `CVS'; skipping
cvs add: scheduling file `admin-guide.html' for addition
cvs add: scheduling file `bi01.html' for addition
cvs add: scheduling file `data-model.dia' for addition
cvs add: scheduling file `data-model.png' for addition
cvs add: scheduling file `design-config.html' for addition
cvs add: scheduling file `design-data-model.html' for addition
cvs add: scheduling file `design-future.html' for addition
cvs add: scheduling file `design-ui.html' for addition
cvs add: scheduling file `filename.html' for addition
cvs add: scheduling file `index.html' for addition
cvs add: scheduling file `page-map.dia' for addition
cvs add: scheduling file `page-map.png' for addition
cvs add: scheduling file `requirements-cases.html' for addition
cvs add: scheduling file `requirements-introduction.html' for addition
cvs add: scheduling file `requirements-overview.html' for addition
cvs add: scheduling file `requirements.html' for addition
cvs add: scheduling file `sample-data.html' for addition
cvs add: scheduling file `sample.png' for addition
cvs add: scheduling file `user-guide.html' for addition
cvs add: scheduling file `user-interface.dia' for addition
cvs add: scheduling file `user-interface.png' for addition
Directory /cvsroot/service0/packages/samplenote/www/doc/xml added to the repository
cvs add: use 'cvs commit' to add these files permanently
[service0@yourserver doc]$ cd xml
[service0@yourserver xml]$ cvs add Makefile index.xml
cvs add: scheduling file `Makefile' for addition
cvs add: scheduling file `index.xml' for addition
cvs add: use 'cvs commit' to add these files permanently
[service0@yourserver xml]$ cd ../../..
[service0@yourserver samplenote]$ cvs commit -m "new package"
cvs commit: Examining .
cvs commit: Examining www
cvs commit: Examining www/doc
cvs commit: Examining www/doc/xml
RCS file: /cvsroot/service0/packages/samplenote/www/doc/admin-guide.html,v
done
Checking in www/doc/admin-guide.html;
/cvsroot/service0/packages/samplenote/www/doc/admin-guide.html,v <-- admin-guide.html
initial revision: 1.1
done
(many lines omitted)
[service0@yourserver samplenote]$
We need a way to delete records. We'll create a recursive confirmation page.
Add this column to the table_def in index.tcl
{delete "" {} {<td><a href="note-delete?note_id=$note_id">Delete</a></td>}}
Create the delete confirmation/execution page.
[service0@yourserver www]$ emacs note-delete.tcl
ad_page_contract { A page that gets confirmation and then delete notes. @author joel@aufrecht.org @creation-date 2003-02-12 @cvs-id $Id: tutorial-advanced.html,v 1.8 2003/10/28 22:18:47 joela Exp $ } { note_id:integer confirm_p:optional } set title "Delete Note" if {![exists_and_not_null confirm_p]} { # first pass, not confirmed. Display a form for confirmation set note_name [db_string get_name { *SQL }] set title "Delete $note_name" template::form::create note-del-confirm template::element::create note-del-confirm note_id -value $note_id -widget hidden template::element::create note-del-confirm confirm_p -value 1 -widget hidden template::element::create note-del-confirm submit \ -label "Confirm deletion of $note_name" \ -widget submit } else { # second pass, confirmed. Call the database to delete the record db_1row do_delete { *SQL* } ad_returnredirect "index" ad_script_abort }
This page requires a note_id to determine which record should be deleted. It also looks for a confirmation variable, which should initially be absert. If it is absent, we create a form to allow the user to confirm the deletion. Note that in entry-edit.tcl we used ad_form to access the Form Template commands; here, we call them directly because we don't need the extra features of ad_form. The form calls itself, but with hidden variables carrying both note_id and confirm_p. If confirm_p is present, we delete the record, set redirection back to the index, and abort script execution.
The database commands:
[service0@yourserver www]$ emacs note-delete.xql
<?xml version="1.0"?> <queryset> <fullquery name="do_delete"> <querytext> select samplenote__delete(:note_id) </querytext> </fullquery> <fullquery name="get_name"> <querytext> select samplenote__name(:note_id) </querytext> </fullquery> </queryset>
And the adp page:
[service0@yourserver www]$ emacs note-delete.adp
<master> <property name="title">@title@</property> <property name="context">{@title@}</property> <h2>@title@</h2> <formtemplate id="note-del-confirm"></formtemplate> </form>
The ADP is very simple. The formtemplate tag outputs the HTML form generated by the ad_form command with the matching name. Test it by adding the new files in the APM and then deleting a few samplenotes.
You can track comments for any ACS Object. Here we'll track comments for notes. On the notes.tcl/adp pair, which is used to display individual notes, we want to put a link to add comments at the bottom of the screen. If there are any comments, we want to show them.
First, we need to generate a url for adding comments. In notes.tcl:
set comment_add_url "[general_comments_package_url]comment-add?[export_vars { { object_id $note_id } { object_name $title } { return_url "[ad_conn url]?[ad_conn query]"} }]"
This calls a global, public tcl function that the general_comments package registered, to get its url. You then embed in that url the id of the note and its title, and set the return_url to the current url so that the user can return after adding a comment.
We need to create html that shows any existing comments. We do this with another general_comments function:
set comments_html [general_comments_get_comments -print_content_p 1 $note_id]
First, we pass in an optional parameter that that says to actually show the contents of the comments, instead of just the fact that there are comments. Then you pass the note id, which is also the acs_object id.
We put our two new variables in the notes.adp page.
<a href="@comment_add_url@">Add a comment</a> @comments_html@