0.00%
Search · Index

Weblog Page

Showing 91 - 100 of 230 Postings (summary)

How to Update the OpenACS.org repository

Created by Gustaf Neumann, last modified by Gustaf Neumann 17 Feb 2008, at 07:08 AM

  1. Setup a local OpenACS server running 5.0 or better.

  2. Edit packages/acs-admin/www/apm/build-repository.tcl and adjust the Configuration Settings.

  3. Request /acs-admin/apm/build-repository on your new server.

    1. The page will find all branches in the cvs repository labeled oacs-x-y, and build a repository channel for each of those branches where x>=5 (so not for 4.6 and earlier). It will also build a channel for HEAD, which will be named after what you set in 'head_channel' above.

    2. For each channel, it'll do an anonymous checkout of packges and contrib/packages, then build .apm files for each package in the checkout.

    3. The files will be stored on the server's hard drive in the directory specified by the 'repository_dir' variable in the page script, by default "[acs_root_dir]/www/repository/".

  4. If you're on openacs.org, everything should now be fine. Otherwise, you need to move the entire directory tree to openacs.org:/web/openacs/www/repository, replacing what was already there.

    This is automated on OpenACS.org by having a dedicated site just for building the repository, invoked with this shell script. Since the page circumvents security checks for ease of use, the entire site is limited to local requests. The script is called daily with a cron job.

    #!/bin/sh
    #set -x
    
    STATUS=`wget --output-document - http://127.0.0.1:8002/build-repository.tcl | grep DONE | wc -l`
    
    if [ $STATUS -eq "1" ]
    then
        rm -rf /web/openacs.org/www/repository.old
        mv /web/openacs.org/www/repository /web/openacs.org/www/repository.old
        cp -r /web/repository/www/repository /web/openacs.org/www/repository
    fi

Variables

Created by Gustaf Neumann, last modified by Gustaf Neumann 17 Feb 2008, at 07:08 AM

By joel@aufrecht.org

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

Starting with OpenACS 5.0 and the introduction of acs-lang, we recommend retrieving date/time information from the database in ANSI format and then using lc_time_fmt to format it for display.

Example12.1.Getting datetime from the database ANSI-style

db_multirow -extend { mydate_pretty } {
    select to_char(mydate, 'YYYY-MM-DD HH24:MI:SS') as mydate_ansi,
          ...
    ...
} {
    set mydate_ansi [lc_time_system_to_conn $mydate_ansi]
    set mydate_pretty [lc_time_fmt $mydate_ansi "%x %X"]
}

Hierarchical data

Created by Gustaf Neumann, last modified by Gustaf Neumann 17 Feb 2008, at 07:08 AM

by Jade Rubick with help from many people in the OpenACS community

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

One of the nice things about using the OpenACS object system is that it has a built-in facility for tracking hierarchical data in an efficient way. The algorithm behind this is called tree_sortkey.

Any time your tables are subclasses of the acs_objects table, then you automatically get the ability to structure them hierarchically. The way you do this is currently via the context_id column of acs_objects (Note that there is talk of adding in a parent_id column instead, because the use of context_id has been ambiguous in the past). So when you want to build your hierarchy, simply set the context_id values. Then, when you want to make hierarchical queries, you can do them as follows:

      db_multirow categories blog_categories "
      SELECT
      c.*,
      o.context_id,
      tree_level(o.tree_sortkey)
      FROM
      blog_categories c,
      acs_objects o
      WHERE
      c.category_id = o.object_id
      ORDER BY
      o.tree_sortkey"
    

Note the use of the tree_level() function, which gives you the level, starting from 1, 2, 3...

Here's an example, pulling all of the children for a given parent:

      SELECT
      children.*,
      tree_level(children.tree_sortkey) -
        tree_level(parent.tree_sortkey) as level
      FROM
      some_table parent,
      some_table children
      WHERE
      children.tree_sortkey between parent.tree_sortkey and tree_right(parent.tree_sortkey)
      and parent.tree_sortkey <> children.tree_sortkey
      and parent.key = :the_parent_key;
      

The reason we substract the parent's tree_level from the child's tree_level is that the tree_levels are global, so if you want the parent's tree_level to start with 0, you'll want the subtraction in there. This is a reason you'll commonly see magic numbers in tree_sortkey SQL queries, like tree_level(children.tree_sortkey) - 4. That is basically an incorrect way to do it, and subtracting the parent's tree_level is the preferred method.

This example does not include the parent. To return the entire subtree including the parent, leave out the non-equals clause:

      SELECT
      subtree.*,
      tree_level(subtree.tree_sortkey) -
        tree_level(parent.tree_sortkey) as level
      FROM some_table parent, some_table subtree
      WHERE
      subtree.tree_sortkey between parent.tree_sortkey and tree_right(parent.tree_sortkey)
      and parent.key = :the_parent_key;
    

If you are using the Content Repository, you get a similar facility, but the parent_id column is already there. Note you can do joins with tree_sortkey:

      SELECT
      p.item_id,
      repeat(:indent_pattern, (tree_level(p.tree_sortkey) - 5)* :indent_factor) as indent,
      p.parent_id as folder_id,
      p.project_name
      FROM pm_projectsx p, cr_items i
      WHERE p.project_id = i.live_revision
      ORDER BY i.tree_sortkey
    

This rather long thread explains How tree_sortkeys work and this paper describes the technique for tree_sortkeys, although the OpenACS implementation has a few differences in the implementation, to make it work for many languages and the LIKE construct in Postgres.

OpenACS Internationalization Requirements

Created by Gustaf Neumann, last modified by Gustaf Neumann 17 Feb 2008, at 07:08 AM

by Henry Minsky, Yon Feldman, Lars Pind, Peter Marklund, Christian Hvid, and others.

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

This document describes the requirements for functionality in the OpenACS platform to support globalization of the core and optional modules. The goal is to make it possible to support delivery of applications which work properly in multiple locales with the lowest development and maintenance cost.

internationalization (i18n)

The provision within a computer program of the capability of making itself adaptable to the requirements of different native languages, local customs and coded character sets.

locale

The definition of the subset of a user's environment that depends on language and cultural conventions.

localization (L10n)

The process of establishing information within a computer system specific to the operation of particular native languages, local customs and coded character sets.

globalization

A product development approach which ensures that software products are usable in the worldwide markets through a combination of internationalization and localization.

The Mozilla project suggests keeping two catchy phrases in mind when thinking about globalization:

  • One code base for the world

  • English is just another language

Building an application often involves making a number of assumptions on the part of the developers which depend on their own culture. These include constant strings in the user interface and system error messages, names of countries, cities, order of given and family names for people, syntax of numeric and date strings and collation order of strings.

The OpenACS should be able to operate in languages and regions beyond US English. The goal of OpenACS Globalization is to provide a clean and efficient way to factor out the locale dependent functionality from our applications, in order to be able to easily swap in alternate localizations.

This in turn will reduce redundant, costly, and error prone rework when targeting the toolkit or applications built with the toolkit to another locale.

The cost of porting the OpenACS to another locale without some kind of globalization support would be large and ongoing, since without a mechanism to incorporate the locale-specific changes cleanly back into the code base, it would require making a new fork of the source code for each locale.

A globalized application will perform some or all of the following steps to handle a page request for a specific locale:

  1. Decide what the target locale is for an incoming page request

  2. Decide which character set encoding the output should be delivered in

  3. If a script file to handle the request needs to be loaded from disk, determine if a character set conversion needs to be performed when loading the script

  4. If needed, locale-specific resources are fetched. These can include text, graphics, or other resources that would vary with the target locale.

  5. If content data is fetched from the database, check for locale-specific versions of the data (e.g. country names).

  6. Source code should use a message catalog API to translate constant strings in the code to the target locale

  7. Perform locale-specific linguistic sorting on data if needed

  8. If the user submitted form input data, decide what character set encoding conversion if any is needed. Parse locale-specific quantities if needed (number formats, date formats).

  9. If templating is being used, select correct locale-specific template to merge with content

  10. Format output data quantities in locale-specific manner (date, time, numeric, currency). If templating is being used, this may be done either before and/or after merging the data with a template.

Since the internationalization APIs may potentially be used on every page in an application, the overhead for adding internationalization to a module or application must not cause a significant time delay in handling page requests.

In many cases there are facilities in Oracle to perform various localization functions, and also there are facilities in Java which we will want to move to. So the design to meet the requirements will tend to rely on these capabilities, or close approximations to them where possible, in order to make it easier to maintain Tcl and Java OpenACS versions.

Here are the cases that we need to be able to handle efficiently:

  1. A developer needs to author a web site/application in a language besides English, and possibly a character set besides ISO-8859-1. This includes the operation of the OpenACS itself, i.e., navigation, admin pages for modules, error messages, as well as additional modules or content supplied by the web site developer.

    What do they need to modify to make this work? Can their localization work be easily folded in to future releases of OpenACS?

  2. A developer needs to author a web site which operates in multiple languages simultaneously. For example, www.un.org with content and navigation in multiple languages.

    The site would have an end-user visible UI to support these languages, and the content management system must allow articles to be posted in these languages. In some cases it may be necessary to make the modules' admin UI's operate in more than one supported language, while in other cases the backend admin interface can operate in a single language.

  3. A developer is writing a new module, and wants to make it easy for someone to localize it. There should be a clear path to author the module so that future developers can easily add support for other locales. This would include support for creating resources such as message catalogs, non-text assets such as graphics, and use of templates which help to separate application logic from presentation.

Other application servers: ATG Dyanmo, Broadvision, Vignette, ... ? Anyone know how they deal with i18n ?

Because the requirements for globalization affect many areas of the system, we will break up the requirements into phases, with a base required set of features, and then stages of increasing functionality.

10.0

A standard representation of locale will be used throughout the system. A locale refers to a language and territory, and is uniquely identified by a combination of ISO language and ISO country abbreviations.

See Content Repository Requirement 100.20

10.10 Provide a consistent representation and API for creating and referencing a locale

10.20 There will be a Tcl library of locale-aware formatting and parsing functions for numbers, dates and times. Note that Java has builtin support for these already.

10.30 For each locale there will be default date, number and currency formats. Currency i18n is NOT IMPLEMENTED for 5.0.0.

10.40Administrators can upgrade their servers to use new locales via the APM. NOT IMPLEMENTED in 5.0.0; current workaround is to get an xml file and load it manually.

20.0

The request processor must have a mechanism for associating a locale with each request. This locale is then used to select the appropriate template for a request, and will also be passed as the locale argument to the message catalog or locale-specific formatting functions.

20.10 The locale for a request should be computed by the following method, in descending order of priority:

  • get locale associated with subsite or package id

  • get locale from user preference

  • get locale from site wide default

    20.20 An API will be provided for getting the current request locale from the ad_conn structure.

30.0

A mechanism must be provided for a developer to group a set of arbitrary content resources together, keyed by a unique identifier and a locale.

For example, what approaches could be used to implement a localizable nav-bar mechanism for a site? A navigation bar might be made up of a set of text strings and graphics, where the graphics themselves are locale-specific, such as images of English or Japanese text (as on www.un.org). It should be easy to specify alternate configurations of text and graphics to lay out the page for different locales.

Design note: Alternative mechanisms to implement this functionality might include using templates, Java ResourceBundles, content-item containers in the Content Repository, or some convention assigning a common prefix to key strings in the message catalog.

40.0

A message catalog facility will provide a database of translations for constant strings for multilingual applications. It must support the following:

40.10 Each message will referenced via unique a key.

40.20 The key for a message will have some hierarchical structure to it, so that sets of messages can be grouped with respect to a module name or package path.

40.30 The API for lookup of a message will take a locale and message key as arguments, and return the appropriate translation of that message for the specifed locale.

40.40 The API for lookup of a message will accept an optional default string which can be used if the message key is not found in the catalog. This lets the developer get code working and tested in a single language before having to initialize or update a message catalog.

40.50 For use within templates, custom tags which invoke the message lookup API will be provided.

40.60 Provide a method for importing and exporting a flat file of translation strings, in order to make it as easy as possible to create and modify message translations in bulk without having to use a web interface.

40.70 Since translations may be in different character sets, there must be provision for writing and reading catalog files in different character sets. A mechanism must exist for identifying the character set of a catalog file before reading it.

40.80 There should be a mechanism for tracking dependencies in the message catalog, so that if a string is modified, the other translations of that string can be flagged as needing update.

40.90 The message lookup must be as efficient as possible so as not to slow down the delivery of pages.

Character Sets

50.0 A locale will have a primary associated character set which is used to encode text in the language. When given a locale, we can query the system for the associated character set to use.

The assumption is that we are going to use Unicode in our database to hold all text data. Our current programming environments (Tcl/Oracle or Java/Oracle) operate on Unicode data internally. However, since Unicode is not yet commonly used in browsers and authoring tools, the system must be able to read and write other character sets. In particular, conversions to and from Unicode will need to be explicitly performed at the following times:

  • Loading source files (.tcl or .adp) or content files from the filesystem

  • Accepting form input data from users

  • Delivering text output to a browser

  • Composing an email message

  • Writing data to the filesystem

Acs-templating does the following.

  • When the acs-templating package opens an an ADP or TCL file, it assumes the file is iso-8859-1. If the output charset (OutputCharset) in the AOLserver config file is set, then acs-templating assumes it's that charset. Writing Files

  • When the acs-templating package writes an an ADP or TCL file, it assumes the file is iso-8859-1. If the output charset (OutputCharset) in the AOLserver config file is set, then acs-templating assumes it's that charset.

There are two classes of Tcl files loaded by the system; library files loaded at server startup, and page script files, which are run on each page request.

Should we require all Tcl files be stored as UTF8? That seems too much of a burden on developers.

50.10 Tcl library files can be authored in any character set. The system must have a way to determine the character set before loading the files, probably from the filename.

50.20 Tcl page script files can be authored in any character set. The system must have a way to determine the character set before loading the files, probably from the filename.

50.30 Data which is submitted with a HTTP request using a GET or POST method may be in any character set. The system must be able to determine the encoding of the form data and convert it to Unicode on demand.

50.35 The developer must be able to override the default system choice of character set when parsing and validating user form data. INCOMPLETE - form widgets in acs-templating/tcl/date-procs.tcl are not internationalized. Also, acs-templating's UI needs to be internationalized by replacing all user-visible strings with message keys.

50.30.10In Japan and some other Asian languages where there are multiple character set encodings in common use, the server may need to attempt to do an auto-detection of the character set, because buggy browsers may submit form data in an unexpected alternate encoding.

50.40 The output character set for a page request will be determined by default by the locale associated with the request (see requirement 20.0).

50.50 It must be possible for a developer to manually override the output character set encoding for a request using an API function.

60.10 All OpenACS error messages must use the message catalog and the request locale to generate error message for the appropriate locale.NOT IMPLEMENTED for 5.0.0.

60.20 Web server error messages such as 404, 500, etc must also be delivered in the appropriate locale.

60.30 Where files are written or read from disk, their filenames must use a character set and character values which are safe for the underlying operating system.

70.0 For a given abstract URL, the designer may create multiple locale-specific template files may be created (one per locale or language)

70.10 For a given page request, the system must be able to select an approprate locale-specific template file to use. The request locale is computed as per (see requirement 20.0).

70.20A template file may be created for a partial locale (language only, without a territory), and the request processor should be able to find the closest match for the current request locale.

70.30 A template file may be created in any character set. The system must have a way to know which character set a template file contains, so it can properly process it.

70.50 The properties of a datasource column may include a datatype so that the templating system can format the output for the current locale. The datatype is defined by a standard OpenACS datatype plus a format token or format string, for example: a date column might be specified as 'current_date:date LONG,' or 'current_date:date "YYYY-Mon-DD"'

70.60 The forms API must support construction of locale-specific HTML form widgets, such as date entry widgets, and form validation of user input data for locale-specific data, such as dates or numbers. NOT IMPLEMENTED in 5.0.0.

70.70 For forms which allow users to upload files, a standard method for a user to indicate the charset of a text file being uploaded must be provided.

Design note: this presumably applies to uploading data to the content repository as well

80.10 Support API for correct collation (sorting order) on lists of strings in locale-dependent way.

80.20 For the Tcl API, we will say that locale-dependent sorting will use Oracle SQL operations (i.e., we won't provide a Tcl API for this). We require a Tcl API function to return the correct incantation of NLS_SORT to use for a given locale with ORDER BY clauses in queries.

80.40 The system must handle full-text search in any supported language.

90.10 Provide API support for specifying a time zone

90.20 Provide an API for computing time and date operations which are aware of timezones. So for example a calendar module can properly synchronize items inserted into a calendar from users in different time zones using their own local times.

90.30 Store all dates and times in universal time zone, UTC.

90.40 For a registered users, a time zone preference should be stored.

90.50 For a non-registered user a time zone preference should be attached via a session or else UTC should be used to display every date and time.

90.60 The default if we can't determine a time zone is to display all dates and times in some universal time zone such as GMT.

100.10 Since UTF8 strings can use up to three (UCS2) or six (UCS4) bytes per character, make sure that column size declarations in the schema are large enough to accomodate required data (such as email addresses in Japanese). Since 5.0.0, this is covered in the database install instructions for both PostgreSQL and Oracle.

When sending an email message, just as when delivering the content in web page over an HTTP connection, it is necessary to be able to specify what character set encoding to use.

110.10 The email message sending API will allow for a character set encoding to be specified.

110.20 The email accepting API will allow for character set to be parsed correctly (hopefully a well formatted message will have a MIME character set content type header)

Mail is not internationalized. The following issues must be addressed.

  • Six different functions currently call ns_sendmail. This means that there are six different end points for sending mail. This should be brought down to no more than two (one for acs_mail and one for acs_mail_lite), and ideally just one. Functions that currently call ns_sendmail directly should instead call acs_mail_lite.

  • Outgoing email functions (acs_mail and acs_mail_lite) must do the following: 1) Determine the appropriate language or languages to use for the message subject and message body. 2) Encode the subject and body appropriately and set message headers, in accordance with RFC 3282 (http://www.ietf.org/rfc/rfc3282.txt) and other RFCs.

  • Extreme Use case: Web site has a default language of Danish. A forum is set up for Swedes, so the forum has a package_id and a language setting of Swedish. A poster posts to the forum in Russian (is this possible?). A user is subscribed to the forum and has a language preference of Chinese. What should be in the message body and message subject? INCOMPLETE - The mail functions in acs_mail and acs_mail_lite are not internationalized.

  • Incoming mail should be localized.

Because globalization touches many different parts of the system, we want to reduce the implementation risk by breaking the implementation into phases.

Document Revision # Action Taken, Notes When? By Whom?
1 Updated with results of MIT-sponsored i18n work at Collaboraid. 14 Aug 2003 Joel Aufrecht
0.4 converting from HTML to DocBook and importing the document to the OpenACS kernel documents. This was done as a part of the internationalization of OpenACS and .LRN for the Heidelberg University in Germany 12 September 2002 Peter Marklund
0.3 comments from Christian 1/14/2000 Henry Minsky
0.2 Minor typos fixed, clarifications to wording 11/14/2000 Henry Minsky
0.1 Creation 11/08/2000 Henry Minsky

Linux Install Guides

Created by Gustaf Neumann, last modified by Gustaf Neumann 17 Feb 2008, at 07:08 AM

Here's a list of some helpful documentation for various OS's

Groups Design

Created by Gustaf Neumann, last modified by Gustaf Neumann 17 Feb 2008, at 07:08 AM

By Rafael H. Schloming and Mark Thomas

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

Almost all database-backed websites have users, and need to model the grouping of users. The OpenACS 4 Parties and Groups system is intended to provide the flexibility needed to model complex real-world organizational structures, particularly to support powerful subsite services; that is, where one OpenACS installation can support what appears to the user as distinct web services for different user communities.

The primary limitation of the OpenACS 3.x user group system is that it restricts the application developer to representing a "flat group" that contains only users: The user_groups table may contain the group_id of a parent group, but parent-child relationship support is limited because it only allows one kind of relationship between groups to be represented. Moreover, the Oracle database's limited support for tree-like structures makes the queries over these relationships expensive.

In addition, the Module Scoping design in OpenACS 3.0 introduced a party abstraction - a thing that is a person or a group of people - though not in the form of an explicit table. Rather, the triple of scope, user_id, and group_id columns was used to identify the party. One disadvantage of this design convention is that it increases a data model's complexity by requiring the programmer to:

  • add these three columns to each "scoped" table

  • define a multi-column check constraint to protect against data corruption (e.g., a row with a scope value of "group" but a null group_id)

  • perform extra checks in Tcl and PL/SQL functions and procedures to check both the user_id and group_id values

...

The core of the Group Systems data model is quite simple, but it was designed in the hopes of modeling "real world" organizations which can be complex graph structures. The Groups System only considers groups that can be modeled using directed acyclic graphs, but queries over these structures are still complex enough to slow the system down. Since almost every page will have at least one membership check, a number of triggers, views, and auxiliary tables have been created in the hopes of increasing performance. To keep the triggers simple and the number of triggers small, the data model disallows updates on the membership and composition tables, only inserts and deletes are permitted.

The data model has tried to balance the need to model actual organizations without making the system too complex or too slow. The added triggers, views, and tables and will increase storage requirements and the insert and delete times in an effort to speed access time. The limited flexibility (no updates on membership) trades against the complexity of the code.

The Group System data model consists of the following tables:

parties

The set of all defined parties: any person, user, or group must have a corresponding row in this table.

persons

The set of all defined persons. To allow easy sorting of persons, the name requirement 30.10 is met by splitting the person's name into two columns: first_names and last_name.

users

The set of all registered users; this table includes information about the user's email address and the user's visits to the site.

user_preferences

Preferences for the user.

groups

The set of all defined groups.

group_types

When a new type of group is created, this table holds additional knowledge level attributes for the group and its subtypes.

membership_rels

The set of direct membership relationships between a group and a party.

group_member_index

A mapping of a party P to the groups {Gi }the party is a member of; this mapping includes the type of relationship by including the appropriaterel_id from the membership_rels table.

composition_rels

The set of direct component relationships between a group and another group.

group_component_index

A mapping of a group Gto the set of groups {Gi } that G is a component of; this mapping includes the type of relationship by including the appropriaterel_id from the composition_rels table.

New groups are created through the group.new constructor. When a specialized type of group is required, the group type can be extended by an application developer. Membership constraints can be specified at creation time by passing a parent group to the constructor.

The membership_rels and composition_rels tables indicate a group's direct members and direct components; these tables do not provide a record of the members or components that are in the group by virtue of being a member or component of one of the group's component groups. Site pages will query group membership often, but the network of component groups can become a very complex directed acyclic graph and traversing this graph for every query will quickly degrade performance. To make membership queries responsive, the data model includes triggers (described in the next paragraph) which watch for changes in membership or composition and update tables that maintain the group party mappings, i.e., group_member_index and group_component_index. One can think of these tables as a manually maintained index.

The following triggers keep the group_*_index tables up to date:

membership_rels_in_tr

Is executed when a new group/member relationship is created (an insert on membership_rels)

membership_rels_del_tr

Is executed when a group/member relationship is deleted (a delete on membership_rels)

composition_rels_in_tr

Is executed when a new group/component relationship is created (an insert on composition_rels)

composition_rels_del_tr

Is executed when a group/component relationship is deleted (a delete on composition_rels)

The data model provides the following views onto the group_member_index and group_component_index tables. No code outside of Groups System should modify the group_*_index tables.

group_member_map

A mapping of a party to the groups the party is a member of; this mapping includes the type of relationship by including the appropriaterel_id from the membership_rels table.

group_approved_member_map

A mapping of a party to the groups the party is an approved member of (member_state is 'approved'); this mapping includes the type of relationship by including the appropriaterel_id from the membership_rels table.

group_distinct_member_map

A person may appear in the group member map multiple times, for example, by being a member of two different groups that are both components of a third group. This view is strictly a mapping of approved members to groups.

group_component_map

A mapping of a group Gto the set of groups {Gi } group G is a component of; this mapping includes the type of relationship by including the appropriaterel_id from the composition_rels table.

party_member_map

A mapping of a party P to the set of parties {Pi } party P is a member of.

party_approved_member_map

A mapping of a party P to the set of parties {Pi } party P is an approved member of.

The API consists of tables and views and PL/SQL functions.

The group_types table is used to create new types of groups.

The group_member_map, group_approved_member_map, group_distinct_member_map, group_component_map, party_member_map, and party_approved_member_map views are used to query group membership and composition.

Person

person.new creates a new person and returns the person_id. The function must be given the full name of the person in two pieces: first_names and last_name. All other fields are optional and default to null except for object_type which defaults to person and creation_date which defaults to sysdate. The interface for this function is:

function person.new (
  person_id          persons.person_id%TYPE,
  object_type        acs_objects.object_type%TYPE,
  creation_date      acs_objects.creation_date%TYPE,
  creation_user      acs_objects.creation_user%TYPE,
  creation_ip        acs_objects.creation_ip%TYPE,
  email              parties.email%TYPE,
  url                parties.url%TYPE,
  first_names        persons.first_names%TYPE,
  last_name          persons.last_name%TYPE
) return persons.person_id%TYPE;

person.delete deletes the person whose person_id is passed to it. The interface for this procedure is:

procedure person.delete (
  person_id     persons.person_id%TYPE
);

person.name returns the name of the person whose person_id is passed to it. The interface for this function is:

function person.name (
  person_id     persons.person_id%TYPE
) return varchar;

User

acs_user.new creates a new user and returns the user_id. The function must be given the user's email address and the full name of the user in two pieces: first_names and last_name. All other fields are optional. The interface for this function is:

function acs_user.new (
  user_id            users.user_id%TYPE,
  object_type        acs_objects.object_type%TYPE,
  creation_date      acs_objects.creation_date%TYPE,
  creation_user      acs_objects.creation_user%TYPE,
  creation_ip        acs_objects.creation_ip%TYPE,
  email              parties.email%TYPE,
  url                parties.url%TYPE,
  first_names        persons.first_names%TYPE,
  last_name          persons.last_name%TYPE
  password           users.password%TYPE,
  salt               users.salt%TYPE,
  password_question  users.password_question%TYPE,
  password_answer    users.password_answer%TYPE,
  screen_name        users.screen_name%TYPE,
  email_verified_p   users.email_verified_p%TYPE
) return users.user_id%TYPE;

acs_user.delete deletes the user whose user_id is passed to it. The interface for this procedure is:

procedure acs_user.delete (
  user_id       users.user_id%TYPE
);

acs_user.receives_alerts_p returns 't' if the user should receive email alerts and 'f' otherwise. The interface for this function is:

function acs_user.receives_alerts_p (
  user_id       users.user_id%TYPE
) return varchar;

Use the procedures acs_user.approve_email and acs_user.unapprove_email to specify whether the user's email address is valid. The interface for these procedures are:

procedure acs_user.approve_email (
  user_id       users.user_id%TYPE
);

procedure acs_user.unapprove_email (
  user_id       users.user_id%TYPE
);

Group

acs_group.new creates a new group and returns the group_id. All fields are optional and default to null except for object_type which defaults to 'group', creation_date which defaults to sysdate, and group_name which is required. The interface for this function is:

function acs_group.new (
  group_id           groups.group_id%TYPE,
  object_type        acs_objects.object_type%TYPE,
  creation_date      acs_objects.creation_date%TYPE,
  creation_user      acs_objects.creation_user%TYPE,
  creation_ip        acs_objects.creation_ip%TYPE,
  email              parties.email%TYPE,
  url                parties.url%TYPE,
  group_name         groups.group_name%TYPE
) return groups.group_id%TYPE;

acs_group.name returns the name of the group whose group_id is passed to it. The interface for this function is:

function acs_group.name (
  group_id      groups.group_id%TYPE
) return varchar;

acs_group.member_p returns 't' if the specified party is a member of the specified group. Returns 'f' otherwise. The interface for this function is:

function acs_group.member_p (
  group_id      groups.group_id%TYPE,
  party_id      parties.party_id%TYPE,
) return char;

Membership Relationship

membership_rel.new creates a new membership relationship type between two parties and returns the relationship type's rel_id. All fields are optional and default to null except for rel_type which defaults to membership_rel. The interface for this function is:

function membership_rel.new (
  rel_id             membership_rels.rel_id%TYPE,
  rel_type           acs_rels.rel_type%TYPE,
  object_id_one      acs_rels.object_id_one%TYPE,
  object_id_two      acs_rels.object_id_two%TYPE,
  member_state       membership_rels.member_state%TYPE,
  creation_user      acs_objects.creation_user%TYPE,
  creation_ip        acs_objects.creation_ip%TYPE,
) return membership_rels.rel_id%TYPE;

membership_rel.ban sets the member_state of the given rel_id to 'banned'. The interface for this procedure is:

procedure membership_rel.ban (
  rel_id           membership_rels.rel_id%TYPE
);

membership_rel.approve sets the member_state of the given rel_id to 'approved'. The interface for this procedure is:

procedure membership_rel.approve (
  rel_id           membership_rels.rel_id%TYPE
);

membership_rel.reject sets the member_state of the given rel_id to 'rejected. The interface for this procedure is:

procedure membership_rel.reject (
  rel_id           membership_rels.rel_id%TYPE
);

membership_rel.unapprove sets the member_state of the given rel_id to an empty string ''. The interface for this procedure is:

procedure membership_rel.unapprove (
  rel_id           membership_rels.rel_id%TYPE
);

membership_rel.deleted sets the member_state of the given rel_id to 'deleted'. The interface for this procedure is:

procedure membership_rel.deleted (
  rel_id           membership_rels.rel_id%TYPE
);

membership_rel.delete deletes the given rel_id. The interface for this procedure is:

procedure membership_rel.delete (
  rel_id           membership_rels.rel_id%TYPE
);

Composition Relationship

composition_rel.new creates a new composition relationship type and returns the relationship's rel_id. All fields are optional and default to null except for rel_type which defaults to composition_rel. The interface for this function is:

function membership_rel.new (
  rel_id             composition_rels.rel_id%TYPE,
  rel_type           acs_rels.rel_type%TYPE,
  object_id_one      acs_rels.object_id_one%TYPE,
  object_id_two      acs_rels.object_id_two%TYPE,
  creation_user      acs_objects.creation_user%TYPE,
  creation_ip        acs_objects.creation_ip%TYPE,
) return composition_rels.rel_id%TYPE;

composition_rel.delete deletes the given rel_id. The interface for this procedure is:

procedure membership_rel.delete (
  rel_id           composition_rels.rel_id%TYPE
);

Describe the admin pages.

...

...

...

System creator

Rafael H. Schloming

System owner

Rafael H. Schloming

Documentation author

Mark Thomas

Document Revision # Action Taken, Notes When? By Whom?
0.1 Creation 08/22/2000 Rafael H. Schloming
0.2 Initial Revision 08/30/2000 Mark Thomas
0.3 Additional revisions; tried to clarify membership/compostion 09/08/2000 Mark Thomas

OpenACS Packages

Created by Gustaf Neumann, last modified by Gustaf Neumann 17 Feb 2008, at 07:08 AM

By Pete Su and Bryan Quinn

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

This document is a guide on how to write a software package for OpenACS. OpenACS packages are installed and maintained with the OpenACS Package Manager (APM) which is part of the acs-admin package. This document presents reasons for packaging software, conventions for the file system and naming that must be followed, and step by step instructions for creating a new package for the "Notes" example package.

Here is how an OpenACS 5 server is laid out starting from the Server root (ROOT):

Figure11.1.Server file layout diagram

ROOT/
    bin/
        Various executables and scripts for server maintanence.
    content-repository-content-files/
        content repository content stored in the filesystem.
    etc/
        Installation scripts and configuration files.
    packages/
        acs-admin/
        acs-api-browser/
        ... many many more...
        workflow/
    log/
        Server error and access logs
    tcl/
        bootstrap code
    www/
        Pages not in packages (static content, customized pages)

Each package encapsulates all of its data model, library code, logic, adminstration pages and user pages in a single part of the file tree. This means developers can track down everything that is related to a particular package without hunting all over the file system. Encapsulating everything about a package in one place also makes it much easier to distribute packages independently from the OpenACS Core.

In order to make this work, we need a system that keeps track of the packages that have been installed in the server, where those packages have been installed, and a standard way to map URLs that a client sends to our server to the right page in the appropriate package. While we're at it, this tool should also automate package installation, dependency checking, upgrades, and package removal. In OpenACS 5, this tool is called the APM.

To illustrate the general structure of a package, let's see what the package for the "notes" application should look like.

Figure11.2.Package file layout diagram

ROOT/
  +-- packages/    APM Root
        |
        +-- notes/  Package Root
        |     |
        |     +-- notes.info                              Package Specification File
        |     +-- sql/
        |     |     |
        |     |     +-- oracle/
        |     |     |        |
        |     |     |        +-- notes-create.sql         Data Model Creation Script for Oracle
        |     |     |        +-- notes-drop.sql           Data Model Drop Script
        |     |     |        +-- *.sql                    Data Model Files
        |     |     |        +-- upgrade/
        |     |     |            +-- upgrade-4.1-4.5.sql  Data Model Upgrade Scripts
        |     |     +-- postgresql/
        |     |     |        |
        |     |     |        +-- notes-create.sql         Data Model Creation Script for PostgreSQL
        |     |     |        +-- notes-drop.sql           Data Model Drop Script
        |     |     |        +-- *.sql                    Data Model Files
        |     |     |        +-- upgrade/
        |     |     |            +-- upgrade-4.1-4.5.sql  Data Model Upgrade Scripts
        |     +-- tcl/
        |     |     |
        |     |     +-- notes-procs.tcl                   Tcl Library
        |     |     +-- notes-procs.xql                   SQL92 Queries for notes-procs.tcl
        |     |     +-- notes-procs-oracle.xql            Oracle-specific queries for notes-procs.tcl
        |     |     +-- notes-procs-postgresql.xql        PostgreSQL-specific Queries for notes-procs.tcl
        |     |     +-- notes-init.tcl                    Tcl Initialization
        |     |     +-- notes-init.xql                    Queries for notes-init.tcl (work in all DBs)
        |     |     +-- *.tcl                             Tcl Library Files
        |     +-- lib/
        |     |     |
        |     |     +-- *.tcl                             Includable page logic
        |     |     +-- *.adp                             Includable page templates
        |     +-- www/
        |     |     |
        |     |     +-- admin/                            Administration UI
        |     |     |     +-- tests/                      Regression Tests
        |     |     |     |     +-- index.tcl             Regression Test Index Page
        |     |     |     |     +-- ...                   Regression Tests
        |     |     |     +-- index.tcl                   Administration UI Index Page
        |     |     |     +-- ...                         Administration UI Pages
        |     |     |
        |     |     +-- doc/                              Documentation
        |     |     |     +-- index.html                  Documentation Index Page
        |     |     |     +-- ...                         Administration Pages
        |     |     +-- resources/                        Static Content
        |     |     |     +-- ...                         Static Content files
        |     |     +-- index.tcl                         UI Index Page
        |     |     +-- index.adp                         UI Index Template
        |     |     +-- index.xql                         Queries for UI Index page
        |     |     +-- *.tcl                             UI Logic Scripts
        |     |     +-- *.adp                             UI Templates
        |     |     +-- *-oracle.xql                      Oracle-specific Queries
        |     |     +-- *-postgresql.xql                  PostgreSQL-specific Queries
        +-- Other package directories.

All file locations are relative to the package root, which in this case is ROOT/packages/notes. The following table describes in detail what each of the files up in the diagram contain.

A special note on the PACKAGE-KEY/www/resources directory. Files in this directory are available at http://yourserver/resources/PACKAGE-KEY/... and are returned without any permissions checking or even checks that the package is installed or mounted. Files are returned directly, so .tcl or .adp files are not sourced in these directories. This makes it suitable for storing icons, css files, javascript, and other static content which can be treated this way.

Table11.1.Package files

File Type Its Use Naming Convention
Package Specification File The package specification file is an XML file generated and maintained by the OpenACS Package Manager (APM). It specifies information about the package including its parameters and its files. notes.info
Data Model Creation Script Contains the SQL that creates the necessary data model and PL/SQL packages (or PL/pgSQL or whatever) to support the package. The name must match the convention below or the package will not be installed correctly. Notice that the script must be under the appropriate directory for the database you are developing your package for (hopefully all OpenACS-supported databases :-)) sql/<database>/notes-create.sql
Data Model Drop Script Contains the SQL that removes the data model and PL/SQL packages generated by the creation script. The name must match the convention below or the package will not be installed correctly. sql/<database>/notes-drop.sql
Data Model File Any .sql file that does not match the naming convention above is recognized as a data model file. It is useful to separate the SQL in the creation and drop scripts into several files and then have the scripts source the other data model files. In Oracle this can be done by including @@ filename in the creation or drop scripts. See the Oracle FAQ for examples. In PostgreSQL the same is acomplished by including \i filename. sql/<database>/*.sql
Data Model Upgrade Scripts Contain changes to the data model between versions. The APM can automatically load the appropriate upgrade scripts when upgrading to a new version of a package. sql/<database>/upgrade/upgrade-<old>-<new>.sql
SQL92 Query Files Files with queries that are supported by all databases. These are usually SQL92 queries. Notice that the .xql filename must match the name of the .tcl file that uses those queries. *.xql
Oracle-specific Query Files Files with queries that are Oracle-specific. Notice that the .xql filename must match the name of the .tcl file that uses those queries. *-oracle.xql
PostgreSQL-specific Query Files Files with queries that are PostgreSQL-specific. Notice that the .xql filename must match the name of the .tcl file that uses those queries. *-postgresql.xql
Tcl Library Files The Tcl library files include a set of procedures that provide an application programming interface (API) for the package to utilize. tcl/notes-procs.tcl
Tcl Initialization The initialization files are used to run Tcl procedures that should only be sourced once on startup. Examples of statements to put here are registered filters or procedures. Tcl initialization files are sourced once on server startup after all of the Tcl library files are sourced. tcl/notes-init.tcl
Administration UI The administration UI is used to administer the instances of the package. For example, the forums administration UI is used to create new forums, moderate postings, and create new categories for forums postings. www/admin/*
Administration UI Index Page Every package administration UI must have an index page. In most cases, this is index.tcl but it can be any file with the name index, such as index.html or index.adp. www/admin/index.tcl
Regression Tests Every package should have a set of regression tests that verify that it is in working operation. These tests should be able to be run at any time after the package has been installed and report helpful error messages when there is a fault in the system. www/admin/tests/
Regression Test Index Page The regression test directory must have an index page that displays all of the tests available and provides information on how to run them. This file can have any extension, as long as its name is index. www/admin/tests/index.html
Documentation Every package must include a full set of documentation that includes requirements and design documents, and user-level and developer-level documentation where appropriate. www/doc/
Documentation Index Page The documentation directory must include a static HTML file with the name of index.html. www/doc/index.html
UI Logic Scripts Packages provide a UI for users to access the system. The UI is split into Logic and Templates. The logic scripts perform database queries and prepare variables for presentation by the associated templates. www/*.tcl
UI Templates Templates are used to control the presentation of the UI. Templates receive a set of data sources from the logic scripts and prepare them for display to the browser. www/*.adp
UI Index Page The UI must have an index page composed of a logic script called index.tcl and a template called index.adp. www/index.tcl

The APM is used to create, maintain, and install packages. It takes care of copying all of the files and registering the package in the system. The APM is responsible for:

  1. Package registration

  2. Automatic installation of packages: loading data models, code libraries, and so on.

  3. Checking what packages depend on what other packages.

  4. Storing information on the package including ownership and a file list.

In addition for packages that are applications, the APM is responsible for keeping track of where in the site a user must go in order to use the application. To do this, the APM defines a set of objects that we call package instances. Once a package is loaded, the administrator can create as many instances of the package as she likes, and map these instances to any URL in the site that she wants. If packages are analogous to executable programs in an operating system, then package instances are analgous to multiple running copies of a single program. Each instance can be independently administered and each instance maintains its own set of application parameters and options.

The following sections will show you how to make a package for the Notes application. In addition, they will discuss some site management features in OpenACS 5 that take advantage of the APM's package instance model. The two most important of these are subsites, and the site map tool, which can be used to map applications to one or more arbitrary URLs in a running site.

We will also discuss how to organize your files and queries so they work with the OpenACS Query Dispatcher.

Here is how you make a package.

  1. Login as a site-wide administrator on your web service.

  2. Go to the package manager on your server. The URL is /acs-admin/apm.

  3. Click on the link /acs-admin/apm/package-add.

  4. Fill out the form for adding a new package. The form explains what everything means, but we'll repeat the important bits here for easy reference:

    Package Key

    This is a short text string that should uniquely name your package to distinguish it from all the others. It is used as a database key to keep track of the package and as the name of the directory in the file system where all the files related to your package will live. Example package keys in the current system include: forums, acs-kernel and so on. For the example application, we will use the package key notes.

    Package Name

    This is a short human readable name for your package. For our example, we will use the name "Notes".

    Package Plural

    If your package name is a nice singular noun, this should be the plural form of it. I assume the plural form is used when multiple instances of the package are used by a single service. We'll talk more about package instances later. Our example apllication doesn't really have a good plural name. So just make it also be "Notes".

    Package Type

    Generally we think of packages as either being applications, meaning that the package is meant primarily for use by end-users, or services meaning that the package is meant to be a reusable library of code, to be used by other packages. forums is a good example of an application, while acs-templating is a good example of a service. Our example is an application, so pick that.

    Package URL

    The URL from which people will download your package when it is done. Just use the default for this, you can change it later.

    Initial Version

    Just use the default here, which by convention is 0.1d.

    Version URL

    Just use the default here.

    Summary and Description

    Enter a short summary and longer description of what the Notes application will do. That is, something like "this application keeps short textual notes in the database", and so on.

  5. Click the button "Create Package".

  6. At this point, APM will create a directory called ROOT/packages/notes.

  7. The directory that APM created will be empty except for the notes.info file. Create a file called ROOT/packages/notes/sql/oracle/notes-create.sql. We'll fill this file with our data model very soon. Create a file called ROOT/packages/notes/sql/oracle/notes-drop.sql. This will contain the instructions to drop the data model. To be complete, you would also create the PostgreSQL versions of these files as well in ROOT/packages/notes/sql/postgresql/notes-create.sql and ROOT/packages/notes/sql/postgresql/notes-drop.sql.

    After you do this, go back to the main APM page. From there, click the link called "notes" to go to the management page for the new package. Now click the link called "Manage file information", then the "Scan the packages/notes directory for additional files in this package" link on that page to scan the file system for new files. This will bring you do a page that lists all the files you just added and lets you add them to the notes package.

    Note that while the .sql files have been added to the packge, they have not been loaded into the database. For the purposes of development, you have to load the data model by hand, because while OpenACS has automatic mechanisms for loading and reloading .tcl files for code, it does not do the same thing for data model files.

  8. Now go back to the main management page for the notes If your package has parameters, create them using the "Manage Parameter Information" link. Define package callbacks via the "Tcl Callbacks (install, instantiate, mount)" link.

  9. The new package has been created and installed in the server. At this point, you should add your package files to your CVS repository. I'll assume that you have set up your development repository according to the standards described in this appendix. If so, then you just do this:

    % cd ROOT/packages
    % cvs add notes
    % cd notes
    % cvs add notes.info
    % cvs add sql
    % cd sql
    % cvs add *.sql
    % cd ROOT/packages/notes
    % cvs commit -m "add new package for notes"
        
  10. Now you can start developing the package. In addition to writing code, you should also consider the tasks outlined in the package development tutorial.

At this point, you are probably excited to see your new package in action. But, we haven't added any user visible pages yet. By convention, user visible pages go in the ROOT/packages/notes/www directory. So go there and add a file called hello.html with some text in it. Now we have to make the user pages visible in the site. Since we didn't put the pages underneath ROOT/www they will not appear on their own. What we have to do is mount the application into the site map. That is, we have to define the URL from which the application will serve its pages.

In OpenACS 5, administrators can define an arbitrary mapping between the URLs the user types and the actual file in the file system that is served. This mapping is called the site map and entries in the site map are called site nodes. Each site node maps a URL to an OpenACS object. Since package instances are objects, the site map allows us to easily map package instances to URLs. As we said before, each instance of an application has its own set of parameters and runs from its own URL within the site. What this means is that even though all the code for the notes application lives in ROOT/packages/notes, the application itself can run from any number of locations in the site. This allows developers and administrators to build sites that look to the user like a collection of many indedendent applications that actually run on a single shared code base. The request-processor document shows you how OpenACS figures out which instance of your application was requested by the user at any given time. The page development tutorial shows you how to use this information in your user interface.

In order to make the new notes application visible to users, we have to mount it in the site map. You do this by going to the Site Map page, which is by default available at /acs-admin/site-map. Use the interface here to add a new sub-folder called notes to the root of the site, then click "new application" to mount a new instance of the notes application to the site. Name the new instance notes-1.

Then type this URL into your browser: http://yourserver/notes/hello.html

Now you should see the contents of the page that you added. What has happened is that all URLs that start with /notes have been mapped in such a way as to serve content from the directory ROOT/packages/notes/www. At this point, you can experiment with the site map by mounting multiple instances of the not yet written Notes application at various places in the site. In a later document, we'll see how to write your application so that the code can detect from what URL it was invoked. This is the key to supporting subsites.

The APM performs the following tasks in an OpenACS site:

  • Manages creation, installation, and removal of packages from the server. Also keeps track of what files belong to which packages.

  • Manages package upgrades.

  • Manages information on all package instances in a site. For correctly written application packages, this allows the site administrator to map multiple instances of a package to URLs within a site.

  • Writes out package distribution files for other people to download and install. We'll cover this later.

Future Topics

Created by Gustaf Neumann, last modified by Gustaf Neumann 17 Feb 2008, at 07:08 AM

  • 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)

  • 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

Prepare the package for distribution.

Created by Gustaf Neumann, last modified by Gustaf Neumann 17 Feb 2008, at 07:08 AM

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 /var/tmp.

Package development guidelines

Vacuum Postgres nightly

Created by Gustaf Neumann, last modified by Gustaf Neumann 17 Feb 2008, at 07:08 AM

The "vacuum" command must be run periodically to reclaim space in versions of PostgreSQL before 7.4. The "vacuum analyze" form additionally collects statistics on the disbursion of columns in the database, which the optimizer uses when it calculates just how to execute queries. The availability of this data can make a tremendous difference in the execution speed of queries. This command can also be run from cron, but it probably makes more sense to run this command as part of your nightly backup procedure - if "vacuum" is going to screw up the database, you'd prefer it to happen immediately after (not before!) you've made a backup! The "vacuum" command is very reliable, but conservatism is the key to good system management. So, if you're using the export procedure described above, you don't need to do this extra step.

Edit your crontab:

[joeuser ~]$ crontab -e

We'll set vacuum up to run nightly at 1 AM. Add the following line:

0 1 * * * /usr/local/pgsql/bin/vacuumdb $OPENACS_SERVICE_NAME

Next Page