- I OpenACS For Everyone
- I.1 High level information: What is OpenACS?
- I.1.1 Overview
- I.1.2 OpenACS Release Notes
- I.2 OpenACS: robust web development framework
- I.2.1 Introduction
- I.2.2 Basic infrastructure
- I.2.3 Advanced infrastructure
- I.2.4 Domain level tools
- I.1 High level information: What is OpenACS?
- II Administrator's Guide
- II.2 Installation Overview
- II.2.1 Basic Steps
- II.2.2 Prerequisite Software
- II.3 Complete Installation
- II.3.1 Install a Unix-like system and supporting software
- II.3.2 Install Oracle 10g XE on debian
- II.3.2.1 Install Oracle 8.1.7
- II.3.3 Install PostgreSQL
- II.3.4 Install AOLserver 4
- II.3.5 Quick Install of OpenACS
- II.3.5.1 Complex Install OpenACS 5.3
- II.3.6 OpenACS Installation Guide for Windows2000
- II.3.7 OpenACS Installation Guide for Mac OS X
- II.4 Configuring a new OpenACS Site
- II.4.1 Installing OpenACS packages
- II.4.2 Mounting OpenACS packages
- II.4.3 Configuring an OpenACS package
- II.4.4 Setting Permissions on an OpenACS package
- II.4.5 How Do I?
- II.4.6 Configure OpenACS look and feel with templates
- II.5 Upgrading
- II.5.1 Overview
- II.5.2 Upgrading 4.5 or higher to 4.6.3
- II.5.3 Upgrading OpenACS 4.6.3 to 5.0
- II.5.4 Upgrading an OpenACS 5.0.0 or greater installation
- II.5.5 Upgrading the OpenACS files
- II.5.6 Upgrading Platform components
- II.6 Production Environments
- II.6.1 Starting and Stopping an OpenACS instance.
- II.6.2 AOLserver keepalive with inittab
- II.6.3 Running multiple services on one machine
- II.6.4 High Availability/High Performance Configurations
- II.6.5 Staged Deployment for Production Networks
- II.6.6 Installing SSL Support for an OpenACS service
- II.6.7 Set up Log Analysis Reports
- II.6.8 External uptime validation
- II.6.9 Diagnosing Performance Problems
- II.7 Database Management
- II.7.1 Running a PostgreSQL database on another server
- II.7.2 Deleting a tablespace
- II.7.3 Vacuum Postgres nightly
- II.8 Backup and Recovery
- II.8.1 Backup Strategy
- II.8.2 Manual backup and recovery
- II.8.3 Automated Backup
- II.8.4 Using CVS for backup-recovery
- II.A Install Red Hat 8/9
- II.B Install additional supporting software
- II.B.1 Unpack the OpenACS tarball
- II.B.2 Initialize CVS (OPTIONAL)
- II.B.3 Add PSGML commands to emacs init file (OPTIONAL)
- II.B.4 Install Daemontools (OPTIONAL)
- II.B.5 Install qmail (OPTIONAL)
- II.B.6 Install Analog web file analyzer
- II.B.7 Install nspam
- II.B.8 Install Full Text Search
- II.B.9 Install Full Text Search using Tsearch2
- II.B.10 Install Full Text Search using OpenFTS (deprecated see tsearch2)
- II.B.11 Install nsopenssl
- II.B.12 Install tclwebtest.
- II.B.13 Install PHP for use in AOLserver
- II.B.14 Install Squirrelmail for use as a webmail system for OpenACS
- II.B.15 Install PAM Radius for use as external authentication
- II.B.16 Install LDAP for use as external authentication
- II.B.17 Install AOLserver 3.3oacs1
- II.C Credits
- II.C.1 Where did this document come from?
- II.C.2 Linux Install Guides
- II.C.3 Security Information
- II.C.4 Resources
- II.2 Installation Overview
- III For OpenACS Package Developers
- III.9 Development Tutorial
- III.9.1 Creating an Application Package
- III.9.2 Setting Up Database Objects
- III.9.3 Creating Web Pages
- III.9.4 Debugging and Automated Testing
- III.10 Advanced Topics
- III.10.1 Write the Requirements and Design Specs
- III.10.2 Add the new package to CVS
- III.10.3 OpenACS Edit This Page Templates
- III.10.4 Adding Comments
- III.10.5 Admin Pages
- III.10.6 Categories
- III.10.7 Profile your code
- III.10.8 Prepare the package for distribution.
- III.10.9 Distributing upgrades of your package
- III.10.10 Notifications
- III.10.11 Hierarchical data
- III.10.12 Using .vuh files for pretty urls
- III.10.13 Laying out a page with CSS instead of tables
- III.10.14 Sending HTML email from your application
- III.10.15 Basic Caching
- III.10.16 Scheduled Procedures
- III.10.17 Enabling WYSIWYG
- III.10.18 Adding in parameters for your package
- III.10.19 Writing upgrade scripts
- III.10.20 Connect to a second database
- III.10.21 Future Topics
- III.11 Development Reference
- III.11.1 OpenACS Packages
- III.11.2 OpenACS Data Models and the Object System
- III.11.3 The Request Processor
- III.11.4 The OpenACS Database Access API
- III.11.5 Using Templates in OpenACS
- III.11.6 Groups, Context, Permissions
- III.11.7 Writing OpenACS Application Pages
- III.11.8 Parties in OpenACS
- III.11.9 OpenACS Permissions Tediously Explained
- III.11.10 Object Identity
- III.11.11 Programming with AOLserver
- III.11.12 Using Form Builder: building html forms dynamically
- III.12 Engineering Standards
- III.12.1 OpenACS Style Guide
- III.12.2 Release Version Numbering
- III.12.3 Constraint naming standard
- III.12.4 ACS File Naming and Formatting Standards
- III.12.5 PL/SQL Standards
- III.12.6 Variables
- III.12.7 Automated Testing
- III.13 CVS Guidelines
- III.13.1 Using CVS with OpenACS
- III.13.2 OpenACS CVS Concepts
- III.13.3 Contributing code back to OpenACS
- III.13.4 Additional Resources for CVS
- III.14 Documentation Standards
- III.14.1 OpenACS Documentation Guide
- III.14.2 Using PSGML mode in Emacs
- III.14.3 Using nXML mode in Emacs
- III.14.4 Detailed Design Documentation Template
- III.14.5 System/Application Requirements Template
- III.15 TCLWebtest
- III.16 Internationalization
- III.16.1 Internationalization and Localization Overview
- III.16.2 How Internationalization/Localization works in OpenACS
- III.16.4 Design Notes
- III.16.5 Translator's Guide
- III.D Using CVS with an OpenACS Site
- III.9 Development Tutorial
- IV For OpenACS Platform Developers
- IV.17 Kernel Documentation
- IV.17.1 Overview
- IV.17.2 Object Model Requirements
- IV.17.3 Object Model Design
- IV.17.4 Permissions Requirements
- IV.17.5 Permissions Design
- IV.17.6 Groups Requirements
- IV.17.7 Groups Design
- IV.17.8 Subsites Requirements
- IV.17.9 Subsites Design Document
- IV.17.10 Package Manager Requirements
- IV.17.11 Package Manager Design
- IV.17.12 Database Access API
- IV.17.13 OpenACS Internationalization Requirements
- IV.17.14 Security Requirements
- IV.17.15 Security Design
- IV.17.16 Security Notes
- IV.17.17 Request Processor Requirements
- IV.17.18 Request Processor Design
- IV.17.19 Documenting Tcl Files: Page Contracts and Libraries
- IV.17.20 Bootstrapping OpenACS
- IV.17.21 External Authentication Requirements
- IV.18 Releasing OpenACS
- IV.18.1 OpenACS Core and .LRN
- IV.18.2 How to Update the OpenACS.org repository
- IV.18.3 How to package and release an OpenACS Package
- IV.18.4 How to Update the translations
- IV.17 Kernel Documentation
- V Tcl for Web Nerds
- V.1 Tcl for Web Nerds Introduction
- V.2 Basic String Operations
- V.3 List Operations
- V.4 Pattern matching
- V.5 Array Operations
- V.6 Numbers
- V.7 Control Structure
- V.8 Scope, Upvar and Uplevel
- V.9 File Operations
- V.10 Eval
- V.11 Exec
- V.12 Tcl for Web Use
- V.13 OpenACS conventions for TCL
- V.14 Solutions
- VI SQL for Web Nerds
- VI.1 SQL Tutorial
- VI.1.1 SQL Tutorial
- VI.1.2 Answers
- VI.2 SQL for Web Nerds Introduction
- VI.3 Data modeling
- VI.3.1 The Discussion Forum -- philg's personal odyssey
- VI.3.2 Data Types (Oracle)
- VI.3.4 Tables
- VI.3.5 Constraints
- VI.4 Simple queries
- VI.5 More complex queries
- VI.6 Transactions
- VI.7 Triggers
- VI.8 Views
- VI.9 Style
- VI.10 Escaping to the procedural world
- VI.11 Trees
- VI.1 SQL Tutorial
III.10.6 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:
-
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/$OPENACS_SERVICE_NAME/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/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/admin/index.adp
file:<a href="@category_map_url@"<#categories.Site_wide_Categories#</a>
The link created by the above code (
category_map_url
) 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 ispackage_id
so that category trees will be associated with the object identified by thispackage_id
. The categorization service is actually more general than that: instead ofpackage_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 useforum_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 tonote-edit.tcl
. To achieve this we'll need to use the-extend
switch to thead_form
command. Here's the "meat" of thenote-edit.tcl
page:#extend the form to support categories set package_id [ad_conn package_id] category::ad_form::add_widgets -form_name note -container_object_id $package_id -categorized_object_id [value_if_exists item_id] ad_form -extend -name note -on_submit { set category_ids [category::ad_form::get_categories -container_object_id $package_id] } -new_data { .... category::map_object -remove_old -object_id $item_id $category_ids db_dml insert_asc_named_object "insert into acs_named_objects (object_id, object_name, package_id) values ( :item_id, :title, :package_id)" } -edit_data { .... db_dml update_asc_named_object "update acs_named_objects set object_name = :title, package_id = :package_id where object_id = :item_id" category::map_object -remove_old -object_id $item_id $category_ids } -after_submit { ad_returnredirect "." ad_script_abort }
While the
category::ad_form::add_widgets
proc is taking care to extend your form with associated categories you need to ensure that your items are mapped to the corresponding category object yourself. Also since the categories package knows nothing from your objects you have to keep theacs_named_objects
table updated with any changes taking place. We use the items title so that they are listed in the categories browser by title.Make sure that you also delete these entries if your item is delete. Add this to your corresponding delete page:
db_dml delete_named_object "delete from acs_named_objects where object_id = :item_id"
note-edit.tcl
requires anote_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 inentry-edit.tcl
we usedad_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 bothnote_id
andconfirm_p
. If confirm_p is present, we delete the record, set redirection back to the index, and abort script execution.The database commands:
[$OPENACS_SERVICE_NAME@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:
[$OPENACS_SERVICE_NAME@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. -
We will now make categories optional on package instance level and also add a configuration page to allow the package admin to enable/disable categories for his package.
Go to the APM and create a number parameter with the name "
EnableCategoriesP
" and the default value "0
".Add the following lines to your
index.tcl
:set return_url [ns_conn url] set use_categories_p [parameter::get -parameter "EnableCategoriesP"]
Change your to this:
<a href=configure?<%=[export_url_vars return_url]%>>Configure</a> <if @use_categories_p@> <a href="@category_map_url@"<#categories.Site_wide_Categories#</a> </if>
Now create a configure page
ad_page_contract { This page allows an admin to change the categories usage mode. } { {return_url ""} } set title "Configure category mode" set context [list $title] set use_categories_p [parameter::get -parameter "EnableCategoriesP"] ad_form -name categories_mode -form { {enabled_p:text(radio) {label "Enable Categories"} {options {{Yes 1} {No 0}}} {value $use_categories_p} } {return_url:text(hidden) {value $return_url}} {submit:text(submit) {label "Set Mode"}} } -on_submit { parameter::set_value -parameter "EnableCategoriesP" -value $enabled_p if {![empty_string_p $return_url]} { ns_returnredirect $return_url } }
and add this to its corresponding ADP page
<master> <property name="title">@title@</property> <property name="context">@context@</property> <formtemplate id="categories_mode"></formtemplate>
Reference this page from your admin page
#TCL: set return_url [ad_conn url] #ADP: <a href=configure?<%=[export_url_vars return_url]%>>Configure</a>
Change the
note-edit.tcl
:# Use Categories? set use_categories_p [parameter::get -parameter "EnableCategoriesP" -default 0] if { $use_categories_p == 1 } { # YOUR NEW FORM DEFINITION } else { # YOUR OLD FORM DEFINITION }
-
You can filter your notes using categories. The below example does not support multiple filters and displays a category in a flat format.
The first step is to define the optional parameter
category_id
forindex.tcl
:ad_page_contract { YOUR TEXT } { YOURPARAMS {category_id:integer,optional {}} }
Now you have to check whether categories are enabled or not. If this is the case and a category id is passed you need to extend your sql select query to support filtering. One way would be to extend the
mfp::note::get
proc to support two more swiches-where_clause
and-from_clause
.set use_categories_p [parameter::get -parameter "EnableCategoriesP" -default 0] if { $use_categories_p == 1 && [exists_and_not_null category_id] } { set from_clause "category_object_map com, acs_named_objects nam" set_where_clause "com.object_id = qa.entry_id and nam.package_id = :package_id and com.object_id = nam.object_id and com.category_id = :category_id" ... mfp::note::get \ -item_id $item_id \ -array note_array \ -where_clause $where_clause \ -from_clause $from_clause ... } else { # OLD STUFF }
Also you need to make sure that the user can see the corresponding categories. Add the following snippet to the end of your index page:
# Site-Wide Categories if { $use_categories_p == 1} { set package_url [ad_conn package_url] if { ![empty_string_p $category_id] } { set category_name [category::get_name $category_id] if { [empty_string_p $category_name] } { ad_return_exception_page 404 "No such category" "Site-wide \ Category with ID $category_id doesn't exist" return } # Show Category in context bar append context_base_url /cat/$category_id lappend context [list $context_base_url $category_name] set type "all" } # Cut the URL off the last item in the context bar if { [llength $context] > 0 } { set context [lreplace $context end end [lindex [lindex $context end] end]] } db_multirow -unclobber -extend { category_name tree_name } categories categories { select c.category_id as category_id, c.tree_id from categories c, category_tree_map ctm where ctm.tree_id = c.tree_id and ctm.object_id = :package_id } { set category_name [category::get_name $category_id] set tree_name [category_tree::get_name $tree_id] } }
and to the corresponding index ADP page:
<if @use_categories_p@> <multiple name="categories"> <h2>@categories.tree_name@ <group column="tree_id"> <a href="@package_url@cat/@categories.category_id@?@YOURPARAMS@&category_id=@categories.category_id@">@categories.category_name@ </group> </multiple> <a href="@package_url@view?@YOURPARAMS@">All Items</if>
Finally you need a an
index.vuh
in your www folder to rewrite the URLs correctly, the section called âUsing .vuh files for pretty urlsâ:set url /[ad_conn extra_url] if {[regexp {^/+cat/+([^/]+)/*} $url \ ignore_whole category_id]} { rp_form_put category_id $category_id } rp_internal_redirect "/packages/YOURPACKAGE/www/index"
Now when ever the user select a category only notes that belong to this category are displayed.