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.14.2.11 -r1.14.2.12 --- openacs-4/packages/acs-core-docs/www/tutorial-advanced.html 21 Jan 2004 18:36:16 -0000 1.14.2.11 +++ openacs-4/packages/acs-core-docs/www/tutorial-advanced.html 2 Feb 2004 18:10:57 -0000 1.14.2.12 @@ -1,32 +1,27 @@ -Advanced Topics

Advanced Topics

Important

This section is a work in progress.

by Joel Aufrecht


+Advanced Topics

Advanced Topics

by Joel Aufrecht

OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff. -

Overview

This tutorial covers topics which are not essential to +

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

Write the Requirements and Design Specs

It's time to document. For the tutorial we'll use + you've completed the basic tutorial.

Write the Requirements and Design Specs

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 + 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@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 + 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 @@ -42,7 +37,7 @@ 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
+      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)
@@ -58,25 +53,25 @@
 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

Add the new package to CVS

Before you do any more work, make sure that your work is +[service0 xml]$

Verify that the documentation was generated and reflects + your changes by browsing to http://yoursite:8000/myfirstpackage/doc

Add the new package to CVS

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)

[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
@@ -99,120 +94,250 @@
 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
+Directory /cvsroot/service0/packages/myfirstpackage/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
+[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@yourserver xml]$ cd ../../..
-[service0@yourserver samplenote]$ cvs commit -m "new package"
+[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/samplenote/www/doc/admin-guide.html,v
+RCS file: /cvsroot/service0/packages/myfirstpackage/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
+/cvsroot/service0/packages/myfirstpackage/www/doc/admin-guide.html,v  <--  admin-guide.html
 initial revision: 1.1
 done
 (many lines omitted)
-[service0@yourserver samplenote]$

Delete with confirmation

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.
+[service0 myfirstpackage]$

Adding Comments

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@

Admin Pages

+ 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>
     
    -    @author joel@aufrecht.org
    -    @creation-date 2003-02-12
    -    @cvs-id $Id$
    -} {
    -    note_id:integer
    -    confirm_p:optional
    +<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 title "Delete Note"
    +set package_id [ad_conn package_id]
     
    -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"
    +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>
    +

Categories

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: +

  1. + 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. +

  2. + 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.

General_comments

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@

Prepare the package for distribution.

Browse to the package manager. Click on +} +

+

Prepare the package for distribution.

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.

-

Notifications

by David Bell and Simon Carstensen


+ /tmp.

+

Notifications

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 +

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 @@ -316,4 +441,9 @@ 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.

View comments on this page at openacs.org
+ look at the forums package.

Future Topics:

See also the OpenACS Programming FAQ

View comments on this page at openacs.org