Index: openacs-4/packages/acs-core-docs/www/xml/Makefile =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/Makefile,v diff -u -r1.3 -r1.3.2.1 --- openacs-4/packages/acs-core-docs/www/xml/Makefile 22 Sep 2002 05:16:25 -0000 1.3 +++ openacs-4/packages/acs-core-docs/www/xml/Makefile 7 Apr 2003 16:45:03 -0000 1.3.2.1 @@ -18,10 +18,12 @@ XSLTPROC=/usr/bin/xsltproc HTMLDOC=/usr/bin/htmldoc -all: html pdf +all: html prelim: cp -u files/*.{txt,html} ../files/ + cp -u files/samplenote/*.* ../files/samplenote/ + cp -u files/samplenote/Makefile ../files/samplenote/ cp -u images/*.{pdf,png,gif,jpg} ../images/ cp -u openacs.css .. Index: openacs-4/packages/acs-core-docs/www/xml/openacs.css =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/openacs.css,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/acs-core-docs/www/xml/openacs.css 10 Aug 2002 21:38:38 -0000 1.1 +++ openacs-4/packages/acs-core-docs/www/xml/openacs.css 7 Apr 2003 16:45:03 -0000 1.1.2.1 @@ -1,4 +1,20 @@ +/* Override some HTML defaults to make things look better */ + +hr +{height: 1px} + +table { +border-collapse: collapse; +border-spacing: 0;} + +td { +padding: 2px} +} + +/* These are aimed at DocBook output, specifically from the chunk.xsl style and derivatives /* + body, ol, td, th, hr, h1, h2, h3, strong, dl, a, blockquote, em, .force, dt, dd, ul, li, p{font-family:verdana,helvetica,arial,sans-serif} + a:link{color:0000ff} a:visited{color:000099} a.topnav{font-size:11pt} @@ -7,7 +23,23 @@ code{font-family:mono-space} .CVS, .cvstag{font-family:mono-space; font-size:small; color:#999999; text-align:right} + +/* this section is targeted at Docbook-generated HTML */ + +pre {background-color:#eeeeee;} + .codeblock{background-color:#ffffff;font-family:monospace} .programlisting{background-color:#CCCCCC} .strong{font-weight:bold} .authorblurb{font-size:small} + +.guibutton{} +.replaceable{color:red; font-style:italic;font-size:1.1em;} +.guilabel{padding:2px;} +.programlisting{background-color:#eeeeee} +.strong{font-weight:bold} +.authorblurb{font-size:small} +.screen{padding:3px; background-color:#eeeeee} +.action{padding:0.5em; margin:0.5em;font-weight:bold; border: 1px dotted gray;} + + Index: openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-advanced.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-advanced.xml,v diff -u -r1.1.2.1 -r1.1.2.2 --- openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-advanced.xml 30 Mar 2003 20:31:47 -0000 1.1.2.1 +++ openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-advanced.xml 7 Apr 2003 16:45:17 -0000 1.1.2.2 @@ -18,7 +18,10 @@ 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 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 @@ -35,6 +38,84 @@ + 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. + + @author joel@aufrecht.org + @creation-date 2003-02-12 + @cvs-id $Id$ +} { + note_id:integer + confirm_p:optional +} + +set title "Delete Note" + +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" + 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 @@ -54,15 +135,15 @@ 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. - Now we need to create html that shows any existing comments. + 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. - Now we put our two new variables in the notes.adp + We put our two new variables in the notes.adp page. <a href="@comment_add_url@">Add a comment</a> @comments_html@ Index: openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-db.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-db.xml,v diff -u -r1.1.2.1 -r1.1.2.2 --- openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-db.xml 30 Mar 2003 20:31:47 -0000 1.1.2.1 +++ openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-db.xml 7 Apr 2003 16:45:17 -0000 1.1.2.2 @@ -13,7 +13,7 @@ the samplenote/sql/oracle or samplenote/sql/postgresql. Packages can support Oracle, PostgreSQL, or both. - The first file is + The first file will be samplenote-create.sql. The package manager requires a file with the name packagekey-create.sql, @@ -30,22 +30,32 @@ stored procedures and is fairly complicated even for a simple table. A listing is provided below for you to cut and paste. Comments are located within the source code, with each comment - preceeding the relevant code. + preceeding the relevant code. (More + info about ACS Objects) First, create the necessary subdirectories and add them cvs as you go. - [service0@yourserver samplenote]$ mkdir sql + [service0@yourserver samplenote]$ cd /web/service0/packages/samplenote +[service0@yourserver samplenote]$ mkdir sql [service0@yourserver samplenote]$ cvs add sql Directory /cvsroot/service0/packages/samplenote/sql added to the repository [service0@yourserver samplenote]$ cd sql/ [service0@yourserver sql]$ mkdir postgresql [service0@yourserver sql]$ cvs add postgresql Directory /cvsroot/service0/packages/samplenote/sql/postgresql added to the repository -[service0@yourserver sql]$ cd postgresql/ -[service0@yourserver postgresql]$ emacs samplenote-create.sql +[service0@yourserver sql]$ cd postgresql/ + We break out the sql commands into several files that can + be called independently, and then call all of the create files + from the master create file. The top of each sql file has some + standard comments, including doc tags such as + @author which will be picked up + by the API browser. The string + $Id$ will automatically be + expanded when the file is checked in to cvs. +[service0@yourserver postgresql]$ emacs samplenote-create.sql Paste this into the file and save and close.
- Database Creation Script + Database Creation Script - master create file -- -- packages/samplenote/sql/postgresql/samplenote-create.sql -- @@ -54,15 +64,47 @@ -- @cvs-id $Id$ -- -- + +\i samplenote-table-create.sql +\i samplenote-functions-create.sql +
+ Create the file to create the database table. + [service0@yourserver postgresql]$ emacs samplenote-table-create.sql + Paste this into the file and save and close. +
+ Database Creation Script - table + -- +-- packages/samplenote/sql/postgresql/samplenote-table-create.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-10-22 +-- @cvs-id $Id$ +-- -/* We create a temporary function 'inline_0' which we use to -create an ACS Object Type. Each record in our package is a -'samplenote', and each samplenote will be an ACS Object. By making -our records ACS objects, we gain access to the permissions model and -other meta-functions. Each 'samplenote' record will have a matching -record in acs_objects. In general, you should make a table an ACS -Object Type if you expect to apply permissions directly at that level. */ +/* Create the table. Each constraint is named to make it easier to +identify during debugging. The note_id is identical to the object +id. */ +create table samplenote ( + note_id integer constraint samplenote_fk + references acs_objects(object_id) + constraint samplenote_pk + primary key, + title varchar(255) + constraint samplenote_title_nn + not null, + body varchar(1024) +); + + +/* Create a temporary function 'inline_0' which we use to create an +ACS Object Type. Each record in our package is an 'samplenote', and each +samplenote is an ACS Object. That means that each record in the samplenote +table has a corresponding record in acs_objects. By making our +records ACS objects, we gain access to the permissions model and other +meta-functions. In general, you should make a table an ACS Object +Type if you expect to apply permissions directly at that level. */ + create function inline_0 () returns integer as ' begin @@ -71,7 +113,7 @@ ''Sample Note'', -- pretty_name ''Sample Notes'', -- pretty_plural ''acs_object'', -- supertype - ''samplenote'', -- table_name + ''samplenote'', -- table_name ''note_id'', -- id_column null, -- package_name ''f'', -- abstract_p @@ -82,42 +124,51 @@ end;' language 'plpgsql'; select inline_0 (); drop function inline_0 (); + +
+ Create the file to create the functions used to manipulate records. +[service0@yourserver postgresql]$ emacs samplenote-functions-create.sql + Paste this into the file and save and close. +
+ Database Creation Script - functions + -- +-- packages/samplenote/sql/postgresql/samplenote-functions-create.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-10-22 +-- @cvs-id $Id$ +-- +-- -/* We create the table. Each constraint is named to make it easier to -identify during debugging. The note_id is identical to the object -id.*/ - -create table samplenote ( - note_id integer constraint samplenote_fk - references acs_objects(object_id) - constraint samplenote_pk - primary key, - title varchar(255) - constraint samplenote_title_nn - not null, - body varchar(1024) -); - /* Since each record is also an Object, we make a creation function that will create an object and then use the object id to create a -record in our table. The function also takes several optional input -variables. Creation date will default to now; creation user should be -the user id that will own the object; creation ip is optional; context -id should usually be the package id, which will be explained later.*/ +record in our table. The function also takes several input variables. +Title is required +Body is required +Creation date is optional and defaults to now +Creation user, required, is the user id owns the object +Creation ip is optional +Context id, required, is the id of the package instance. This allows +segregation of records by package, required to make the package +"package-aware." +define_function_args prepares the function to be used by a tcl wrapper function. */ -create function samplenote__new (varchar,varchar,timestamp,integer,varchar,integer) +select define_function_args(samplenote__new,'note_id,title,creation_date,creation_user,creation_ip,context_id'); + +create or replace function samplenote__new (integer,varchar,varchar,timestamptz,integer,varchar,integer) returns integer as ' declare - p_title alias for $1; - p_body alias for $2; - p_creation_date alias for $3; - p_creation_user alias for $4; - p_creation_ip alias for $5; - p_context_id alias for $6; + p_note_id alias for $1; + p_title alias for $2; + p_body alias for $3; + p_creation_date alias for $4; + p_creation_user alias for $5; + p_creation_ip alias for $6; + p_context_id alias for $7; v_samplenote_id int; begin v_samplenote_id := acs_object__new ( - null, + p_note_id, ''samplenote'', p_creation_date, p_creation_user, @@ -130,15 +181,17 @@ (v_samplenote_id, p_title, p_body); PERFORM acs_permission__grant_permission( v_samplenote_id, - p_owner_id, + p_creation_user, ''admin'' ); return v_samplenote_id; end;' language 'plpgsql'; /* The __delete function deletes a record and all related overhead. */ -create function samplenote__delete (integer) + +select define_function_args('samplenote___delete','note_id'); +create or replace function samplenote__delete (integer) returns integer as ' declare p_samplenote_id alias for $1; @@ -158,15 +211,17 @@ can be identified. Now we have to build that function. In this case, we'll return a field called title as the name. */ -create function samplenote__name (integer) +select define_function_args('samplenote___name','note_id'); + +create or replace function samplenote__name (integer) returns varchar as ' declare p_samplenote_id alias for $1; v_samplenote_name samplenote.title%TYPE; begin select title into v_samplenote_name from samplenote - where samplenote_id = p_samplenote_id; + where note_id = p_samplenote_id; return v_samplenote_name; end; ' language 'plpgsql'; @@ -180,15 +235,18 @@ -- packages/samplenote/sql/samplenote-drop.sql -- drop script -- +-- @author rhs@mit.edu +-- @creation-date 2000-10-22 +-- @cvs-id $Id$ +-- /* This script removes from the database everything associated with our table. */ ---drop functions -drop function samplenote__new (varchar,varchar,timestamp,integer,varchar,integer); -drop function samplenote__delete (integer); -drop function samplenote__name (integer); +--drop package, which drops all functions created with define_function_args +select drop_package('samplenote'); + --drop permissions delete from acs_permissions where object_id in (select note_id from samplenote); @@ -234,28 +292,53 @@ (many lines omitted) done [service0@yourserver samplenote]$ - Now run the create script manually to add your tables and functions. + Run the create script manually to add your tables and functions. [service0@yourserver samplenote]$ cd sql/postgresql/ [service0@yourserver postgresql]$ psql -f samplenote-create.sql +psql:samplenote-table-create.sql:22: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'samplenote_pk' for table 'samplenote' +psql:samplenote-table-create.sql:22: NOTICE: CREATE TABLE will create implicit +trigger(s) for FOREIGN KEY check(s) CREATE +CREATE inline_0 ---------- 0 (1 row) DROP -psql:samplenote-create.sql:51: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'samplenote_pk' for table 'samplenote' -psql:samplenote-create.sql:51: NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s) + define_function_args +---------------------- + 1 +(1 row) + CREATE + define_function_args +---------------------- + 1 +(1 row) + CREATE + define_function_args +---------------------- + 1 +(1 row) + CREATE -CREATE [service0@yourserver postgresql]$ - If there are errors, use them to debug the sql file and try again. Once you get the same output as shown above, test the drop script: + If there are errors, use them to debug the sql file and try again. If there are errors in the database table creation, you may need to run the drop script to drop the table so that you can recreate it. The drop script will probably have errors since some of the things it's trying to drop may be missing. They can be ignored. + If there are errors creating the functions, you can re-run the function creation file directly after fixing it, because all of the functions are created with create or replace commands. This will also make it easier to fix mistakes within the functions that aren't apparent until the functions are used. And it will make upgrades easier. + Once you get the same output as shown above, test the drop script: [service0@yourserver postgresql]$ psql -f samplenote-drop.sql -DROP -DROP -DROP +psql:samplenote-drop.sql:13: NOTICE: DROP PACKAGE: samplenote +psql:samplenote-drop.sql:13: NOTICE: DROPPING FUNCTION: samplenote__delete +psql:samplenote-drop.sql:13: NOTICE: DROPPING FUNCTION: samplenote__name +psql:samplenote-drop.sql:13: NOTICE: DROPPING FUNCTION: samplenote__new +psql:samplenote-drop.sql:13: NOTICE: PACKAGE: samplenote: DROPPED + drop_package +-------------- + +(1 row) + DELETE 0 CREATE inline_0 @@ -264,8 +347,8 @@ (1 row) DROP -psql:samplenote-drop.sql:33: NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "acs_objects" -psql:samplenote-drop.sql:33: NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "acs_objects" +psql:samplenote-drop.sql:35: NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "acs_objects" +psql:samplenote-drop.sql:35: NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "acs_objects" DROP acs_object_type__drop_type ---------------------------- Index: openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-debug.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-debug.xml,v diff -u -r1.1.2.1 -r1.1.2.2 --- openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-debug.xml 30 Mar 2003 20:31:48 -0000 1.1.2.1 +++ openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-debug.xml 7 Apr 2003 16:45:17 -0000 1.1.2.2 @@ -19,7 +19,10 @@ database name. You can use C-(up arrow) and C-(down arrow) for command history. - + + Hint: "Parse error near *" usually means that an xql file + wasn't recognized, because the tcl file is choking on the *SQL* + placeholder that it falls back on. Watching the server log Index: openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-pages.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-pages.xml,v diff -u -r1.1.2.1 -r1.1.2.2 --- openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-pages.xml 30 Mar 2003 20:31:48 -0000 1.1.2.1 +++ openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-pages.xml 7 Apr 2003 16:45:17 -0000 1.1.2.2 @@ -18,14 +18,40 @@ [service0@yourserver samplenote]$ cd /web/service0/packages/samplenote/www [service0@yourserver www]$ emacs index.tcl - Paste this into the file. There are several things to + Paste this into the file. + ad_page_contract { + This is the main page for the package. It displays all of the Notes and provides links to edit them and to create new Notes. + + @author rhs@mit.edu + @creation-date 2000-10-23 + @cvs-id $Id$ + @param orderby indicates when the user clicks on a column to order by that \column + @return table_html preformatting html table constructed by querying the sam\plenotes table + +} { + {orderby:optional {title}} +} -properties { + table_html +} +# define the columns in the table +set table_def { + {title "Note"} + {body "Contents"} + {edit "" {} {<td><a href="note-edit?note_id=$note_id">Edit</a></td>}} +} + +# construct an html table from the samplenotes database table +set table_html [ad_table -Torderby $orderby notes_query { *SQL* } $table_def] + There are several things to note about the file: The page begins with an ad_page_contract function. This is where we declare the input and output variables and their types and restrictions. It's also where we document the - page, including descriptions of the parameters and return. + page, including descriptions of the parameters and return. + (More information about TCL + pages and page contracts) We have one input variable, @@ -65,32 +91,7 @@ - - ad_page_contract { - This is the main page for the package. It displays all of the Sample Notes\ and provides links to edit them and to create new Notes. - - @author rhs@mit.edu - @creation-date 2000-10-23 - @cvs-id $Id$ - @param orderby indicates when the user clicks on a column to order by that \column - @return table_html preformatting html table constructed by querying the sam\plenotes table - -} { - {orderby:optional {title}} -} -properties { - table_html -} -# define the columns in the table -set table_def { - {title "Note"} - {body "Contents"} - {edit "" {} {<td><a href="note-edit?note_id=$note_id">Edit</a></td>}} - {delete "" {} {<td><a href="note-delete?note_id=$note_id">Delete</a></td>}} -} - -# construct an html table from the samplenotes database table -set table_html [ad_table -Torderby $orderby notes_query { *SQL* } $table_def] - Now put the database query into a separate file. If the + Put the database query into a separate file. If the database query is exactly the same for Oracle and PostgreSQL, it can go into a file with the same name as the tcl file but an xql extension, e.g., index.xql. If @@ -117,7 +118,7 @@ </querytext> </fullquery> </queryset> - Now we create the user-visible page. + Create the user-visible page. [service0@yourserver www]$ emacs index.adp The first line indicates that this page should be rendered within the the master template, which defaults to /web/service0/www/default-master. The second line passes a title variable to the master template. The third line inserts the contents of the variable table_html. The last line is a link to a page we haven't created yet. <master> @@ -127,7 +128,10 @@ Add files to APM - Before we can test these files, we have to notify the package manager that they exist. (To be precise, the tcl and adp will work fine as-is, but the xql file will not be recognized until we tell the APM about it.). + Before we can test these files, we have to notify the + package manager that they exist. (More precisely, the tcl and + adp will work fine as-is, but the xql file will not be + recognized until we tell the APM about it.). Go to http://yourserver.test:8000/acs-admin/apm @@ -140,12 +144,22 @@ Click add checked files + On the list of files, on the + index.xql line, click + watch. Unlike adp and tcl + pages, xql pages get cached. (And new xql files don't get + loaded when they're added.) Watching an xql file causes the APM + to load the contents of the XQL into memory so that it can be + used, and to reload it whenever the file is changed. The + watch will last until the server is restarted. + + Now that the pages are in the APM, check to make sure that the self-documenting code is working. - Browse to http://yourserver:8000/api-doc/ + Browse to http://yourserver.test:8000/api-doc/ - Click # Notes (Sample Application) 0.1d + Click Notes 0.1d Click Content Pages @@ -155,30 +169,44 @@ Test the index page - Go to http://192.168.0.2:8000/samplenote/. You should see something like this: + Go to http://yourserver.test:8000/note/. You should see this: Sample Notes Your Workspace : Main Site : Sample Note No data found. +Add a note. + foo@yourserver.test Since our table is empty, it's a pretty boring page. So next we'll make it possible to add records. - If you get any other output, such as an error message, skip to . Note also that, while tcl and adp pages update automatically, xql pages get cached. So if you change an xql page, the change won't take effect unless you restart the server, reload the package via the APM, or put a watch on the file in the APM file list. With a watch, which lasts until the next service restart, the file will be updated each time it is changed on disk. + If you get any other output, such as an error message, skip to . Add the add/edit page - We'll create a single page to handle both adding and editing records. First, create the tcl: + We'll create a single page to handle both adding and + editing records. In this recursive approach, the same tcl + function can present a blank HTML form, present the same form + pre-loaded with an existing record, and handle the resulting + submission of either updated or new records. This recursive + approach reduces the total amount of code and files. First, + create the tcl: + [service0@yourserver www]$ emacs note-edit.tcl - The page takes a single, optional input parameter, note_id. If it's present, logic within ad_form will assume that we're editing an existing record. We check user_id with ad_maybe_redirect_for_registration, which will redirect to the login page (with an automatic return path to bring them back after login or registration) if the visitor isn't logged in. Then we call ad_form, specifying the primary key of the table, the fields we want to edit, and functions for insert and update. + Paste and save and edit: ad_page_contract { Simple add/edit form for samplenote. } { - note_id:optional + note_id:integer,optional } set user_id [ad_maybe_redirect_for_registration] +set title "Add a note" +if {[exists_and_not_null note_id]} { + set title "Edit a note" +} + ad_form -name note -form { note_id:key {title:text @@ -188,20 +216,37 @@ {label "Body"} } } -select_query_name note_query -new_data { -db_1row do_insert { *SQL* } +samplenote::new db_1row do_insert { *SQL* } } -edit_data { db_dml do_update { *SQL* } } -after_submit { ad_returnredirect "index" -ad_script_abort } + We use ad_form + to automate most of the work here. Ad_form is a wrapper for the + template + functions for creating HTML forms. These functions should + always be used for HTML forms; this promotes consistency and, + since all template functions use the same stylesheet system, makes it easy to change + the appearance of forms. + The page takes a single, optional input parameter, + note_id. If it's present, ad_form will assume that we're editing + an existing record, look up that record, and pre-populate the + form. We'll also check and change the page title if necessary. We check user_id with ad_maybe_redirect_for_registration, + which will redirect to the login page (with an automatic return + path to bring them back after login or registration) if the + visitor isn't logged in. Then we call ad_form, specifying the + primary key of the table, the fields we want to edit, and + functions for insert and update. Next, we create the database functions. [service0@yourserver www]$ emacs note-edit.xql <?xml version="1.0"?> <queryset> <fullquery name="do_insert"> <querytext> - select samplenote__new(:title, :body,null,:user_id,null,null) + select samplenote__new(null,:title, :body,null,:user_id,null,null) </querytext> </fullquery> <fullquery name="do_update"> @@ -221,68 +266,23 @@ </querytext> </fullquery> </queryset> - And now the user-visible page: + Create the user-visible page: [service0@yourserver www]$ emacs note-edit.adp <master> +<property name="title">@title@</property> +<property name="context">{@title@}</property> <formtemplate id="note"></formtemplate> + The property tags are passed to the master template, which + uses their values to set the page title and context bar + (breadcrumb trail). We use the same variable, + title, for both variables but + wrap it in curly brackets for context so that the spaces aren't + interpreted separators. The formtemplate tag outputs the form + html with the matching name. Go to the APM as before and scan for new files and add your new work. Then test all this by going to the package home page and adding and editing a few records. - A Deletion page - Now we need a way to delete records. We'll create a recursive confirmation page. - [service0@yourserver www]$ emacs note-delete.tcl - 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. The form calls the same page, but with hidden variables carrying both note_id and confirm_p. - ad_page_contract { - A page that gets confirmation and then delete notes. - - @author joel@aufrecht.org - @creation-date 2003-02-12 - @cvs-id $Id$ -} { - note_id:integer - confirm_p:optional -} - -set title "Delete Note" - -if {[exists_and_not_null confirm]} { - # if confirmed, call the database to delete the record - db_1row do_delete { *SQL* } - ad_returnredirect "index" -} else { - # if 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 -} - Now the database calls: - [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> -<h2>@title@</h2> -<formtemplate id="note-del-confirm"></formtemplate> -</form> - Now test it by adding the new files in the APM and then deleting a few samplenotes. - - Adding files to cvs Put your new work into source control. [service0@yourserver www]$ cvs add *.adp *.tcl *.xql @@ -291,9 +291,6 @@ cvs add: scheduling file `index.adp' for addition cvs add: scheduling file `index.tcl' for addition cvs add: scheduling file `index.xql' for addition -cvs add: scheduling file `note-delete.adp' for addition -cvs add: scheduling file `note-delete.tcl' for addition -cvs add: scheduling file `note-delete.xql' for addition cvs add: scheduling file `note-edit.adp' for addition cvs add: scheduling file `note-edit.tcl' for addition cvs add: scheduling file `note-edit.xql' for addition Index: openacs-4/packages/acs-core-docs/www/xml/install-guide/aolserver.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/install-guide/aolserver.xml,v diff -u -r1.6.2.3 -r1.6.2.4 --- openacs-4/packages/acs-core-docs/www/xml/install-guide/aolserver.xml 30 Mar 2003 05:43:44 -0000 1.6.2.3 +++ openacs-4/packages/acs-core-docs/www/xml/install-guide/aolserver.xml 7 Apr 2003 16:45:30 -0000 1.6.2.4 @@ -6,23 +6,23 @@ This page assumes you have downloaded aolserver to to -/tmp/aolserver3.3ad13-oacs1-beta-src.tar.gz. If not, +/tmp/aolserver3.3oacs1.tar.gz. If not, get it. It also assumes you are following the &version;-P or &version;-O Reference Platform installation, using Red Hat 8.0. Places where other systems are different are noted. As root, untar - aolserver3.3ad13-oacs1-beta-src.tar.gz + aolserver3.3oacs1.tar.gz into /usr/local/src. [root@yourserver root]# cd /usr/local/src -[root@yourserver src]# tar xzf /tmp/aolserver3.3ad13-oacs1-beta-src.tar.gz +[root@yourserver src]# tar xzf /tmp/aolserver3.3oacs1.tar.gz [root@yourserver src]# cd /usr/local/src -tar xzf /tmp/aolserver3.3ad13-oacs1-beta-src.tar.gz +tar xzf /tmp/aolserver3.3oacs1.tar.gz @@ -36,22 +36,20 @@ cd /usr/local/src/aolserver ./conf-clean - Put the name of the driver(s) that you want into - conf-db. This can be - postgresql, - oracle, or the word + If you are using Oracle, edit + conf-db and change + postgresql to + oracle, or to the word both if you want both drivers installed. - [root@yourserver aolserver]# echo "postgresql" > conf-db + conf-inst should contain the + location where AOLserver is to be installed. Overwrite the + tarball's default value with our default value, /usr/local/aolserver: + [root@yourserver aolserver]# echo "/usr/local/aolserver" > conf-inst [root@yourserver aolserver]# - conf-inst should contain the - location where AOLserver is to be installed. This defaults to - /usr/local/aolserver, so we - don't need to change it. - conf-make should contain the name of the GNU Make command on your system. It defaults to gmake. Verify that gmake is installed: @@ -68,23 +66,9 @@ [root@yourserver aolserver]# If you don't get similar results, including an equal or higher version number to 3.79.1, install gmake or check your aliases. - - If you're going to be installing the Postgresql driver, you'll - have to adjust the makefile first. This will hopefully be cleaned - up in future versions of this distribution. - - - [root@yourserver aolserver]# emacs pgdriver/makefile - - - Edit the lines containing PGLIB and PGINC so they look like this: - - - PGLIB=/usr/local/pgsql/lib -PGINC=/usr/local/pgsql/include - - Run the conf program, which compiles AOLserver and the default modules and installs them. - [root@yourserver aolserver]# ./conf + Set an environment variable that the nspostgres driver + Makefile needs to compile correctly and run conf, which compiles AOLserver and the default modules and installs them. + [root@yourserver aolserver]# export POSTGRES=/usr/local/pgsql; ./conf Building in /usr/local/aolserver with the following modules: aolserver @@ -101,7 +85,7 @@ Running gmake in nsrewrite/; output in log/nsrewrite.log Running gmake in nssha1/; output in log/nssha1.log Running gmake in nsxml/; output in log/nsxml.log -Running gmake in pgdriver/; output in log/pgdriver.log +Running gmake in nspostgres/; output in log/nspostgres.log Creating ... ================================================================== Done Building Sat Mar 8 10:31:35 PST 2003 Index: openacs-4/packages/acs-core-docs/www/xml/install-guide/recovery.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/install-guide/recovery.xml,v diff -u -r1.1.2.1 -r1.1.2.2 --- openacs-4/packages/acs-core-docs/www/xml/install-guide/recovery.xml 30 Mar 2003 05:56:18 -0000 1.1.2.1 +++ openacs-4/packages/acs-core-docs/www/xml/install-guide/recovery.xml 7 Apr 2003 16:45:30 -0000 1.1.2.2 @@ -1,6 +1,6 @@ - - Backup and Recovery - + + Backup and Recovery + by Don Baccus with additions by Joel Aufrecht @@ -77,7 +77,7 @@ supervise directory, which is unneccesary and has complicated permissions. Make sure that you are using the cron job to back up the database to a file in /web/service0/database-backup so that the tar command will include the database. [root@yourserver root]# su - service0 -[service0@yourserver service0]$ tar -cpsj --exclude /web/service0/etc/daemontools/supervise --file /tmp/service0-backup.tar.bz2 /web/service0/ --exclude /web/service0/etc/daemontools/supervise/ +[service0@yourserver service0]$ tar -cpsj --exclude /web/service0/etc/daemontools/supervise --file /tmp/service0-backup.tar.bz2 /web/service0/ tar: Removing leading `/' from member names [service0@yourserver service0]$ Index: openacs-4/packages/acs-core-docs/www/xml/install-guide/software.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/install-guide/software.xml,v diff -u -r1.1.2.1 -r1.1.2.2 --- openacs-4/packages/acs-core-docs/www/xml/install-guide/software.xml 30 Mar 2003 05:56:18 -0000 1.1.2.1 +++ openacs-4/packages/acs-core-docs/www/xml/install-guide/software.xml 7 Apr 2003 16:45:30 -0000 1.1.2.2 @@ -21,15 +21,15 @@ Reference Platform &version;-P (<ulink>tarball</ulink>, <ulink>ISO image</ulink>) Reference Platform A: OpenACS &version;, AOLserver - 3.3ad13-oacs1-beta, PostGreSQL 7.2.3, and all supporting + 3.3oacs1, PostGreSQL 7.2.3, and all supporting files. Also requires Red Hat 8.0. Reference Platform &version;-O (<ulink>tarball</ulink>, <ulink>ISO image</ulink>) Reference Platform B: OpenACS &version;, AOLserver - 3.3ad13-oacs1-beta, Oracle 8.1.7, and all supporting +3.3oacs1, Oracle 8.1.7, and all supporting files. Also requires Red Hat 8.0. Also requires Oracle - see for information on how to get Oracle. @@ -174,7 +174,7 @@ <ulink - url="http://uptime.openacs.org/aolserver-openacs/aolserver3.3ad13-oacs1-beta-src.tar.gz">AOLserver 3.3ad13-oacs1-beta</ulink>, REQUIRED + url="http://uptime.openacs.org/aolserver-openacs/aolserver3.3oacs1.tar.gz">AOLserver 3.3oacs1, REQUIRED Mat Kovach's source distribution of AOLserver, including all of the patches listed below. Index: openacs-4/packages/acs-core-docs/www/xml/kernel/tcl-doc.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/kernel/tcl-doc.xml,v diff -u -r1.3 -r1.3.2.1 --- openacs-4/packages/acs-core-docs/www/xml/kernel/tcl-doc.xml 10 Aug 2002 19:34:42 -0000 1.3 +++ openacs-4/packages/acs-core-docs/www/xml/kernel/tcl-doc.xml 7 Apr 2003 16:49:22 -0000 1.3.2.1 @@ -14,36 +14,9 @@ The Big Picture +We use functions to document Tcl files and a web-based user +interface for browsing the documentation: -In versions of the OpenACS prior to 3.4, the standard -place to document Tcl files (both Tcl pages and Tcl library files) was in -a comment at the top of the file: - - - - -# -# path from server home/filename -# -# Brief description of the file's purpose -# -# author's email address, file creation date -# -# $Id$ -# - - - -In addition, the inputs expected by a Tcl page (i.e., form variables) would -be enumerated in a call to ad_page_variables, in effect, -documenting the page's argument list. - - -The problem with these practices is that the documentation is only -accessible by reading the source file itself. For this reason, ACS 3.4 -introduces a new API for documenting Tcl files and, on top of that, a -web-based user interface for browsing the documentation: - ad_page_contract: Every Tcl page has a contract that explicitly defines what inputs the page @@ -89,7 +62,7 @@ with the documents API so that each script's contract will document precisely the set of properties available to graphical designers in templates. (Document API integration is subject to change, so we don't -decsribe it here yet; for now, you can just consider +desrribe it here yet; for now, you can just consider ad_page_contract a newer, better, documented ad_page_variables.)