Index: openacs-4/packages/acs-core-docs/www/tutorial-advanced.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/tutorial-advanced.html,v diff -u -r1.17 -r1.18 --- openacs-4/packages/acs-core-docs/www/tutorial-advanced.html 4 Feb 2004 16:47:33 -0000 1.17 +++ openacs-4/packages/acs-core-docs/www/tutorial-advanced.html 12 Feb 2004 13:51:40 -0000 1.18 @@ -1,677 +1,7 @@ -
Table of Contents
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.
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 - myfirstpackage/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 service0]$ cd /var/lib/aolserver/service0/packages/myfirstpackage/ -[service0 myfirstpackage]$ mkdir -p www/doc/xml -[service0 myfirstpackage]$ cd www/doc/xml -[service0 xml]$ cp /var/lib/aolserver/service0/packages/acs-core-docs/www/files/myfirstpackage/* . -[service0 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 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 xml]$
Verify that the documentation was generated and reflects - your changes by browsing to http://yoursite:8000/myfirstpackage/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 xml]$ cd .. -[service0 doc]$ cd .. -[service0 www]$ cd .. -[service0 myfirstpackage]$ cd .. -[service0 packages]$ cvs add myfirstpackage/ -Directory /cvsroot/service0/packages/myfirstpackage added to the repository -[service0 packages]$ cd myfirstpackage/ -[service0 myfirstpackage]$ cvs add www -Directory /cvsroot/service0/packages/myfirstpackage/www added to the repository -[service0 myfirstpackage]$ cd www -[service0 www]$ cvs add doc -Directory /cvsroot/service0/packages/myfirstpackage/www/doc added to the repository -[service0 www]$ cd doc -[service0 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/myfirstpackage/www/doc/xml added to the repository -cvs add: use 'cvs commit' to add these files permanently -[service0 doc]$ cd xml -[service0 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 xml]$ cd ../../.. -[service0 myfirstpackage]$ 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/myfirstpackage/www/doc/admin-guide.html,v -done -Checking in www/doc/admin-guide.html; -/cvsroot/service0/packages/myfirstpackage/www/doc/admin-guide.html,v <-- admin-guide.html -initial revision: 1.1 -done -(many lines omitted) -[service0 myfirstpackage]$
You can track comments for any ACS Object. Here we'll track - comments for notes. On the note-edit.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 note-edit.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 note-edit.adp - page.
<a href="@comment_add_url@">Add a comment</a> - @comments_html@
- There are at least two flavors of admin user interface: -
Admins use same pages as all other users, except - that they are offered admin links and buttons where appropriate. - For example, if admins have privilege to bulk-delete items you - could provide checkboxes next to every item seen on a list and the - Delete Selected button on the bottom of the list. -
Dedicated admin pages. If you want admins to have - access to data that users aren't interested in or aren't allowed - to see you will need dedicated admin pages. The conventional - place to put those dedicated admin pages is in the - /var/lib/aolserver/service0/packages/myfirstpackage/www/admin - directory. -
[service0 www]$ mkdir admin
[service0 www]$ cd admin
- Even if your application doesn't need any admin pages of its own you will - usually need at least one simple page with a bunch of links to existing - administration UI such as Category Management or standard Parameters UI. - Adding the link to Category Management is described in the section on - categories. The listing below adds a link to the Parameters UI of our - package. -
[service0 admin]$ vi index.adp
-<master> -<property name="title">@title;noquote@</property> -<property name="context">@context;noquote@</property> - -<ul class="action-links"> - <li><a href="@parameters_url@" title="Set parameters" class="action_link">Set parameters</a></li> -</ul> -
[service0 admin]$ vi index.tcl
-ad_page_contract {} { -} -properties { - context_bar -} - -set package_id [ad_conn package_id] - -set admin_p [ad_require_permission $package_id admin] - -set context [list] - -set title "Administration" - -set parameters_url [export_vars -base "/shared/parameters" { - package_id { return_url [ad_return_url] } -}] - -
-Now that you have the first admin page it would be nice to have a link to it -somewhere in the system so that admins don't have to type in the -/admin every time they need to reach it. You -could put a static link to the toplevel -index.adp but that might be distracting for -people who are not admins. Besides, some people consider it impolite to first -offer a link and then display a nasty "You don't have permission to access this -page" message. -
-In order to display the link to the admin page only to users that have admin -privileges add the following code near the top of -/var/lib/aolserver/service0/packages/myfirstpackage/www/admin/index.tcl: -
- -set package_id [ad_conn package_id] - -set admin_p [permission::permission_p -object_id $package_id \ - -privilege admin -party_id [ad_conn untrusted_user_id]] - -if { $admin_p } { - set admin_url "admin" - set admin_title Administration -} -
-In -/var/lib/aolserver/service0/packages/myfirstpackage/www/admin/index.adp put: -
-<if @admin_p@ ne nil> - <a href="@admin_url@">@admin_title@</a> -</if> -
You can associate any ACS Object with one or more categories. - In this tutorial we'll show how to equip your application with user - interface to take advantage of the Categories service. -
- We'll start by installing the Categories service. Go to - /acs/admin and install it. This step - won't be necessary for the users of your applications because you'll create - a dependency with the Package Manager which will take care that the - Categories service always gets installed when your application gets - installed. -
- Now that we have installed the Categories service we can proceed to - modifying our application so that it can take advantage of it. We'll do it - in three steps: -
- The Categories service provides a mechanism to associate one or - more category trees that are relevant to - your application. One example of such tree is a tree of - geographical locations. Continents are on the top of such tree, - each continent containing countries etc. Another tree might - contain market segments etc. Before users of your application - can take advantage of the Categories service there needs to be a - way for administrators of your application to choose which - category trees are applicable for the application. -
- The way to achieve this is is to provide a link - to the Category Management pages. Add the following snippet to your - /var/lib/aolserver/service0/packages/myfirstpackage/www/admin/index.tcl - file: -
-set category_map_url [export_vars -base \ - "[site_node::get_package_url -package_key categories]cadmin/one-object" \ - { { object_id $package_id } }] -
- and the following snippet to your - /var/lib/aolserver/service0/packages/myfirstpackage/www/admin/index.adp - file: -
-<li><a href="@category_map_url@" - class="action_link">Site-Wide Categories</a> -
The link created by the above code will take the admin to the generic - admin UI where he can pick category trees that make sense for this - application. The same UI also includes facilities to build and edit - category trees. Notice that the only parameter in this example is - package_id so that category trees - will be associated with the object identified by this - package_id. The categorization - service is actually more general than that: instead of - package_id you could use an ID of - some other object that serves as a "container" in your application. - For example, if your discussion forums application supports multiple - forums you would use forum_id to - associate category trees with just that one forum rather than the - entire application instance. -
- Once the category trees have been selected users need a way - to categorize items. The easiest way to do this is by adding the - category widget type of the - form builder to note-edit.tcl. - To achieve this we'll need to use the -extend - switch to the ad_form command. Here's the "meat" of the - note-edit.tcl page:
-ad_form -name note -form { - {item_id:key} - {title:text {label Title}} -} - -set package_id [ad_conn package_id] - -set category_trees [category_tree::get_mapped_trees $package_id] - -foreach tree $category_trees { - foreach { tree_id name subtree_id } $tree {} - ad_form -extend -name note -form \ - [list [list category_id_${tree_id}:integer(category),optional \ - {label $name} \ - {html {single single}} \ - {category_tree_id $tree_id} \ - {category_subtree_id $subtree_id} \ - {category_object_id {[value_if_exists entry_id]}}]] -} - -ad_form -extend \ - -name note \ - -new_request { - permission::require_permission -object_id [ad_conn package_id] -privilege create - set page_title "Add a Note" - set context [list $page_title] -} -edit_request { - permission::require_write_permission -object_id $item_id - mfp::note::get \ - -item_id $item_id \ - -array note_array - - set title $note_array(title) - - set page_title "Edit a Note" - set context [list $page_title] -} -new_data { - mfp::note::add \ - -title $title -} -after_submit { - ad_returnredirect "." - 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@
- There are at least two flavors of admin user interface: -
Admins use same pages as all other users, except - that they are offered admin links and buttons where appropriate. - For example, if admins have privilege to bulk-delete items you - could provide checkboxes next to every item seen on a list and the - Delete Selected button on the bottom of the list. -
Dedicated admin pages. If you want admins to have - access to data that users aren't interested in or aren't allowed - to see you will need dedicated admin pages. The conventional - place to put those dedicated admin pages is in the -/var/lib/aolserver/service0/packages/myfirstpackage/www/admin -directory. -
[service0@yourserver www]$ mkdir admin
[service0@yourserver www]$ cd admin
- Even if your application doesn't need any admin pages of its own you will - usually need at least one simple page with a bunch of links to existing - administration UI such as Category Management or standard Parameters UI. - Adding the link to Category Management is described in the section on - categories. The listing below adds a link to the Parameters UI of our - package. -
[service0@yourserver admin]$ vi index.adp
-<master> -<property name="title">@title;noquote@</property> -<property name="context">@context;noquote@</property> - -<ul class="action-links"> - <li><a href="@parameters_url@" title="Set parameters" class="action_link">Set parameters</a></li> -</ul> -
[service0@yourserver admin]$ vi index.tcl
-ad_page_contract {} { -} -properties { - context_bar -} - -set package_id [ad_conn package_id] - -set admin_p [ad_require_permission $package_id admin] - -set context [list] - -set title "Administration" - -set parameters_url [export_vars -base "/shared/parameters" { - package_id { return_url [ad_return_url] } -}] - -
-Now that you have the first admin page it would be nice to have a link to it -somewhere in the system so that admins don't have to type in the -/admin every time they need to reach it. You -could put a static link to the toplevel -index.adp but that might be distracting for -people who are not admins. Besides, some people consider it impolite to first -offer a link and then display a nasty "You don't have permission to access this -page" message. -
-In order to display the link to the admin page only to users that have admin -privileges add the following code near the top of -/var/lib/aolserver/service0/packages/myfirstpackage/www/admin/index.tcl: -
- -set package_id [ad_conn package_id] - -set admin_p [permission::permission_p -object_id $package_id \ - -privilege admin -party_id [ad_conn untrusted_user_id]] - -if { $admin_p } { - set admin_url "admin" - set admin_title Administration -} -
-In -/var/lib/aolserver/service0/packages/myfirstpackage/www/admin/index.adp put: -
-<if @admin_p@ ne nil> - <a href="@admin_url@">@admin_title@</a> -</if> -
You can associate any ACS Object with one or more categories. - In this tutorial we'll show how to equip your application with user - interface to take advantage of the Categories service. -
- We'll start by installing the Categories service. Go to - /acs/admin and install it. This step - won't be necessary for the users of your applications because you'll create - a dependency with the Package Manager which will take care that the - Categories service always gets installed when your application gets - installed. -
- Now that we have installed the Categories service we can proceed to - modifying our application so that it can take advantage of it. We'll do it - in three steps: -
- The Categories service provides a mechanism to associate one or - more category trees that are relevant to - your application. One example of such tree is a tree of - geographical locations. Continents are on the top of such tree, - each continent containing countries etc. Another tree might - contain market segments etc. Before users of your application - can take advantage of the Categories service there needs to be a - way for administrators of your application to choose which - category trees are applicable for the application.
- The way to achieve this is is to provide a link - to the Category Management pages. Add the following snippet to your - /var/lib/aolserver/service0/packages/myfirstpackage/www/admin/index.tcl - file: -
-set category_map_url [export_vars -base \ - "[site_node::get_package_url -package_key categories]cadmin/one-object" \ - { { object_id $package_id } }] -
- and the following snippet to your - /var/lib/aolserver/service0/packages/myfirstpackage/www/admin/index.adp - file: -
-<li><a href="@category_map_url@" - class="action_link">Site-Wide Categories</a> -
The link created by the above code will take the admin to the generic - admin UI where he can pick category trees that make sense for this - application. The same UI also includes facilities to build and edit - category trees. Notice that the only parameter in this example is - package_id so that category trees - will be associated with the object identified by this - package_id. The categorization - service is actually more general than that: instead of - package_id you could use an ID of - some other object that serves as a "container" in your application. - For example, if your discussion forums application supports multiple - forums you would use forum_id to - associate category trees with just that one forum rather than the - entire application instance. -
- Once the category trees have been selected users need a way - to categorize items. The easiest way to do this is by adding the - category widget type of the - form builder to note-edit.tcl. - To achieve this we'll need to use the -extend - switch to the ad_form command. Here's the "meat" of the - note-edit.tcl page: -
-ad_form -name note -form { - {item_id:key} - {title:text {label Title}} -} - -set package_id [ad_conn package_id] - -set category_trees [category_tree::get_mapped_trees $package_id] - -foreach tree $category_trees { - foreach { tree_id name subtree_id } $tree {} - ad_form -extend -name note -form \ - [list [list category_id_${tree_id}:integer(category),optional \ - {label $name} \ - {html {single single}} \ - {category_tree_id $tree_id} \ - {category_subtree_id $subtree_id} \ - {category_object_id {[value_if_exists entry_id]}}]] -} - -ad_form -extend \ - -name note \ - -new_request { - permission::require_permission -object_id [ad_conn package_id] -privilege create - set page_title "Add a Note" - set context [list $page_title] -} -edit_request { - permission::require_write_permission -object_id $item_id - mfp::note::get \ - -item_id $item_id \ - -array note_array - - set title $note_array(title) - - set page_title "Edit a Note" - set context [list $page_title] -} -new_data { - mfp::note::add \ - -title $title -} -after_submit { - ad_returnredirect "." - ad_script_abort -} -
-
Browse to the package manager. Click on - tutorialapp.
Click on Generate a distribution file - for this package from the - filesystem. -
Click on the file size - (37.1KB) - after the label Distribution - File: and save the file to - /tmp.
by David Bell and Simon Carstensen
- OpenACS docs are written by the named authors, and may be edited - by OpenACS documentation staff. -The notifications package allows you to send notifications through any - defined communications medium (e.g. email, sms) upon some event occuring within - the system.
This tutorial steps through the process of integrating the notifications - package with your package.
First step is to create the notification types. To do this a script similar - to the one below needs to be loaded into Postgresql. I create this script in a - package-name/sql/postgresql/package-name-notifications-init.sql file. I then load - this file from my create sql file. The following code snippet is taken from - Weblogger. It creates a lars_blogger_notif notification type (which was created - above).
- create function inline_0() returns integer as ' - declare - impl_id integer; - v_foo integer; - begin - -- the notification type impl - impl_id := acs_sc_impl__new ( - ''NotificationType'', - ''lars_blogger_notif_type'', - ''lars-blogger'' - ); - - v_foo := acs_sc_impl_alias__new ( - ''NotificationType'', - ''lars_blogger_notif_type'', - ''GetURL'', - ''lars_blogger::notification::get_url'', - ''TCL'' - ); - - v_foo := acs_sc_impl_alias__new ( - ''NotificationType'', - ''lars_blogger_notif_type'', - ''ProcessReply'', - ''lars_blogger::notification::process_reply'', - ''TCL'' - ); - - PERFORM acs_sc_binding__new ( - ''NotificationType'', - ''lars_blogger_notif_type'' - ); - - v_foo:= notification_type__new ( - NULL, - impl_id, - ''lars_blogger_notif'', - ''Blog Notification'', - ''Notifications for Blog'', - now(), - NULL, - NULL, - NULL - ); - - -- enable the various intervals and delivery methods - insert into notification_types_intervals - (type_id, interval_id) - select v_foo, interval_id - from notification_intervals where name in (''instant'',''hourly'',''daily''); - - insert into notification_types_del_methods - (type_id, delivery_method_id) - select v_foo, delivery_method_id - from notification_delivery_methods where short_name in (''email''); - - return (0); - end; - ' language 'plpgsql'; - - select inline_0(); - drop function inline_0(); -
The next step is to setup our notification creation. A new notification must - be added to the notification table for each blog entry added. We do this using the - notification::new procedure
- notification::new \ - -type_id [notification::type::get_type_id \ - -short_name lars_blogger_notif] \ - -object_id $blog(package_id) \ - -response_id $blog(entry_id) \ - -notif_subject $blog(title) \ - -notif_text $new_content -
This code is placed in the tcl procedure that creates blog entries, right after - the entry gets created in the code. The $blog(package_id) - is the OpenACS object_id of the Weblogger instance to which the entry has been posted to - and the $new_content is the content of the entry.
The final step is to setup the notification subscription process. In this - example we want to let a user find out when a new entry has been posted to the blog. To - do this we put a link on the blog that allows them to subscribe to notifications of new - entries. The notifications/requests-new page is very handy in this situation.
Such a link can be created using the notification::display::request_widget - proc:
- set notification_chunk [notification::display::request_widget \ - -type lars_blogger_notif \ - -object_id $package_id \ - -pretty_name [lars_blog_name] \ - -url [lars_blog_public_package_url] \ - ] -
which will return something like - -
- You may <a href="/notifications/request-new?...">request notification</a> for Weblogger.
- - which can be readily put on the blog index page. The pretty_name - parameter is what appears at the end of the text returned (i.e. "... request notification</a> for pretty_name"), - The url parameter should be set to the address we want the user - to be redirected to after they have finished the subscription process.
This should be all you need to implement a notification system. For more examples - look at the forums package.
Future Topics:
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 prepare pagelets for inclusion in other pages
How and when to put procedures in a tcl procedure library
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
See also the OpenACS Programming FAQ
Prev | Home | Next |
Debugging and Automated Testing | Up | Write the Requirements and Design Specs |