Index: openacs-4/packages/acs-core-docs/www/subsites.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/subsites.html,v diff -u -N -r1.46 -r1.47 --- openacs-4/packages/acs-core-docs/www/subsites.html 11 Dec 2010 23:36:32 -0000 1.46 +++ openacs-4/packages/acs-core-docs/www/subsites.html 31 Jul 2011 23:11:46 -0000 1.47 @@ -1,8 +1,8 @@ - -Writing OpenACS Application Pages

Writing OpenACS Application Pages

By Rafael H. Schloming and Pete Su

+ +Writing OpenACS Application Pages

Writing OpenACS Application Pages

By Rafael H. Schloming and Pete Su

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

Overview

+

Overview

In this document, we'll examine the user interface pages of the Notes application in more detail, covering two separate aspects of page development in OpenACS. First, we'll talk about the code needed to make @@ -11,8 +11,8 @@ form-based user interfaces in OpenACS. While these seem like unrelated topics, they both come up in the example page that we are going to look at, so it makes sense to address them at the same time. -

Application Instances and Subsites

-As you will recall from the packages tutorial, the Request +

Application Instances and Subsites

+As you will recall from the packages tutorial, the Request Processor (RP) and Package Manager (APM) allow site administrators to define an arbitrary mapping from URLs in the site to objects representing content. These objects may represent single @@ -22,63 +22,63 @@ particular URL. The tutorial also showed how a given URL is translated into a physical file to serve using the site map. We'll repeat this description here, assuming that you have mounted an -instance of Notes at the URL /notes as we did in the packages-example: -

  • -AOLserver receives your request for the URL /notes/somepage. -

  • +instance of Notes at the URL /notes as we did in the packages-example: +

    • +AOLserver receives your request for the URL /notes/somepage. +

    • This URL is passed to the request processor. -

    • +

    • The RP looks up the URL in the site map, and sees that the object -mounted at that location is an instance of the notes +mounted at that location is an instance of the notes application. -

    • +

    • The RP asks the package manager where in the file system the Notes package lives. In the standard case, this would be -ROOT/packages/notes. -

    • +ROOT/packages/notes. +

    • The RP translates the URL to serve a page relative to the page root of the application, which is -ROOT/packages/notes/www/. Therefore, the page that is -finally served is ROOT/packages/notes/www/hello.html, +ROOT/packages/notes/www/. Therefore, the page that is +finally served is ROOT/packages/notes/www/hello.html, which is what we wanted.

    What is missing from this description is a critical fact for application developers: In addition to working out what file to serve, the RP also stores information about which package instance the file belongs to into the AOLserver connection environment. The following -ad_conn interfaces can be used to extract this +ad_conn interfaces can be used to extract this information: -

    [ad_conn package_url]

    +

    [ad_conn package_url]

    If the URL refers to a package instance, this is the URL to the root of the tree where the package is mounted. -

    [ad_conn package_id]

    +

    [ad_conn package_id]

    If the URL refers to a package instance, this is the ID of that package instance. -

    [ad_conn package_key] +

    [ad_conn package_key]

    If the URL refers to a package instance, this is the unique key name of the package. -

    [ad_conn extra_url] +

    [ad_conn extra_url]

    If we found the URL in the site map, this is the tail of the URL following the part that matched a site map entry.

    In the Notes example, we are particularly interested in the -package_id field. If you study the data model and code, -you'll see why. As we said before in the data modeling tutorial, the Notes application points the -context_id of each Note object that it creates to the -package instance that created it. That is, the context_id -corresponds exactly to the package_id that comes in from +package_id field. If you study the data model and code, +you'll see why. As we said before in the data modeling tutorial, the Notes application points the +context_id of each Note object that it creates to the +package instance that created it. That is, the context_id +corresponds exactly to the package_id that comes in from the RP. This is convenient because it allows the administrator and the owner of the package to easily define access control policies for all the notes in a particular instance just my setting permissions on the package instance itself.

    The code for adding and editing notes, in -notes/www/add-edit.tcl, shows how this works. At the top -of the page, we extract the package_id and use it to do +notes/www/add-edit.tcl, shows how this works. At the top +of the page, we extract the package_id and use it to do permission checks:

     
    @@ -87,11 +87,11 @@
     if {[info exists note_id]} {
           permission::require_permission -object_id $note_id -privilege write
     
    -      set context_bar [ad_context_bar "Edit Note"]
    +      set context_bar [ad_context_bar "Edit Note"]
     } else {
           permission::require_permission -object_id $note_id -privilege create
     
    -      set context_bar [ad_context_bar "New Note"]
    +      set context_bar [ad_context_bar "New Note"]
     }
     
     

    @@ -100,7 +100,7 @@ for each action.

    Later, when we actually create a note, the SQL that we run ensures -that the context_id is set the right way: +that the context_id is set the right way:

     
     db_dml new_note {
    @@ -124,25 +124,25 @@
     without generating a lot of duplicated HTML in your pages. It also
     encapsulates most of the common logic that we use in dealing with
     forms, which we'll discuss next.
    -

Using Forms

+

Using Forms

The forms API is pretty simple: You use calls in the -template::form namespace in your Tcl script to create +template::form namespace in your Tcl script to create form elements. The final template page then picks this stuff up and lays the form out for the user. The form is set up to route submit buttons and whatnot back to the same Tcl script that set up the form, so your Tcl script will also contain the logic needed to process these requests.

So, given this outline, here is a breakdown of how the forms code -works in the add-edit.tcl page. First, we create a form object -called new_note: +works in the add-edit.tcl page. First, we create a form object +called new_note:

 
 template::form create new_note
 
 

All the forms related code in this page will refer back to this -object. In addition, the adp part of this page does +object. In addition, the adp part of this page does nothing but display the form object:

 
@@ -153,7 +153,7 @@
 <hr>
 
 <center>
-<formtemplate id="new_note"></formtemplate>
+<formtemplate id="new_note"></formtemplate>
 </center>
 
 

@@ -176,31 +176,31 @@ }

-The if_request call returns true if we are asking the +The if_request call returns true if we are asking the page to render the form for the first time. That is, we are rendering -the form to ask the user for input. The tcl part of a +the form to ask the user for input. The tcl part of a form page can be called in 3 different states: the initial request, the initial submission, and the validated submission. These states reflect the typical logic of a forms based page in OpenACS: -

  • +

    • First render the input form. -

    • +

    • Next, control passes to a validation page that checks and confirms the inputs. -

    • +

    • Finally, control passes to the page that performs the update in the database.

    -The rest of the if condition figures out if we are +The rest of the if condition figures out if we are creating a new note or editing an existing note. If -note_id is passed to us from the calling page, we assume +note_id is passed to us from the calling page, we assume that we are editing an existing note. In this case, we do a database query to grab the data for the note so we can populate the form with it.

    The next two calls create form elements where the user can insert or edit the title and body of the Note. The interface to -template::element is pretty straightforward. +template::element is pretty straightforward.

    Finally, the code at the bottom of the page performs the actual database updates when the form is submitted and validated: @@ -234,7 +234,7 @@ } } - ad_returnredirect "." + ad_returnredirect "." }

    @@ -243,7 +243,7 @@ the HTML rendering, input validation and database transaction logic on your behalf. This means that you can write pages without duplicating all of that code in every set of pages that uses forms. -

How it All Fits

+

How it All Fits

To watch all of this work, use the installer to update the Notes package with the new code that you grabbed out of CVS or the package repository, mount an instance of Notes somewhere in your server and @@ -254,15 +254,15 @@ visible to that user. The end result is a site where users can come and write notes to themselves.

-This is a good example of the leverage available in the OpenACS 5.6.0 +This is a good example of the leverage available in the OpenACS 5.7.0 system. The code that we have written for Notes is not at all more complex than a similar application without access control or site map awareness. By adding a small amount of code, we have taken a small, simple, and special purpose application to something that has the potential to be a very useful, general-purpose tool, complete with multi-user features, access control, and centralized administration. -

Summary

-In OpenACS 5.6.0, application pages and scripts can be aware of the package +

Summary

+In OpenACS 5.7.0, application pages and scripts can be aware of the package instance, or subsite in which they are executing. This is a powerful general purpose mechanism that can be used to structure web services in very flexible ways.