Index: openacs-4/packages/q-wiki/README.md =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/README.md,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/README.md 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,70 @@ +Q-Wiki +======= + +For the latest updates to this readme file, see: http://openacs.org/xowiki/q-wiki + +The lastest version of the code is available at the development site: + http://github.com/tekbasse/q-wiki + +introduction +------------ + +Q-Wiki is an OpenACS wiki using a templating system. +It allows tcl procedures to be used in a web-based publishing environment. +It is not tied to vertical web applications, such as OpenACS ecommerce package. + +Q-Wiki is derived from OpenACS' ecommerce package. Administrators + have voiced interest in having some kind of strictly filtered + ACS developer support dynamics for user content. + +license +------- +Copyright (c) 2013 Benjamin Brink +po box 20, Marylhurst, OR 97036-0020 usa +email: kappa@dekka.com + +Q-Wiki is open source and published under the GNU General Public License, consistent with the OpenACS system: http://www.gnu.org/licenses/gpl.html +A local copy is available at q-wiki/www/doc/LICENSE.html + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +features +-------- + +Pages automatically have revisioning. + +Pages must be trashed before being deleted. Trashed pages can be untrashed. + +Trashed pages are not published. + +Users with create permission can also trash their own creations. + +No UI javascript is used, so technologies with limited UI can use it. + +Tcl procedures pass through two filters: +1. a list of glob expressions stating which procedures are allowed to be used +2. a list of specifically banned procedures + +A package parameter can switch the TCL/ADP rendering of content on or off. + +This web-app is easily modifiable for custom applications. +It consists of a single q-wiki tcl/adp page pair and + an extra unused "flags" field. + +This app is ready for web-based publishing SEO optimization. +Besides content, pages include comments, keywords, and page description fields. + + + + Index: openacs-4/packages/q-wiki/q-wiki.info =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/q-wiki.info,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/q-wiki.info 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,39 @@ + + + + + Q-Wiki + Q-Wikis + f + f + f + f + + + Benjamin Brink + OpenACS Community + A wiki and templating system + A wiki and templating system derived from the ecommerce product templating system. + 1 + GNU Gpl 2.0 or higher + GPL2 + + + + + + + + + + + + + + + + + + + + Index: openacs-4/packages/q-wiki/tcl/q-group-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/tcl/q-group-procs.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/tcl/q-group-procs.tcl 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,81 @@ +ad_library { + + q-wiki user collaboration and contribution procedures + @creation-date 11 Mar 2013 + @Copyright (c) 2013-5 Benjamin Brink + @license GNU General Public License 2, see project home or https://www.gnu.org/licenses/gpl-2.0.html + @project home: http://github.com/tekbasse/q-wiki + @address: po box 20, Marylhurst, OR 97036-0020 usa + @email: tekbasse@yahoo.com +} + +# contributors of a page or instance (by most recent contributions, or user last_name) +# most_recent_edit (by and time) +# revisions contributed by a user? --not necessary, use page revisions +# pages with contributions by a user (a user's most recent contributions) + +ad_proc -public qw_contributors { + {template_id ""} + {instance_id ""} +} { + Returns list of contributors of template_id or instance_id +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + if { $template_id ne "" } { + set rev_user_ids_list [db_list_of_lists qw_pg_contributor_user_ids { select user_id from qw_wiki_page where template_id = :template_id and instance_id =:instance_id order by last_modified desc } ] + } else { + set rev_user_ids_list [db_list_of_lists qw_contributor_user_ids { select user_id from qw_wiki_page where instance_id =:instance_id order by last_modified desc } ] + } + set user_id_list [list ] + foreach rev_user_id_list $rev_user_ids_list { + set user_id [lindex $rev_user_id_list 0] + if { [lsearch -exact $user_id_list $user_id] == -1 } { + lappend user_id_list $user_id + } + } + return $user_id_list +} + +ad_proc -public qw_most_recent_edit_stats { + {template_id ""} + {instance_id ""} +} { + Returns user_id, last_modified and page_id (revision) as list for most recent edit of template_id or instance_id +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + if { $template_id ne "" } { + set rev_exists_p [db_0or1row qw_most_recent_template_edits { select user_id, last_modified, id as page_id from qw_wiki_page where template_id = :template_id and instance_id = :instance_id order by last_modified desc limit 1 } ] + } else { + set rev_exists_p [db_0or1row qw_most_recent_instance_edits { select user_id, last_modified, id as page_id from qw_wiki_page where instance_id = :instance_id order by last_modified desc limit 1 } ] + } + if { $rev_exists_p } { + set stats_list [list $user_id $last_modified $page_id] + } else { + set stats_list [list ] + } + return $stats_list +} + +ad_proc -public qw_user_contributions { + {user_id ""} + {instance_id ""} +} { + Returns page_ids that user has contributed revisions (not necessarily current revisions) +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + if { $user_id eq "" } { + set user_id [ad_conn user_id] + } + set page_ids_list [db_list_of_lists qw_contributor_page_ids { select id from qw_wiki_page where instance_id =:instance_id order by last_modified desc } ] + + return $page_ids_list +} Index: openacs-4/packages/q-wiki/tcl/q-wiki-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/tcl/q-wiki-procs.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/tcl/q-wiki-procs.tcl 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,676 @@ +ad_library { + + API for q-wiki + @creation-date 17 Jul 2012 + @Copyright (c) 2012-5 Benjamin Brink + @license GNU General Public License 2, see project home or https://www.gnu.org/licenses/gpl-2.0.html + @project home: http://github.com/tekbasse/q-wiki + @address: po box 20, Marylhurst, OR 97036-0020 usa + @email: tekbasse@yahoo.com +} + +ad_proc -public qw_page_id_exists { + page_id + {instance_id ""} +} { + Returns 1 if page_id exists for instance_id, else returns 0 +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + + set page_exists_p [db_0or1row wiki_page_get_id {select name from qw_wiki_page where id = :page_id and instance_id = :instance_id } ] + return $page_exists_p +} + +ad_proc -public qw_change_page_id_for_url { + page_id_new + page_url + {instance_id ""} +} { + Changes the active revision (page_id) for page_url. Returns 1 if successful, otherwise 0. +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + set user_id [ad_conn user_id] + set write_p [permission::permission_p -party_id $user_id -object_id $instance_id -privilege write] + set success_p 0 + if { $write_p } { + # new page + set page_new_stats_list [qw_page_stats $page_id_new $instance_id] + set template_id_new [lindex $page_new_stats_list 5] + set trashed_p_new [lindex $page_new_stats_list 7] + set page_url_new [qw_page_url_from_id $page_id_new $instance_id] + # new and current page + if { $page_url_new ne "" && $page_url eq $page_url_new && !$trashed_p_new } { + db_dml wiki_change_revision { update qw_page_url_map + set page_id = :page_id_new where url = :page_url and instance_id = :instance_id } + db_dml wiki_change_revision_active { update qw_wiki_page + set last_modified = current_timestamp where id = :page_id_new and instance_id = :instance_id } + set success_p 1 + } + } + return $success_p +} + +# qw_page_rename start +ad_proc -public qw_page_rename { + page_url + page_name + {instance_id ""} +} { + Changes the url where the page is served from page_url to page_name. Returns 1 if successful, otherwise 0. +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + set user_id [ad_conn user_id] + set write_p [permission::permission_p -party_id $user_id -object_id $instance_id -privilege write] + set success_p 0 + if { $write_p && $page_url ne "" && $page_name ne "" } { + set page_urls_id [qw_page_id_from_url $page_url $instance_id] + set page_stats_list [qw_page_stats $page_urls_id $instance_id] + set template_id [lindex $page_stats_list 5] + # does page_name already exist? + set pn_page_id [qw_page_id_from_url $page_name $instance_id] + + if { $pn_page_id ne "" } { + set pn_stats_list [qw_page_stats $pn_page_id $instance_id] + set pn_template_id [lindex $pn_stats_list 5] + # just: + # mv the template_id of page_url revisions to page_name revisions template_id + db_dml wiki_name_change_template_id { update qw_wiki_page + set last_modified = current_timestamp, template_id =:pn_template_id, name =:page_name where template_id = :template_id and instance_id = :instance_id } + # get rid of the existing page_name entry + db_dml wiki_name_change_url_del { delete from qw_page_url_map + where url = :page_url and instance_id = :instance_id } + + } else { + # update qw_page_url_map.url qw_wiki_page.page_name to page_name for template_id, instance_id + db_dml wiki_name_change_pages { update qw_wiki_page + set last_modified = current_timestamp, name = :page_name where template_id = :template_id and instance_id = :instance_id } + db_dml wiki_name_change_url { update qw_page_url_map + set url = :page_name where url = :page_url and instance_id = :instance_id } + } + set success_p 1 + } + return $success_p +} + + +# +ad_proc -public qw_page_id_from_url { + page_url + {instance_id ""} +} { + Returns page_id if page_url exists for instance_id, else returns empty string. +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + set user_id [ad_conn user_id] + set write_p [permission::permission_p -party_id $user_id -object_id $instance_id -privilege write] + if { $write_p } { + # okay to return trashed pages + set page_exists_p [db_0or1row wiki_page_get_id_from_url {select page_id from qw_page_url_map + where url = :page_url and instance_id = :instance_id } ] + } else { + set page_exists_p [db_0or1row wiki_page_get_id_from_url {select page_id from qw_page_url_map + where url = :page_url and instance_id = :instance_id and not ( trashed = '1' ) } ] + } + if { !$page_exists_p } { + set page_id "" + } + return $page_id +} + +ad_proc -public qw_page_url_from_id { + page_id + {instance_id ""} +} { + Returns page_url if page_id exists for instance_id, even if page_id is not the active revision, else returns empty string. +} { + set page_url "" + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + set user_id [ad_conn user_id] + set write_p [permission::permission_p -party_id $user_id -object_id $instance_id -privilege write] + if { $write_p } { + # okay to return trashed pages + set page_exists_p [db_0or1row wiki_page_get_all_url_from_id { select url as page_url from qw_page_url_map + where page_id = :page_id and instance_id = :instance_id } ] + } else { + set page_exists_p [db_0or1row wiki_page_get_untrashed_url_from_id { select url as page_url from qw_page_url_map + where page_id = :page_id and instance_id = :instance_id and not ( trashed = '1' ) } ] + } + if { !$page_exists_p } { + set page_stat_list [qw_page_stats $page_id] + set template_id [lindex $page_stat_list 5] +# ns_log Notice "qw_page_url_from_id: page_id '$page_id' template_id '$template_id'" + if { $template_id ne "" } { + # get page_url from template_id + db_0or1row wiki_page_get_url_from_ids_template { select url as page_url from qw_page_url_map + where page_id in ( select id as page_id from qw_wiki_page + where instance_id = :instance_id and template_id = :template_id ) } + } + if { $page_url eq "" } { + # maybe page_id doesn't exist, but page_id is a template_id + db_0or1row wiki_page_get_url_from_template_id { select url as page_url from qw_page_url_map + where page_id in ( select id as page_id from qw_wiki_page + where instance_id = :instance_id and template_id = :page_id ) } + } + } + return $page_url +} + +ad_proc -public qw_page_url_id_from_template_id { + template_id + {instance_id ""} +} { + Returns page_id mapped to the url mapped to template_id, else returns empty string. +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + set page_id "" + db_0or1row wiki_page_get_url_from_template_id { select page_id from qw_page_url_map + where instance_id = :instance_id and page_id in ( select id as page_id from qw_wiki_page + where instance_id = :instance_id and template_id = :template_id ) } + return $page_id +} + + +ad_proc -public qw_page_from_url { + page_url + {instance_id ""} +} { + Returns page_id if page is published (untrashed) for instance_id, else returns empty string. +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + set page_exists_p [db_0or1row wiki_page_get_id_from_url2 {select page_id from qw_page_url_map + where url = :page_url and instance_id = :instance_id and not ( trashed = '1' ) } ] + if { !$page_exists_p } { + set page_id "" + } + return $page_id +} + +ad_proc -public qw_page_create { + url + name + title + content + keywords + description + comments + {template_id ""} + {flags ""} + {instance_id ""} + {user_id ""} +} { + Creates wiki page. returns page_id, or 0 if error. instance_id is usually package_id +} { + + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + if { $user_id eq "" } { + set user_id [ad_conn user_id] + set untrusted_user_id [ad_conn untrusted_user_id] + } + set return_page_id 0 + set create_p [permission::permission_p -party_id $user_id -object_id $instance_id -privilege create] + ns_log Notice "qw_page_create: create_p $create_p" + if { $create_p } { + set template_id "" + set trashed_p 0 + set page_url_exists_p [db_0or1row wiki_url_get_page_id {select page_id from qw_page_url_map where url = :url and instance_id = :instance_id } ] + if { $page_url_exists_p } { + set page_id_exists_p [db_0or1row wiki_url_get_id { select page_id from qw_page_url_map where page_id = :page_id and instance_id = :instance_id } ] + if { $page_id_exists_p } { + set page_id_stats_list [qw_page_stats $page_id $instance_id $user_id] + set template_id [lindex $page_id_stats_list 5] + } + } else { + set page_id_exists_p 0 + } + set page_id [db_nextval qw_page_id_seq] + if { $template_id eq "" } { + set template_id $page_id + } + db_transaction { + ns_log Notice "qw_page_create: wiki_page_create id '$page_id' template_id '$template_id' name '$name' instance_id '$instance_id' user_id '$user_id'" + db_dml wiki_page_create { insert into qw_wiki_page + (id,template_id,name,title,keywords,description,content,comments,instance_id,user_id,last_modified,created) + values (:page_id,:template_id,:name,:title,:keywords,:description,:content,:comments,:instance_id,:user_id,current_timestamp,current_timestamp) } + + # Add entry to qw_page_url_map if new page, otherwise update existing record. + # A new record is only when template_id = page_id + if { $page_id eq $template_id } { + ns_log Notice "qw_page_create: wiki_url_create url '$url' page_id '$page_id' trashed_p '$trashed_p' instance_id '$instance_id'" + db_dml wiki_page_url_create { insert into qw_page_url_map + ( url, page_id, trashed, instance_id ) + values ( :url, :page_id, :trashed_p, :instance_id ) } + } else { + ns_log Notice "qw_page_create: wiki_url_update url '$url' page_id '$page_id' trashed_p '$trashed_p' instance_id '$instance_id'" + db_dml wiki_page_url_update { update qw_page_url_map + set page_id = :page_id where url = :url and instance_id = :instance_id } + } + set return_page_id $page_id + + } on_error { + set return_page_id 0 + ns_log Error "qw_page_create: general psql error during db_dml for url $url" + } + } + return $return_page_id +} + +ad_proc -public qw_page_stats { + page_id + {instance_id ""} + {user_id ""} +} { + Returns page stats as a list: name, title, comments, keywords, description, template_id, flags, trashed, popularity, time last_modified, time created, user_id +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + if { $user_id eq "" } { + set user_id [ad_conn user_id] + set untrusted_user_id [ad_conn untrusted_user_id] + } + # check permissions + set read_p [permission::permission_p -party_id $user_id -object_id $instance_id -privilege read] + + if { $read_p } { + set return_list_of_lists [db_list_of_lists wiki_page_stats { select name, title, comments, keywords, description, template_id, flags, trashed, popularity, last_modified, created, user_id from qw_wiki_page where id = :page_id and instance_id = :instance_id } ] + # convert return_lists_of_lists to return_list + set return_list [lindex $return_list_of_lists 0] + # convert trash null/empty value to logical 0 + if { [llength $return_list] > 1 && [lindex $return_list 7] eq "" } { + set return_list [lreplace $return_list 7 7 0] + } + + } else { + set return_list [list ] + } + return $return_list +} + +ad_proc -public qw_pages { + {instance_id ""} + {user_id ""} + {template_id ""} +} { + Returns a list of q-wiki page_ids. If template_id is included, the results are scoped to pages with same template (aka revisions). + If user_id is included, the results are scoped to the user. If nothing found, returns and empty list. +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + if { $user_id eq "" } { + set party_id [ad_conn user_id] + set untrusted_user_id [ad_conn untrusted_user_id] + } else { + set party_id $user_id + } + set read_p [permission::permission_p -party_id $party_id -object_id $instance_id -privilege read] + + if { $read_p } { + if { $template_id eq "" } { + if { $user_id ne "" } { + # get a list of page_ids that are mapped to a url for instance_id and where the current revision was created by user_id + set return_list [db_list wiki_pages_user_list { select id from qw_wiki_page where instance_id = :instance_id and user_id = :user_id and id in ( select page_id from qw_page_url_map where instance_id = :instance_id ) order by last_modified desc } ] + } else { + # get a list of all page_ids mapped to a url for instance_id. + set return_list [db_list wiki_pages_list { select id as page_id from qw_wiki_page where id in ( select page_id from qw_page_url_map where instance_id = :instance_id ) order by last_modified desc } ] + } + } else { + # is the template_id valid? + set has_template [db_0or1row wiki_page_template { select template_id as db_template_id from qw_wiki_page where template_id= :template_id limit 1 } ] + if { $has_template && [info exists db_template_id] && $template_id > 0 } { + if { $user_id ne "" } { + # get a list of all page_ids of the revisions of page (template_id) that user_id created. + set return_list [db_list wiki_pages_t_u_list { select id from qw_wiki_page where instance_id = :instance_id and user_id = :user_id and template_id = :template_id order by last_modified desc } ] + } else { + # get a list of all page_ids of the revisions of page (template_id) + set return_list [db_list wiki_pages_list { select id from qw_wiki_page where instance_id = :instance_id and template_id = :template_id order by last_modified } ] + } + } else { + set return_list [list ] + } + } + } else { + set return_list [list ] + } + return $return_list +} + +ad_proc -public qw_page_read { + page_id + {instance_id ""} + {user_id ""} +} { + Returns page contents of page_id. Returns page as list of attribute values: name, title, keywords, description, template_id, flags, trashed, popularity, last_modified, created, user_id, content, comments +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + if { $user_id eq "" } { + set user_id [ad_conn user_id] + set untrusted_user_id [ad_conn untrusted_user_id] + } + set read_p [permission::permission_p -party_id $user_id -object_id $instance_id -privilege read] + set return_list [list ] + if { $read_p } { + set return_list_of_lists [db_list_of_lists wiki_page_get { select name, title, keywords, description, template_id, flags, trashed, popularity, last_modified, created, user_id, content, comments from qw_wiki_page where id = :page_id and instance_id = :instance_id } ] + # convert return_lists_of_lists to return_list + set return_list [lindex $return_list_of_lists 0] + # convert trash null/empty value to logical 0 + if { [llength $return_list] > 1 && [lindex $return_list 6] eq "" } { + set return_list [lreplace $return_list 6 6 0] + } + + } + return $return_list +} + +ad_proc -public qw_page_write { + name + title + content + keywords + description + comments + page_id + {template_id ""} + {flags ""} + {instance_id ""} + {user_id ""} +} { + Writes a new revision of an existing q-wiki page. page_id is an existing revision of template_id. returns the new page_id or a blank page_id if unsuccessful. +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + if { $user_id eq "" } { + set user_id [ad_conn user_id] + set untrusted_user_id [ad_conn untrusted_user_id] + } + set write_p [permission::permission_p -party_id $user_id -object_id $instance_id -privilege write] + set new_page_id "" + + if { $write_p } { + set page_exists_p [db_0or1row wiki_page_get_user_id {select user_id as creator_id from qw_wiki_page where id = :page_id } ] + if { $page_exists_p } { + set page_id_stats_list [qw_page_stats $page_id $instance_id $user_id] + set template_id [lindex $page_id_stats_list 5] + } + + if { $page_exists_p } { + set old_page_id $page_id + set url qw_page_url_from_id $old_page_id + set new_page_id [db_nextval qw_page_id_seq] + ns_log Notice "qw_page_write: wiki_page_create id '$page_id' template_id '$template_id' name '$name' instance_id '$instance_id' user_id '$user_id'" + db_transaction { + db_dml wiki_page_create { insert into qw_wiki_page + (id,template_id,name,title,keywords,description,content,comments,instance_id,user_id, last_modified, created) + values (:new_page_id,:template_id,:name,:title,:keywords,:description,:content,:comments,:instance_id,:user_id, current_timestamp, current_timestamp) } + ns_log Notice "qw_page_write: wiki_page_id_update page_id '$new_page_id' instance_id '$instance_id' old_page_id '$old_page_id'" + db_dml wiki_page_id_update { update qw_page_url_map + set page_id = :new_page_id where instance_id = :instance_id and url = :url } + } on_error { + set success_p 0 + ns_log Error "qw_page_write: general db error during db_dml" + } + } else { + set success_p 0 + ns_log Warning "qw_page_write: no page exists for page_id $page_id" + } + set success_p 1 + } else { + set success_p 0 + } + return $new_page_id +} + + +ad_proc -public qw_page_delete { + {page_id ""} + {template_id ""} + {instance_id ""} + {user_id ""} +} { + Deletes all revisions of template_id if not null, or if page_id not null, deletes page_id. + Returns 1 if deleted. Returns 0 if there were any issues. +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + if { $user_id eq "" } { + set user_id [ad_conn user_id] + } + set delete_p [permission::permission_p -party_id $user_id -object_id $instance_id -privilege delete] + set success_p 0 + set page_id_active_p 0 + ns_log Notice "qw_page_delete: delete_p '$delete_p' page_id '$page_id' template_id '$template_id'" + if { $delete_p } { + + if { $page_id ne "" } { + set template_id [lindex [qw_page_stats $page_id $instance_id] 5] + # delete a revision + db_dml wiki_page_delete { delete from qw_wiki_page + where id=:page_id and instance_id =:instance_id and trashed = '1' } + # is page_id the active revision for template_id? + set page_id_active_p [db_0or1row qw_url_from_page_id { select url from qw_page_url_map + where page_id = :page_id and instance_id = :instance_id } ] + } elseif { $template_id ne "" } { + # delete all revisions of template_id and the url_mapped to it + # get active page_id for reference later + set page_id [qw_page_url_id_from_template_id $template_id $instance_id] + # delete all revisions + db_dml wiki_template_delete { delete from qw_wiki_page + where template_id=:template_id and instance_id =:instance_id and trashed = '1' } + set page_id_active_p 1 + } + + } else { + + # a user can only delete their own creations + if { $page_id ne "" } { + set template_id [lindex [qw_page_stats $page_id $instance_id] 5] + # delete a revision + db_dml wiki_page_delete_u { delete from qw_wiki_page + where id=:page_id and instance_id =:instance_id and user_id=:user_id and trashed = '1' } + # is page_id the active revision for template_id? + set page_id_active_p [db_0or1row qw_url_from_page_id { select url from qw_page_url_map + where page_id = :page_id and instance_id = :instance_id } ] + set success_p 1 + } elseif { $template_id ne "" } { + # delete all revisions of template_id and the url_mapped to it + # get active page_id for reference later + set page_id [qw_page_url_id_from_template_id $template_id $instance_id] + # delete all revisions + db_dml wiki_template_delete_u { delete from qw_wiki_page + where template_id=:template_id and instance_id =:instance_id and user_id = :user_id and trashed = '1' } + set page_id_active_p 1 + } + + } + + if { $page_id_active_p } { + # change the page_id mapped to the url, or delete it if no alternates exist + # find the most recent untrashed revision + set new_untrashed_id_exists_p [db_0or1row qw_previous_page_id { select id as new_page_id from qw_wiki_page + where template_id = :template_id and instance_id = :instance_id and not ( trashed = '1') and not ( id = :page_id ) order by created desc limit 1 } ] + if { $new_untrashed_id_exists_p } { + # point to the most recent untrashed revision + db_dml wiki_page_id_update { update qw_page_url_map set page_id = :new_page_id + where instance_id = :instance_id and page_id = :page_id } + } else { + # point to the most recent trashed revision, and trash the mapped url status for consistency + set new_trashed_id_exists_p [db_0or1row qw_previous_page_id2 { select id as new_page_id from qw_wiki_page + where template_id = :template_id and instance_id = :instance_id and not ( id = :page_id ) order by created desc limit 1 } ] + if { $new_trashed_id_exists_p } { + db_dml wiki_page_id_update_trashed { update qw_page_url_map + set page_id = :new_page_id, trashed = '1' + where instance_id = :instance_id and page_id = :page_id } + } else { + # the revision being deleted is the last revision, delete the mapped url entry + set url [qw_page_url_from_id $template_id] + db_dml wiki_page_url_delete { delete from qw_page_url_map + where url =:url and instance_id =:instance_id } + } + } + } + return 1 +} + + + +ad_proc -public qw_page_trash { + {page_id ""} + {trash_p "1"} + {template_id ""} + {instance_id ""} + {user_id ""} +} { + Trashes/untrashes page_id or template_id (subject to permission check). + set trash_p to 1 (default) to trash page. Set trash_p to '0' to untrash. + Returns 1 if successful, otherwise returns 0 +} { + # page_id can be unpublished revision or the published revision, trashed or untrashed + set url "" + + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + if { $user_id eq "" } { + set user_id [ad_conn user_id] + set untrusted_user_id [ad_conn untrusted_user_id] + } + set write_p [permission::permission_p -party_id $user_id -object_id $instance_id -privilege write] + set page_id_active_p 0 + + # if write_p, don't need to scope to user_id == page_user_id + if { $write_p } { + + if { $page_id ne "" } { + # trash revision + set template_id [lindex [qw_page_stats $page_id $instance_id] 5] + set url [qw_page_url_from_id $template_id] + # wtr = write privilege trash revision + db_dml wiki_page_trash_wtr { update qw_wiki_page set trashed =:trash_p, last_modified = current_timestamp + where id=:page_id and instance_id =:instance_id } + # is page_id associated with a url ie published? + set page_id_active_p [db_0or1row qw_url_from_page_id { select url from qw_page_url_map + where page_id = :page_id and instance_id = :instance_id } ] + + } elseif { $template_id ne "" } { + set url [qw_page_url_from_id $template_id] + # template_id affects all revisions. + # page_id is blank. set page_id to page url's page_id + set page_id [qw_page_id_from_url $url] + # wtp = write privilege trash page ie bulk trashing revisions + db_dml wiki_page_trash_wtp { update qw_wiki_page set trashed =:trash_p, last_modified = current_timestamp + where template_id=:template_id and instance_id =:instance_id } + set page_id_trash_p 1 + } + + } else { + + # a user can only un/trash their own entries + # the user_id scope is applied in the query + if { $page_id ne "" } { + # trash one revision + set template_id [lindex [qw_page_stats $page_id $instance_id] 5] + set url [qw_page_url_from_id $template_id] + # utr = user privilege trash revision + db_dml wiki_page_trash_utr { update qw_wiki_page set trashed =:trash_p, last_modified = current_timestamp + where id=:page_id and instance_id =:instance_id and user_id=:user_id } + # is page_id associated with a url ie published? + set page_id_active_p [db_0or1row qw_url_from_page_id { select url from qw_page_url_map + where page_id = :page_id and instance_id = :instance_id } ] + + } elseif { $template_id ne "" 0 } { + # trash for all revisions possible for same template_id + set url [qw_page_url_from_id $template_id] + set page_id [qw_page_id_from_url $url] + + # utp = user privilege trash page (as many revisions as they created) + db_dml wiki_page_trash_utp { update qw_wiki_page set trashed =:trash_p, last_modified = current_timestamp + where template_id=:template_id and instance_id =:instance_id and user_id=:user_id } + set page_id_active_p 1 + } + + } + +# ns_log Notice "qw_page_trash: page_id_active_p '$page_id_active_p' trash_p '$trash_p'" + + if { $page_id_active_p && $trash_p } { + # need to choose an alternate page_id if available, since this page_id is trashed + ns_log Notice "qw_page_trash(529). need to change page_id" + # page_id is old_page_id + # select most recent, available new_page_id + set new_page_id_exists [db_0or1row qw_available_page_id { select id as new_page_id from qw_wiki_page + where template_id = :template_id and instance_id = :instance_id and not (trashed = '1') and not ( id =:page_id ) order by created desc limit 1 } ] + if { $new_page_id_exists } { + ns_log Notice "qw_page_trash(583): new_page_id $new_page_id" + # point to the most recent untrashed revision + if { $page_id ne $new_page_id } { + ns_log Notice "qw_page_trash: changing active page_id from $page_id to $new_page_id" + db_dml wiki_page_url_id_update { update qw_page_url_map set page_id = :new_page_id + where instance_id = :instance_id and page_id = :page_id } + # we avoided having to update trashed status for url_map + set $page_id_active_p 0 + } + } + } + + if { !$trash_p } { + # if page_id of url_map is trashed, untrash it. + + db_0or1row qw_page_url_trashed_p { select trashed as url_trashed_p from qw_page_url_map + where url = :url and instance_id = :instance_id } + set url_trashed_p_exists_p [info exists url_trashed_p] + if { !$url_trashed_p_exists_p || ( $url_trashed_p_exists_p && $url_trashed_p ne "1" ) } { + set url_trashed_p 0 + } + if { $url_trashed_p } { + set url_page_id [qw_page_id_from_url $url $instance_id] + # ns_log Notice "qw_page_trash(603): updating trash and page_id '$url_page_id' for url '$url' to page_id '$page_id' untrashed" + db_dml wiki_page_url_map_update2 { update qw_page_url_map set page_id = :page_id, trashed = :trash_p + where instance_id = :instance_id and page_id = :url_page_id } + set page_id_active_p 0 + } + # untrash the url + } + + # if page_id active or untrashing page_id and page_url trashed + if { $page_id_active_p } { + # published page_id is affected, set mapped page trash also. + ns_log Notice "qw_page_trash: updating qw_page_url_map page_id '$page_id' instance_id '$instance_id'" + db_dml wiki_page_url_trash_update { update qw_page_url_map set trashed = :trash_p + where page_id = :page_id and instance_id = :instance_id } + } + return 1 +} Index: openacs-4/packages/q-wiki/tcl/template-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/tcl/template-procs.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/tcl/template-procs.tcl 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,112 @@ +ad_library { + + API for q-wiki templates + @creation-date 17 Jul 2012 + @Copyright (c) 2012-5 Benjamin Brink + @license GNU General Public License 3, see project home or http://www.gnu.org/licenses/gpl-3.0.en.html + @project home: http://github.com/tekbasse/q-wiki + @address: po box 20, Marylhurst, OR 97036-0020 usa + @email: tekbasse@yahoo.com +} + +ad_proc -public qw_template_custom_read { + report_ref + default_fields + {instance_id ""} + {user_id ""} +} { + This procedure returns a custom order for use with templates, where a template contains ordered references, + $1 .. $9. By supplying a custom order of fields for a report, admins (and possibly users) can control the + order of fields displayed in a table or responsive list substitute for an html TABLE. + The default is to return default_fields in the sequence passed to this proc. Limit length of space separated list: 320 characters. +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + set custom_fields $default_fields + set report_ref [string range $report_ref 0 79] + if { [qf_is_natural_number $user_id] } { + set possible_lists [db_list_of_lists qw_template_custom_map_read_w_u "select custom_order, user_id from qw_template_custom_map where instance_id =:instance_id and report_ref=:report_ref and default_fields =:default_fields and ( user_id =:user_id or user_id is null)"] + # There should be only 2 possibilities max + if { [llength $possible_lists > 1 ] } { + # choose the one with the user_id + foreach row_list $possible_lists { + if { [lindex $row_list 1] eq $user_id } { + set custom_fields [lindex $row_list 0] + } + } + } else { + set custom_fields [lindex $possible_lists 0] + } + } else { + # defaults to use custom_fields from above if no rows found + db_0or1row qw_template_custom_map_read "select custom_order as custom_fields from qw_template_custom_map where instance_id =:instance_id and report_ref=:report_ref and default_fields =:default_fields and user_id is null" + } + return $custom_fields +} + +ad_proc -public qw_template_custom_set { + report_ref + default_fields + custom_fields + {instance_id ""} + {user_id ""} +} { + This procedure sets a custom order for use with templates, where a template contains ordered references, + $1 .. $9. By supplying a custom order of fields for a report, admins (and possibly users) can control the + order of fields displayed in a table or responsive list substitute for an html TABLE. + Limit length of space separated list: 320 characters. +} { + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + set success_p 1 + # get current custom (if any) to see if a write is necessary + set custom_fields_old [qw_template_custom_read $report_ref $default_fields $instance_id $user_id] + if { $custom_fields_old ne $custom_fields } { + # update or create it + set report_ref [string range $report_ref 0 79] + if { $user_id eq "" } { + # set for all cases + db_0or1row qw_template_custom_map_all_ck "select custom_order as custom_order_old2 from qw_template_custom_map where instance_id =:instance_id and report_ref=:report_ref and default_fields =:default_fields and user_id is null" + if { [info exists custom_order_old2] } { + # record exists. + if { $custom_order_old2 ne $custom_fields } { + # update record + db_dml { update qw_template_custom_map + set custom_order =:custom_fields where instance_id=:instance_id and report_ref=:report_ref and default_fields=:default_fields and user_id is null + } + } + } else { + # create record + db_dml { insert into qw_template_custom_map + (custom_fields,instance_id,report_ref,default_fields) + values (:custom_order,:instance_id,:report_ref,:default_fields) + } + } + } elseif { [qf_is_natural_number $user_id] } { + # set for this user + db_0or1row qw_template_custom_map_all_ck "select custom_order as custom_order_old2 from qw_template_custom_map where instance_id =:instance_id and report_ref=:report_ref and default_fields =:default_fields and user_id =:user_id" + if { [info exists custom_order_old2] } { + # record exists. + if { $custom_order_old2 ne $custom_fields } { + # update record + db_dml { update qw_template_custom_map + set custom_order =:custom_fields where instance_id=:instance_id and report_ref=:report_ref and default_fields=:default_fields and user_id =:user_id + } + } + } else { + # create record + db_dml { insert into qw_template_custom_map + (custom_fields,instance_id,report_ref,default_fields,:user_id) + values (:custom_order,:instance_id,:report_ref,:default_fields,:user_id) + } + } + } else { + set success_p 0 + } + } + return $success_p +} Index: openacs-4/packages/q-wiki/www/index.vuh =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/www/index.vuh,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/www/index.vuh 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,47 @@ +# q-wiki/www/index.vuh +# part of Q-Wiki package +# requires OpenACS + +# index.vuh allows q-wiki to integrate with other services. +# For robustness, rename q-wiki.tcl/q-wiki.adp to index.vuh to bypass having to repost data +set conn_path_url [ad_conn path_info] + +array set input_array [list \ + url ""\ + page_id ""\ + page_name ""\ + page_title ""\ + page_contents ""\ + keywords ""\ + description ""\ + page_comments ""\ + page_template_id ""\ + page_flags ""\ + page_contents_default ""\ + submit "" \ + reset "" \ + mode "v" \ + next_mode "" \ + url_referring ""\ + ] +set query_key_list [array names input_array] + +set form_posted [qf_get_inputs_as_array input_array] +set input_array(url) $conn_path_url +set input_array(url_referring) "index.vuh" +# re-post data to new location +foreach query_key $query_key_list { + rp_form_put $query_key [ad_urlencode $input_array(${query_key})] + if { $query_key eq "url" } { + set package_id [ad_conn package_id] + if { $input_array(url) eq "" && [parameter::get -package_id $package_id -parameter IndexIsList -default 0] } { + set input_array(url) "index" + set input_array(mode) "l" + } + ns_log Notice "q-wiki/www/index.vuh: url $input_array(url)" + } +} +rp_internal_redirect /packages/q-wiki/www/q-wiki +ad_script_abort + + Index: openacs-4/packages/q-wiki/www/q-wiki.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/www/q-wiki.adp,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/www/q-wiki.adp 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,36 @@ + + @title@ + @title@ + @context;noquote@ + + + +
@menu_html;noquote@
+
+

@title@

+ +
    + @user_message_html;noquote@ +
+
+ + + @form_html;noquote@ + + + +

#acs-admin.Pages#

+ @page_stats_html;noquote@ +
+ + +

#acs-kernel.member_state_Deleted#

+ @page_trashed_html;noquote@ +
+ + + @page_main_code_html;noquote@ + + + + Index: openacs-4/packages/q-wiki/www/q-wiki.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/www/q-wiki.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/www/q-wiki.tcl 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,1002 @@ +# q-wiki/q-wiki.tcl +# part of the Q-Wiki package +# depends on OpenACS website toolkit at OpenACS.org +# copyrigh t +# released under GPL license +# this page split into MVC components: +# inputs/observations (controller), actions (model), and outputs/reports (view) sections + +## For consistency, user_id can only make modifications if they have create_p permissions. +## User_id is not enough, as there would be issues with choosing active revisions +## so, user_id revsion changes are moderated. ie user_id can create a revision, but it takes write_p user to make revision active. + + +# INPUTS / CONTROLLER + +# set defaults +# template_id is first page_id, subsequent revisions have same template_id, but new page_id +# flags are blank -- an unused db column / page attribute for extending the app for use cases +# url has to be a given (not validated), since this page may be fed $url via an index.vuh + +set title "Q-Wiki" +set icons_path1 "/resources/acs-subsite/" +set icons_path2 "/resources/ajaxhelper/icons/" +set delete_icon_url [file join $icons_path2 delete.png] +set trash_icon_url [file join $icons_path2 page_delete.png] +set untrash_icon_url [file join $icons_path2 page_add.png] +set radio_checked_url [file join $icons_path1 radiochecked.gif] +set radio_unchecked_url [file join $icons_path1 radio.gif] +set redirect_before_v_p 0 + +set package_id [ad_conn package_id] +set user_id [ad_conn user_id] +set read_p [permission::permission_p -party_id $user_id -object_id $package_id -privilege read] +set create_p [permission::permission_p -party_id $user_id -object_id $package_id -privilege create] +set write_p [permission::permission_p -party_id $user_id -object_id $package_id -privilege write] +set admin_p [permission::permission_p -party_id $user_id -object_id $package_id -privilege admin] +set delete_p [permission::permission_p -party_id $user_id -object_id $package_id -privilege delete] + +array set input_array [list \ + url ""\ + page_id ""\ + page_name ""\ + page_title ""\ + page_contents ""\ + keywords ""\ + description ""\ + page_comments ""\ + page_template_id ""\ + page_flags ""\ + page_contents_default ""\ + submit "" \ + reset "" \ + mode "v" \ + next_mode "" \ + url_referring "" \ + ] + +set user_message_list [list ] +set title $input_array(page_title) + +# get previous form inputs if they exist +set form_posted [qf_get_inputs_as_array input_array2] +if { $form_posted && ( $input_array2(mode) eq "w" || $input_array2(mode) eq "d" ) } { + # do this again for hash_check to avoid irreversable cases. + array unset input_array2 + set form_posted [qf_get_inputs_as_array input_array hash_check 1] +} else { + array set input_array [array get input_array2] +} +set page_id $input_array(page_id) +set page_template_id $input_array(page_template_id) + +set page_name $input_array(page_name) +set page_title $input_array(page_title) +set page_flags $input_array(page_flags) +set keywords $input_array(keywords) +set description $input_array(description) +set page_comments $input_array(page_comments) +set page_contents $input_array(page_contents) +set mode $input_array(mode) +set next_mode $input_array(next_mode) + + +# Is this a redirect from index.vuh ? +set file_name [file tail [ad_conn file]] +if { [ns_urldecode $input_array(url_referring)] eq "index.vuh" && $file_name eq "q-wiki.adp" } { + # To do, when write_p == 1: index.vuh value should be replaced with a session continuity key passed via db. + + # If url is internal_redirecting from index.vuh, url should be same as: + # set url [ad_conn path_info] + + # url_de-encode values + set url $input_array(url) + set page_name [ns_urldecode $page_name] + set page_title [ns_urldecode $page_title] + set page_flags [ns_urldecode $page_flags] + set keywords [ns_urldecode $keywords] + set description [ns_urldecode $description] + set page_comments [ns_urldecode $page_comments] + set page_contents [ns_urldecode $page_contents] + +} elseif { $file_name eq "index.vuh" } { + # is this code executing inside index.vuh? + set url [ad_conn path_info] + ns_log Notice "q-wiki.tcl(29): file_name ${file_name}. Setting url to $url" +} elseif { !$form_posted && $input_array(url_referring) eq "" } { + # this test is for cases where hash_check is required for form posts + # but no user form has been posted, default values still need to be passed. + set url [ad_conn path_info] + set file_name $url +} else { + # A serious assumption has broken. + ns_log Warning "q-wiki.tcl(75): quit with referr_url and file_name out of boundary. Check log for request details." + ns_returnnotfound + # rp_internal_redirect /www/global/404.adp + ad_script_abort +} + +if { $url eq "" || $url eq "/" } { + set url "index" +} + + +if { $write_p } { + set page_id_from_url [qw_page_id_from_url $url $package_id] +} else { + # user can only edit or see it if it is published (not trashed) + set page_id_from_url [qw_page_from_url $url $package_id] +} + + +if { $page_id_from_url ne "" && ![qf_is_natural_number $page_id_from_url] } { + ns_log Notice "q-wiki.tcl(62): page_id_from_url '$page_id_from_url'" +} +ns_log Notice "q-wiki.tcl(63): mode $mode next_mode $next_mode" +# Modes are views, or one of these compound action/views + # d delete (d x) then view as before (where x = l, r or v) + # t trash (d x) then view as before (where x = l, r or v) + # w write (d x) , then view page_id (v) + +# Actions + # d = delete template_id or page_id + # t = trash template_id or page_id + # w = write page_id,template_id, make new page_id for template_id + # a = make page_id the active revision for template_id +# Views + # e = edit page_url, presents defaults (new) if page doesn't exist + # v = view page_url + # l = list pages of instance + # r = view/edit page_url revisions + # default = 404 return + + # url has to come from form in order to pass info via index.vuh + # set conn_package_url [ad_conn package_url] + # set url [string range $url [string length $conn_package_url] end] + # get page_id from url, if any + +if { $form_posted } { + if { [info exists input_array(x) ] } { + unset input_array(x) + } + if { [info exists input_array(y) ] } { + unset input_array(y) + } + if { ![qf_is_natural_number $page_id] } { + set page_id "" + } + + set validated_p 0 + # validate input + # cleanse data, verify values for consistency + # determine input completeness + + + if { $page_id_from_url ne "" } { + # page exists + + + set page_stats_from_url_list [qw_page_stats $page_id_from_url $package_id $user_id] + set page_template_id_from_url [lindex $page_stats_from_url_list 5] + ns_log Notice "q-wiki.tcl(106): page_id_from_url '$page_id_from_url' page_template_id_from_url '$page_template_id_from_url'" + + # page_template_id and page_id gets checked against db for added security + # check for form/db descrepencies + set page_stats_from_form_list [qw_page_stats $page_id] + set page_template_id_from_form_pid [lindex $page_stats_from_form_list 5] + + # if mode is e etc, allow edit of page_id in set of page_id_from_url revisions: + # verify template_id from page_id and from url are consistent. + if { $page_id ne "" && [qf_is_natural_number $page_template_id_from_url ] && $page_template_id_from_url ne $page_template_id_from_form_pid } { + ns_log Notice "q-wiki/q-wiki.tcl: template_ids don't match. page_id '$page_id' page_id_from_url '$page_id_from_url', page_template_id_from_url '$page_template_id_from_url' page_template_id_from_form_pid '$page_template_id_from_form_pid'" + set page_id $page_id_from_url + set mode "" + set next_mode "" + lappend user_message_list "#q-wiki.internal_processing_error# #q-wiki.Try_again_or_report_to_admin#" + util_user_message -message [lindex $user_message_list end] + } + if { $page_template_id ne "" && [qf_is_natural_number $page_template_id ] && $page_template_id_from_url ne $page_template_id } { + ns_log Notice "q-wiki/q-wiki.tcl: template_ids don't match. page_template_id '$page_template_id' page_id_from_url '$page_id_from_url', page_template_id_from_url '$page_template_id_from_url'" + set page_template_id $page_template_id_from_url + set mode "" + set next_mode "" + lappend user_message_list "#q-wiki.internal_processing_error# #q-wiki.Try_again_or_report_to_admin#" + util_user_message -message [lindex $user_message_list end] + } + + # A blank referrer means a direct request + # otherwise make sure referrer is from same domain when editing + set referrer_url [get_referrer] + + + ns_log Notice "q-wiki.tcl(124): mode $mode next_mode $next_mode" + # get info to pass back to write proc + + # This is a place to enforce application specific permissions. + # If package parameter says each template_id is an object_id, + # check user_id against object_id, otherwise check against package_id + # However, original_page_creation_user_id is in the db, so that instance specific + # user permissions can be supported. + # set original_user_id \[lindex $page_stats_list_of_template_id 11\] + + } else { + # page does not exist + if { $write_p && $mode ne "l" && $mode ne "w" } { + # present an edit/new page + set mode "e" + set next_mode "" + set validated_p 1 + } + } + # else should default to 404 at switch in View section. + + # validate input values for specific modes + # failovers for permissions follow reverse order (skipping ok): admin_p delete_p write_p create_p read_p + # possibilities are: d, t, w, e, v, l, r, "" where "" is invalid input or unreconcilable error condition. + # options include d, l, r, t, e, "", w, v + set http_header_method [ad_conn method] + ns_log Notice "q-wiki.tcl(141): initial mode $mode, next_mode $next_mode, http_header_method ${http_header_method}" + if { ( $next_mode eq "v" || $next_mode eq "l" ) && [string match -nocase GET $http_header_method] } { + # redirect when viewing, to clean the url + ns_log Notice "q-wiki.tcl(223): Setting redirect_before_v_p " + set redirect_before_v_p 1 + } + if { $mode eq "d" } { + if { $delete_p } { + ns_log Notice "q-wiki.tcl validated for d" + set validated_p 1 + } elseif { $read_p } { + set mode "l" + set next_mode "" + } else { + set mode "" + set next_mode "" + } + } + ns_log Notice "q-wiki.tcl(157): mode $mode next_mode $next_mode" + if { $mode eq "w" } { + if { $write_p } { + set validated_p 1 + } elseif { $read_p } { + # give the user a chance to save their changes elsewhere instead of erasing the input + set mode "e" + } else { + set mode "" + set next_mode "" + } + } + ns_log Notice "q-wiki.tcl(169): mode $mode next_mode $next_mode" + if { $mode eq "r" || $mode eq "a" } { + if { $write_p } { + if { [qf_is_natural_number $page_template_id_from_url ] } { + set validated_p 1 + ns_log Notice "q-wiki.tcl validated for $mode" + } elseif { $read_p } { + # This is a 404 return, but we list pages for more convenient UI + lappend user_message_list "#q-wiki.Page_not_found# #q-wiki.Showing_a_list_of_pages#" + util_user_message -message [lindex $user_message_list end] + set mode "l" + } + } else { + set mode "" + set next_mode "" + } + } + ns_log Notice "q-wiki.tcl(185): mode $mode next_mode $next_mode" + if { $mode eq "t" } { + if { ( $write_p || $user_id > 0 ) && ([qw_page_id_exists $page_id $package_id] || [qw_page_id_exists $page_id_from_url $package_id] ) } { + # complete validation occurs while trashing. + set validated_p 1 + ns_log Notice "q-wiki.tcl validated for t" + } elseif { $read_p } { + set mode "l" + } else { + set mode "" + } + } + + if { $page_id_from_url eq "" && $write_p && $mode eq "" && $next_mode eq "" } { + # page is blank + # switch to edit mode automatically for users with write_p + set mode "e" + } + + ns_log Notice "q-wiki.tcl(197): mode $mode next_mode $next_mode" + if { $mode eq "e" } { + # validate for new and existing pages. + # For new pages, template_id will be blank (template_exists_p == 0) + # For revisions, page_id will be blank. + set template_exists_p [qw_page_id_exists $page_template_id] + if { !$template_exists_p } { + set page_template_id "" + } + if { $write_p || ( $create_p && !$template_exists_p ) } { + + # page_title cannot be blank + if { $page_title eq "" && $page_template_id eq "" } { + set page_title "[clock format [clock seconds] -format %Y%m%d-%X]" + } elseif { $page_title eq "" } { + set page_title "${page_template_id}" + } else { + set page_title_length [parameter::get -package_id $package_id -parameter PageTitleLen -default 80] + incr page_title_length -1 + set page_title [string range $page_title 0 $page_title_length] + } + + if { $page_template_id eq "" && $page_name ne "" } { + # this is a new page + set url [ad_urlencode $page_name] + set page_id "" + } elseif { $page_template_id eq "" } { + if { [regexp -nocase -- {[^a-z0-9\%\_\-\.]} $url] } { + # url contains unencoded characters + set url [ad_urlencode $url] + set page_id "" + } + + # Want to enforce unchangeable urls for pages? + # If so, set url from db for template_id here. + } + ns_log Notice "q-wiki.tcl(226): url $url" + # page_name is pretty version of url, cannot be blank + if { $page_name eq "" } { + set page_name $url + } else { + set page_name_length [parameter::get -package_id $package_id -parameter PageNameLen -default 40] + incr page_name_length -1 + set page_name [string range $page_name 0 $page_name_length] + } + set validated_p 1 + ns_log Notice "q-wiki.tcl validated for $mode" + } elseif { $read_p && $template_exists_p } { + set mode v + set next_mode "" + } else { + set mode "" + set next_mode "" + } + } + ns_log Notice "q-wiki.tcl(252): mode $mode next_mode $next_mode" + if { $mode eq "l" } { + if { $read_p } { + set validated_p 1 + ns_log Notice "q-wiki.tcl validated for l" + } else { + set mode "" + set next_mode "" + } + } + ns_log Notice "q-wiki.tcl(262): mode $mode next_mode $next_mode" + if { $mode eq "v" } { + if { $read_p } { + # url vetted previously + set validated_p 1 + if { $page_id_from_url ne "" } { + # page exists + } else { + set mode "l" + ns_log Notice "q-wiki.tcl(405): mode = $mode ie. list of pages, index" + } + } else { + set mode "" + set next_mode "" + } + } + + # ACTIONS, PROCESSES / MODEL + ns_log Notice "q-wiki.tcl(268): mode $mode next_mode $next_mode validated $validated_p" + if { $validated_p } { + ns_log Notice "q-wiki.tcl ACTION mode $mode validated_p 1" + # execute process using validated input + # IF is used instead of SWITCH, so multiple sub-modes can be processed in a single mode. + if { $mode eq "d" } { + # delete.... removes context + ns_log Notice "q-wiki.tcl mode = delete" + if { $delete_p } { + qw_page_delete $page_id $page_template_id $package_id $user_id +# qw_page_delete $page_id $page_template_id_from_url $package_id $user_id + } + set mode $next_mode + set next_mode "" + } + ns_log Notice "q-wiki.tcl(358): mode $mode" + if { $mode eq "a" } { + # change active revision of page_template_id_from_url to page_id + if { $write_p } { + if { [qw_change_page_id_for_url $page_id $url $package_id] } { + set mode $next_mode + set page_id_from_url $page_id + } else { + lappend user_message_list "#q-wiki.Revision_could_not_be_activated# #q-wiki.Try_again_or_report_to_admin#" + util_user_message -message [lindex $user_message_list end] + set mode "r" + } + } + set next_mode "" + } + ns_log Notice "q-wiki.tcl(344): mode $mode" + if { $mode eq "t" } { + # toggle trash + ns_log Notice "q-wiki.tcl mode = trash" + # which page to trash page_id or page_id_from_url? + if { $page_id ne "" } { + set page_id_stats [qw_page_stats $page_id] + set trashed_p [lindex $page_id_stats 7] + set page_user_id [lindex $page_id_stats 11] + } elseif { $page_template_id ne "" } { + set page_id_stats [qw_page_stats $page_id_from_url] + set trashed_p [lindex $page_id_stats 7] + set page_user_id [lindex $page_id_stats 11] + } +# set template_id \[lindex $page_id_stats 5\] + set trash_done_p 0 + if { $write_p || $page_user_id eq $user_id } { + if { $trashed_p } { + set trash "0" + } else { + set trash "1" + } + ns_log Notice "q-wiki.tcl(419): qw_page_trash page_id $page_id trash_p $trash templat_id $page_template_id" + set trash_done_p [qw_page_trash $page_id $trash $page_template_id] + set mode $next_mode + } + if { !$trash_done_p } { + lappend user_message_list "#q-wiki.Item_could_not_be_trashed# #q-wiki.You_don_t_have_permission#" + util_user_message -message [lindex $user_message_list end] + } + set next_mode "" + # update the page_id + set page_id_from_url [qw_page_id_from_url $url $package_id] + if { $page_id_from_url ne "" && $mode eq "" } { + set mode "v" + } + } + ns_log Notice "q-wiki.tcl(374): mode $mode" + if { $mode eq "w" } { + if { $write_p } { + ns_log Notice "q-wiki.tcl permission to write the write.." + set page_contents_quoted $page_contents + set page_contents [ad_unquotehtml $page_contents] + set allow_adp_tcl_p [parameter::get -package_id $package_id -parameter AllowADPTCL -default 0] + set flagged_list [list ] + + if { $allow_adp_tcl_p } { + ns_log Notice "q-wiki.tcl(311): adp tags allowed. Fine grain filtering.." + # filter page_contents for allowed and banned procs in adp tags + set banned_proc_list [split [parameter::get -package_id $package_id -parameter BannedProc]] + set allowed_proc_list [split [parameter::get -package_id $package_id -parameter AllowedProc]] + + set code_block_list [qf_get_contents_from_tags_list "<%" "%>" $page_contents] + foreach code_block $code_block_list { + # split into lines + set code_segments_list [split $code_block \n\r] + foreach code_segment $code_segments_list { + # see filters in accounts-finance/tcl/modeling-procs.tcl for inspiration + # split at the beginning of each open square bracket + set executable_fragment_list [split $code_segment \[] + set executable_list [list ] + foreach executable_fragment $executable_fragment_list { + # right-clip to just the executable for screening purposes + set space_idx [string first " " $executable_fragment] + if { $space_idx > -1 } { + set end_idx [expr { $space_idx - 1 } ] + set executable [string range $executable_fragment 0 $end_idx] + } else { + set executable $executable_fragment + } + # screen executable + if { $executable eq "" } { + # skip an empty executable + # ns_log Notice "q-wiki.tcl(395): executable is empty. Screening incomplete?" + } else { + # see if this proc is allowed + set proc_allowed_p 0 + foreach allowed_proc $allowed_proc_list { + if { [string match $allowed_proc $executable] } { + set proc_allowed_p 1 + } + } + # see if this proc is banned. Banned takes precedence over allowed. + if { $proc_allowed_p } { + foreach banned_proc $banned_proc_list { + if { [string match $banned_proc $executable] } { + # banned executable found + set proc_allowed_p 0 + lappend flagged_list $executable + lappend user_message_list "'$executable' #q-wiki.is_banned_from_use#" + util_user_message -message [lindex $user_message_list end] + } + } + } else { + lappend flagged_list $executable + lappend user_message_list "'$executable' #q-wiki.is_not_allowed_at_this_time#" + util_user_message -message [lindex $user_message_list end] + } + } + } + } + } + if { [llength $flagged_list] == 0 } { + # content passed filters + set page_contents_filtered $page_contents + } else { + set page_contents_filtered $page_contents_quoted + } + } else { + # filtering out all adp tags (allow_adp_tcl_p == 0) + ns_log Notice "q-wiki.tcl(358): filtering out adp tags" + # ns_log Notice "q-wiki.tcl(359): range page_contents 0 120: '[string range ${page_contents} 0 120]'" + set page_contents_list [qf_remove_tag_contents "<%" "%>" $page_contents] + set page_contents_filtered [join $page_contents_list ""] + # ns_log Notice "q-wiki.tcl(427): range page_contents_filtered 0 120: '[string range ${page_contents_filtered} 0 120]'" + } + # use $page_contents_filtered, was $page_contents + set page_contents [ad_quotehtml $page_contents_filtered] + + if { [llength $flagged_list ] > 0 } { + ns_log Notice "q-wiki.tcl(369): content flagged, changing to edit mode." + set mode e + } else { + # write the data + # a different user_id makes new context based on current context, otherwise modifies same context + # or create a new context if no context provided. + # given: + + # create or write page + if { $page_id eq "" } { + # create page + set page_id [qw_page_create $url $page_name $page_title $page_contents_filtered $keywords $description $page_comments $page_template_id $page_flags $package_id $user_id] + if { $page_id == 0 } { + ns_log Warning "q-wiki/q-wiki.tcl page write error for url '${url}'" + lappend user_messag_list "There was an error creating the wiki page at '${url}'." + } + } else { + # write page + set page_id [qw_page_write $page_name $page_title $page_contents_filtered $keywords $description $page_comments $page_id $page_template_id $page_flags $package_id $user_id] + if { $page_id eq "" } { + ns_log Warning "q-wiki/q-wiki.tcl page write error for url '${url}'" + lappend user_messag_list "#q-wiki.There_was_an_error_creating_page# '${url}'." + } + } + + # rename existing pages? + if { $url ne $page_name } { + # rename url, but first post the page + if { [qw_page_rename $url $page_name $package_id ] } { + # if success, update url and redirect + set redirect_before_v_p 1 + set url $page_name + set next_mode "v" + } + } + + # switch modes.. + ns_log Notice "q-wiki.tcl(396): activating next mode $next_mode" + set mode $next_mode + } + } else { + # does not have permission to write + lappend user_message_list "#q-wiki.Write_operation_did_not_succeed# #q-wiki.You_don_t_have_permission#" + util_user_message -message [lindex $user_message_list end] + ns_log Notice "q-wiki.tcl(402) User attempting to write content without permission." + if { $read_p } { + set mode "v" + } else { + set mode "" + } + } + # end section of write + set next_mode "" + } + } +} else { + # form not posted + ns_log Warning "q-wiki.tcl(451): Form not posted. This shouldn't happen via index.vuh." +} + + +set menu_list [list ] + +# OUTPUT / VIEW +# using switch, because there's only one view at a time +ns_log Notice "q-wiki.tcl(508): OUTPUT mode $mode" +switch -exact -- $mode { + l { + # list...... presents a list of pages (Branch this off as a procedure and/or lib page fragment to be called by view action) + if { $read_p } { + if { $redirect_before_v_p } { + ns_log Notice "q-wiki.tcl(587): redirecting to url $url for clean url view" + ad_returnredirect "$url?mode=l" + ad_script_abort + } + + ns_log Notice "q-wiki.tcl(427): mode = $mode ie. list of pages, index" + #lappend menu_list [list #q-wiki.edit# "${url}?mode=e" ] + + append title " #q-wiki.index#" + # show page + # sort by template_id, columns + + set page_ids_list [qw_pages $package_id] + set pages_stats_lists [list ] + # we get the entire data set, 1 row(list) per page as table pages_stats_lists + foreach page_id $page_ids_list { + set stats_mod_list [list $page_id] + set stats_orig_list [qw_page_stats $page_id] + # a list: name, title, comments, keywords, description, template_id, flags, trashed, popularity, time last_modified, time created, user_id + foreach stat $stats_orig_list { + lappend stats_mod_list $stat + } + lappend stats_mod_list [qw_page_url_from_id $page_id] + # new: page_id, name, title, comments, keywords, description, template_id, flags, trashed, popularity, time last_modified, time created, user_id, url + lappend pages_stats_lists $stats_mod_list + } + set pages_stats_lists [lsort -index 2 $pages_stats_lists] + # build tables (list_of_lists) stats_list and their html filtered versions page_*_lists for display + set page_scratch_lists [list] + set page_stats_lists [list ] + set page_trashed_lists [list ] + + foreach stats_mod_list $pages_stats_lists { + set stats_list [lrange $stats_mod_list 0 2] + lappend stats_list [lindex $stats_mod_list 5] + lappend stats_list [lindex $stats_mod_list 3] + + set page_id [lindex $stats_mod_list 0] + set name [lindex $stats_mod_list 1] + set template_id [lindex $stats_mod_list 6] + set page_user_id [lindex $stats_mod_list 12] + set trashed_p [lindex $stats_mod_list 8] + set page_url [lindex $stats_mod_list 13] + + # convert stats_list for use with html + + # change Name to an active link and add actions if available + set active_link "$name" + set active_link_list [list $active_link] + set active_link2 "" + + if { $write_p } { + # trash the page + if { $trashed_p } { + set active_link2 " \"#acs-tcl.undelete#\"" + } else { + set active_link2 " \"#acs-tcl.delete#\"" + } + } elseif { $page_user_id == $user_id } { + # trash the revision + if { $trashed_p } { + set active_link2 " \"#acs-tcl.undelete#\"" + } else { + set active_link2 " \"#acs-tcl.delete#\"" + } + } + + if { $delete_p && $trashed_p } { + append active_link2 "     \"#acs-subsite.remove#\"   " + } + set stats_list [lreplace $stats_list 0 0 $active_link] + set stats_list [lreplace $stats_list 1 1 $active_link2] + + # add stats_list to one of the tables for display + if { $trashed_p && ( $write_p || $page_user_id eq $user_id ) } { + lappend page_trashed_lists $stats_list + } elseif { $trashed_p } { + # ignore this row, but track for errors + } else { + lappend page_stats_lists $stats_list + } + } + + # convert table (list_of_lists) to html table + set page_stats_sorted_lists $page_stats_lists + set page_stats_sorted_lists [linsert $page_stats_sorted_lists 0 [list "#acs-subsite.Name#" " " "#acs-kernel.common_Title#" "#acs-subsite.Description#" "#acs-subsite.Comment#"] ] + set page_tag_atts_list [list border 0 cellspacing 0 cellpadding 3] + set cell_formating_list [list ] + set page_stats_html [qss_list_of_lists_to_html_table $page_stats_sorted_lists $page_tag_atts_list $cell_formating_list] + # trashed table + if { [llength $page_trashed_lists] > 0 } { + set page_trashed_sorted_lists $page_trashed_lists + set page_trashed_sorted_lists [linsert $page_trashed_sorted_lists 0 [list "#acs-subsite.Name#" " " "#acs-kernel.common_Title#" "#acs-subsite.Description#" "#acs-subsite.Comment#"] ] + set page_tag_atts_list [list border 0 cellspacing 0 cellpadding 3] + + set page_trashed_html [qss_list_of_lists_to_html_table $page_trashed_sorted_lists $page_tag_atts_list $cell_formating_list] + } + } else { + # does not have permission to read. This should not happen. + ns_log Warning "q-wiki.tcl:(465) user did not get expected 404 error when not able to read page." + } + } + r { + # revisions...... presents a list of page revisions + lappend menu_list [list #q-wiki.index# "index?mode=l"] + + if { $write_p } { + ns_log Notice "q-wiki.tcl mode = $mode ie. revisions" + # build menu options + lappend menu_list [list #q-wiki.edit# "${url}?mode=e" ] + + # show page revisions + # sort by template_id, columns + set template_id $page_template_id_from_url + # these should be sorted by last_modified + set page_ids_list [qw_pages $package_id $user_id $template_id] + + set pages_stats_lists [list ] + # we get the entire data set, 1 row(list) per revision as table pages_stats_lists + # url is same for each + set page_id_active [qw_page_id_from_url $url $package_id] + foreach list_page_id $page_ids_list { + set stats_mod_list [list $list_page_id] + set stats_orig_list [qw_page_stats $list_page_id] + set page_list [qw_page_read $list_page_id] + # a list: name, title, comments, keywords, description, template_id, flags, trashed, popularity, time last_modified, time created, user_id + foreach stat $stats_orig_list { + lappend stats_mod_list $stat + } + lappend stats_mod_list $url + lappend stats_mod_list [string length [lindex $page_list 11]] + lappend stats_mod_list [expr { $list_page_id == $page_id_active } ] + # new: page_id, name, title, comments, keywords, description, template_id, flags, trashed, popularity, time last_modified, time created, user_id, url, content_length, active_revision + lappend pages_stats_lists $stats_mod_list + } + # build tables (list_of_lists) stats_list and their html filtered versions page_*_lists for display + set page_stats_lists [list ] + + # stats_list should contain page_id, user_id, size (string_length) ,last_modified, comments,flags, live_revision_p, trashed? , actions: untrash delete + + set contributor_nbr 0 + set contributor_last_id "" + set page_name [lindex [lindex $pages_stats_lists 0] 1] + append title "${page_name} - page revisions" + + foreach stats_mod_list $pages_stats_lists { + set stats_list [list] + # create these vars: + set index_list [list page_id 0 page_user_id 12 size 14 last_modified 10 created 11 comments 3 flags 7 live_revision_p 15 trashed_p 8] + foreach {list_item_name list_item_index} $index_list { + set list_item_value [lindex $stats_mod_list $list_item_index] + set $list_item_name $list_item_value + lappend stats_list $list_item_value + } + # convert stats_list for use with html + + set active_link "${page_id}" + set stats_list [lreplace $stats_list 0 0 $active_link] + + if { $page_user_id ne $contributor_last_id } { + set contributor_last_id $page_user_id + incr contributor_nbr + } + set contributor_title ${contributor_nbr} + set active_link3 "   ${contributor_title}" + set stats_list [lreplace $stats_list 1 1 $active_link3] + + if { $live_revision_p } { + # no links or actions. It's live, whatever its status + if { $trashed_p } { + set stats_list [lreplace $stats_list 7 7 "\"inactive\""] + } else { + set stats_list [lreplace $stats_list 7 7 "\"active\""] + } + } else { + if { $trashed_p } { + set stats_list [lreplace $stats_list 7 7 " "] + } else { + # it's untrashed, user can make it live. + set stats_list [lreplace $stats_list 7 7 "\"activate\""] + } + } + + set active_link_list [list $active_link] + set active_link2 "" + if { ( $write_p || $page_user_id == $user_id ) && $trashed_p } { + set active_link2 " \"#acs-tcl.undelete#\"" + } elseif { $page_user_id == $user_id || $write_p } { + set active_link2 " \"#acs-tcl.delete#\"" + } + if { ( $delete_p || $page_user_id == $user_id ) && $trashed_p } { + append active_link2 "     \"#acs-subsite.remove#\"   " + } + set stats_list [lreplace $stats_list 8 8 $active_link2] + + + + # if the user can delete or trash this stats_list, display it. + if { $write_p || $page_user_id eq $user_id } { + lappend page_stats_lists $stats_list + } + } + + # convert table (list_of_lists) to html table + set page_stats_sorted_lists $page_stats_lists + set page_stats_sorted_lists [linsert $page_stats_sorted_lists 0 [list "#q-wiki.ID#" "#q-wiki.Contributor#" "#q-wiki.Length#" "#q-wiki.Last_Modified#" "#q-wiki.Created#" "#acs-subsite.Comment#" "#q-wiki.Flags#" "#q-wiki.Liveq#" "#acs-subsite.Status#"] ] + set page_tag_atts_list [list border 0 cellspacing 0 cellpadding 3] + set cell_formating_list [list ] + set page_stats_html [qss_list_of_lists_to_html_table $page_stats_sorted_lists $page_tag_atts_list $cell_formating_list] + } else { + # does not have permission to read. This should not happen. + ns_log Warning "q-wiki.tcl:(465) user did not get expected 404 error when not able to read page." + } + + } + e { + + + if { $write_p } { + # edit...... edit/form mode of current context + + ns_log Notice "q-wiki.tcl mode = edit" + set cancel_link_html "#acs-kernel.common_Cancel#" + + # for existing pages, add template_id + set conn_package_url [ad_conn package_url] + set post_url [file join $conn_package_url $url] + + ns_log Notice "q-wiki.tcl(636): conn_package_url $conn_package_url post_url $post_url" + if { $page_id_from_url ne "" && [llength $user_message_list ] == 0 } { + + # get page info + set page_list [qw_page_read $page_id_from_url $package_id $user_id ] + set page_name [lindex $page_list 0] + set page_title [lindex $page_list 1] + set keywords [lindex $page_list 2] + set description [lindex $page_list 3] + set page_template_id [lindex $page_list 4] + set page_flags [lindex $page_list 5] + set page_contents [lindex $page_list 11] + set page_comments [lindex $page_list 12] + + set cancel_link_html "#acs-kernel.common_Cancel#" + } + + append title "${page_name} - #q-wiki.edit#" + + set rows_list [split $page_contents "\n\r"] + set rows_max [llength $rows_list] + set columns_max 40 + foreach row $rows_list { + set col_len [string length $row] + if { $col_len > $columns_max } { + set columns_max $col_len + } + } + if { $rows_max > 200 } { + set rows_max [expr { int( sqrt( hypot( $columns_max, $rows_max ) ) ) } ] + } + set columns_max [f::min 200 $columns_max] + set rows_max [f::min 800 $rows_max] + set rows_max [f::max $rows_max 6] + + qf_form action $post_url method post id 20130309 hash_check 1 + qf_input type hidden value w name mode + qf_input type hidden value v name next_mode + qf_input type hidden value $page_flags name page_flags + qf_input type hidden value $page_template_id name page_template_id + # qf_input type hidden value $page_id name page_id label "" + qf_append html "

Q-Wiki #acs-templating.Page# #q-wiki.edit#

" + qf_append html "
" + set page_name_unquoted [qf_unquote $page_name] + qf_input type text value $page_name_unquoted name page_name label "#acs-subsite.Name#:" size 40 maxlength 40 + qf_append html "
" + set page_title_unquoted [qf_unquote $page_title] + qf_input type text value $page_title_unquoted name page_title label "#acs-kernel.common_Title#:" size 40 maxlength 80 + qf_append html "
" + set description_unquoted [qf_unquote $description] + qf_textarea value $description_unquoted cols 40 rows 1 name description label "#acs-subsite.Description#:" + qf_append html "
" + set page_comments_unquoted [qf_unquote $page_comments] + qf_textarea value $page_comments_unquoted cols 40 rows 3 name page_comments label "#acs-subsite.Comment#:" + qf_append html "
" + set page_contents_unquoted [qf_unquote $page_contents] + qf_textarea value $page_contents_unquoted cols $columns_max rows $rows_max name page_contents label "#notifications.Contents#:" + qf_append html "
" + set keywords_unquoted [qf_unquote $keywords] + qf_input type text value $keywords_unquoted name keywords label "#q-wiki.Keywords#:" size 40 maxlength 80 + qf_append html "
" + qf_input type submit value "#acs-kernel.common_Save#" + qf_append html "       ${cancel_link_html}" + qf_close + set form_html [qf_read] + } else { + lappend user_message_list "#q-wiki.Edit_operation_did_not_succeed# #q-wiki.You_don_t_have_permission#" + util_user_message -message [lindex $user_message_list end] + } + } + v { + # view page(s) (standard, html page document/report) + if { $read_p } { + # if $url is different than ad_conn url stem, 303/305 redirect to page_id's primary url + + if { $redirect_before_v_p } { + ns_log Notice "q-wiki.tcl(835): redirecting to url $url for clean url view" + ad_returnredirect $url + ad_script_abort + } + ns_log Notice "q-wiki.tcl(667): mode = $mode ie. view" + + lappend menu_list [list #q-wiki.index# "index?mode=l"] + + # get page info + if { $page_id eq "" } { + # cannot use previous $page_id_from_url, because it might be modified from an ACTION + # Get it again. + set page_id_from_url [qw_page_id_from_url $url $package_id] + set page_list [qw_page_read $page_id_from_url $package_id $user_id ] + } else { + set page_list [qw_page_read $page_id $package_id $user_id ] + } + + if { $create_p } { + if { $page_id_from_url ne "" || $page_id ne "" } { + lappend menu_list [list #q-wiki.revisions# "${url}?mode=r"] + } + lappend menu_list [list #q-wiki.edit# "${url}?mode=e" ] + } + + if { [llength $page_list] > 1 } { + set page_title [lindex $page_list 1] + set keywords [lindex $page_list 2] + set description [lindex $page_list 3] + set page_contents [lindex $page_list 11] + set trashed_p [lindex $page_list 6] + set template_id [lindex $page_list 4] + # trashed pages cannot be viewed by public, but can be viewed with permission + if { $delete_p && $trashed_p } { + lappend menu_list [list #acs-subsite.remove# "${url}?mode=d&next_mode=l&page_template_id=${template_id}" ] + } elseif { $delete_p && !$trashed_p } { + lappend menu_list [list #acs-tcl.delete# "${url}?mode=t&next_mode=v&page_template_id=${template_id}" ] + } + + if { $keywords ne "" } { + template::head::add_meta -name keywords -content $keywords + } + if { $description ne "" } { + template::head::add_meta -name description -content $description + } + set title $page_title + # page_contents_filtered + set page_contents_unquoted [ad_unquotehtml $page_contents] + set page_main_code [template::adp_compile -string $page_contents_unquoted] + set page_main_code_html [template::adp_eval page_main_code] + } + } else { + # no permission to read page. This should not happen. + ns_log Warning "q-wiki.tcl:(619) user did not get expected 404 error when not able to read page." + } + } + w { + # save..... (write) page_id + # should already have been handled above + ns_log Warning "q-wiki.tcl(575): mode = save/write THIS SHOULD NOT BE CALLED." + # it's called in validation section. + } + default { + # return 404 not found or not validated (permission or other issue) + # this should use the base from the config.tcl file + if { [llength $user_message_list ] == 0 } { + ns_returnnotfound + # rp_internal_redirect /www/global/404.adp + ad_script_abort + } + } +} +# end of switches + +# using OpenACS built-in util_get_user_messages feature +#set user_message_html "" +#foreach user_message $user_message_list { +# append user_message_html "
  • ${user_message}
  • " +#} + +set menu_html "" +set validated_p_exists [info exists validated_p] +if { $validated_p_exists && $validated_p || !$validated_p_exists } { + foreach item_list $menu_list { + set menu_label [lindex $item_list 0] + set menu_url [lindex $item_list 1] + append menu_html "${menu_label}   " + } +} +set doc(title) $title +set context [list $title] Index: openacs-4/packages/q-wiki/www/admin/index.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/www/admin/index.adp,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/www/admin/index.adp 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,10 @@ + + @title;noquote@ + @context;noquote@ +

    Q-Wiki Admin +

    +

    All admin features are available via the main www directory and package parameters. +

    +

    This page exists to show additional features by example at some point. None yet. +

    + Index: openacs-4/packages/q-wiki/www/admin/index.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/www/admin/index.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/www/admin/index.tcl 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,3 @@ +set title "Admin" +set context [list $title] + Index: openacs-4/packages/q-wiki/www/doc/index-extended-vuh.txt =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/www/doc/index-extended-vuh.txt,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/www/doc/index-extended-vuh.txt 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,61 @@ +# q-wiki/www/index.vuh +# part of Q-Wiki package +# requires OpenACS + +# index.vuh allows q-wiki to integrate with other services. +# For robustness, rename q-wiki.tcl/q-wiki.adp to index.vuh to bypass having to repost data +set conn_path_url [ad_conn path_info] + +array set input_array [list \ + url ""\ + page_id ""\ + page_name ""\ + page_title ""\ + page_contents ""\ + keywords ""\ + description ""\ + page_comments ""\ + page_template_id ""\ + page_flags ""\ + page_contents_default ""\ + submit "" \ + reset "" \ + mode "v" \ + next_mode "" \ + qf_security_hash "" \ + url_referring "" \ + model_ref "" \ + spec1ref "" \ + spec1default "" \ + spec2ref "" \ + spec2default "" \ + spec3ref "" \ + spec3default "" \ + image_name "" \ + image_width "" \ + image_height "" \ + thumbnail_name "" \ + thumbnail_width "" \ + thumbnail_height "" \ + price "" \ + dimensions "" \ + ship_wt "" \ + actual_wt "" \ + unit "" \ + ] +set query_key_list [array names input_array] + +set form_posted [qf_get_inputs_as_array input_array] +set input_array(url) $conn_path_url +set input_array(url_referring) "index.vuh" +# re-post data to new location +foreach query_key $query_key_list { + rp_form_put $query_key [ad_urlencode $input_array(${query_key})] + if { $query_key eq "url" } { + ns_log Notice "q-wiki/www/index.vuh: url $input_array(url)" + } +} +rp_internal_redirect /packages/bw-custom/www/q-wiki +ad_script_abort + + Index: openacs-4/packages/q-wiki/www/doc/index.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/www/doc/index.adp,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/www/doc/index.adp 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,121 @@ + + @title;noquote@ + @context;noquote@ +

    Q-Wiki Documentation

    + +
    (c) 2013 by Benjamin Brink
    +po box 20, Marylhurst, OR 97036-0020 usa
    +email: kappa@dekka.com
    +

    Open source License under GNU GPL

    +
    +    This program is free software: you can redistribute it and/or modify
    +    it under the terms of the GNU General Public License as published by
    +    the Free Software Foundation, either version 2 of the License, or
    +    (at your option) any later version.
    +
    +    This program is distributed in the hope that it will be useful,
    +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +    GNU General Public License for more details.
    +
    +    You should have received a copy of the GNU General Public License
    +    along with this program.  If not, see .
    +
    +

    introduction

    +

    +Q-Wiki is an OpenACS wiki using a templating system that allows tcl procedures to be used in a web-based publishing environment + without being tied to other applications, such as ecommerce. +

    +

    +Q-Wiki is derived from OpenACS' ecommerce package with feedback from administrators that have voiced interest in having some kind of strictly filtered ACS developer support dynamics for user content. +

    +

    features

    +

    Pages automatically have revisioning ie multi-undo.

    +

    Pages must be trashed before being deleted. Trashed pages can be untrashed. Trashed pages are not published.

    +

    Users with create permission can also trash their own creations.

    +

    No UI javascript is used, so technologies with limited UI or computing power can use it.

    +

    Tcl procedures pass through two filters: a list of glob expressions stating which procedures are allowed to be used, and a second list of specifically banned procedures.

    +

    A package parameter can switch the TCL/ADP rendering of content on or off.

    +

    The wiki web-app consists of a single q-wiki tcl/adp page pair and an extra unused "flags" field, which makes the app easily modifiable for custom applications.

    +

    Comments, keywords, and page description fields are included with each page for web-based publishing SEO optimization.

    +

    Extensible. More fields can be added to the page for customized applications.

    +

    +An example dynamic template to hint at its capabilities: +

    +
    +
    +<%
    +    set contributors_list [qw_contributors]
    +    set pretty_contributors_list [template::util::tcl_to_sql_list $contributors_list]
    +    set user_id [lindex $contributors_list 0]
    +    set user_name [person::name -person_id $user_id] 
    +    set pages_of_user_list [qw_user_contributions $user_id] 
    +    set pages_of_user [template::util::tcl_to_sql_list $pages_of_user_list]
    +%>
    +<p>
    +  Wiki last edited on: <%= [lindex [qw_most_recent_edit_stats ] 1] %>
    +</p>
    +<p>
    +  Contributor user numbers: \@pretty_contributors_list\@
    +</p>
    +
    +<p>
    +  Most recent contributor, \@user_name\@, 
    +  made these contributions: \@pages_of_user\@.
    +</p>
    +
    +
    +

    And here's the output for a test installation:

    +

    +Wiki last edited on: 2013-03-12 17:46:20.250505+00 +

    +

    +Contributor user numbers: '667' +

    + +

    Most recent contributor, Admin for or97 net, +made these contributions: '10222', '10221', '10220', '10219', '10218', '10217', '10216', '10215', '10214', '10213', '10212', '10211', '10210', '10209', '10208', '10207', '10206', '10205', '10204', '10203', '10202', '10201', '10200', '10199', '10198', '10197', '10196', '10195', '10194', '10193'.

    + +
    +

    An example showing how to extend Q-wiki for customized applications. +

    +

    file list and example changes:

    + +

    An example simlar to this has been fully implemented in a package called cl-custom at +https://github.com/tekbasse/cl-custom +

    +

    Templates +

    +

    Q-wiki can be setup as a template for tables (and lists and forms) as well as pages for wiki and ecommerce catalog apps. +

    +

    Q-wiki page content stores html for displaying a row. +$1 $2 $3 .. $9 are used to reference variable values by column number. +$1 is value for column 1 etc. +

    +

    A standard table row might have content like this: +

    +
    +<tr> <td>$1</td> <td>$2</td> <td>$3</td> </tr>
    +
    +

    However, TABLEs are too wide for convenient display on many small devices. +

    +

    Lists and DIVs that wrap using responsive style techniques are preferred. +

    +

    Standard workflow is to aply changes to code where html is hardcoded. +Hardcoded html makes code updates for admins a laborious task; +Admins have to re-integrate html changes into each updated code release. +In addition to the extra workload, there's always a risk that something will break in the upgrade. +

    +

    How can style be adjusted without hard-coding customizations? +

    +

    By keeping customizations in the db. One way is by referencing page content using Q-wiki API. +And building a report (list, table etc) using OpenACS procs. +

    +

    qw_template_custom_read allows column orders to be customized on up to a per user case. +This information can then be used to build reports with column in different orders etc. +Each case is set with qw_template_custom_set . +

    Index: openacs-4/packages/q-wiki/www/doc/index.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/www/doc/index.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/www/doc/index.tcl 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,3 @@ +set title "Documentation" +set context [list $title] + Index: openacs-4/packages/q-wiki/www/doc/q-wiki-extended-adp.txt =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/www/doc/q-wiki-extended-adp.txt,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/www/doc/q-wiki-extended-adp.txt 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,41 @@ + + @title@ + @title@ + @context;noquote@ + + + +
    @menu_html;noquote@
    +
    +

    @title@

    + +
      + @user_message_html;noquote@ +
    +
    + + + @form_html;noquote@ + + + +

    pages

    + @page_stats_html;noquote@ +
    + + +

    trashed

    + @page_trashed_html;noquote@ +
    + + + @page_main_code_html;noquote@ + + + + +< include src="lib/product" model=@ model_ref @> +

    Regular adp and /lib templates can be included

    +
    + + Index: openacs-4/packages/q-wiki/www/doc/q-wiki-extended-tcl.txt =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/www/doc/q-wiki-extended-tcl.txt,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/www/doc/q-wiki-extended-tcl.txt 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,1242 @@ +# q-wiki/q-wiki.tcl +# part of the Q-Wiki package +# depends on OpenACS website toolkit at OpenACS.org +# copyrigh t +# released under GPL license +# this page split into MVC components: +# inputs/observations (controller), actions (model), and outputs/reports (view) sections + +## For consistency, user_id can only make modifications if they have create_p permissions. +## User_id is not enough, as there would be issues with choosing active revisions +## so, user_id revsion changes are moderated. ie user_id can create a revision, but it takes write_p user to make revision active. + + +# INPUTS / CONTROLLER + +# set defaults +# template_id is first page_id, subsequent revisions have same template_id, but new page_id +# flags are blank -- an unused db column / page attribute for extending the app for use cases +# url has to be a given (not validated), since this page may be fed $url via an index.vuh + +set title "Q-Wiki" +set icons_path1 "/resources/acs-subsite/" +set icons_path2 "/resources/ajaxhelper/icons/" +set delete_icon_url [file join $icons_path2 delete.png] +set trash_icon_url [file join $icons_path2 page_delete.png] +set untrash_icon_url [file join $icons_path2 page_add.png] +set radio_checked_url [file join $icons_path1 radiochecked.gif] +set radio_unchecked_url [file join $icons_path1 radio.gif] +set redirect_before_v_p 0 + +set package_id [ad_conn package_id] +set user_id [ad_conn user_id] +set read_p [permission::permission_p -party_id $user_id -object_id $package_id -privilege read] +set create_p [permission::permission_p -party_id $user_id -object_id $package_id -privilege create] +set write_p [permission::permission_p -party_id $user_id -object_id $package_id -privilege write] +set admin_p [permission::permission_p -party_id $user_id -object_id $package_id -privilege admin] +set delete_p [permission::permission_p -party_id $user_id -object_id $package_id -privilege delete] + +array set input_array [list \ + url ""\ + page_id ""\ + page_name ""\ + page_title ""\ + page_contents ""\ + keywords ""\ + description ""\ + page_comments ""\ + page_template_id ""\ + page_flags ""\ + page_contents_default ""\ + submit "" \ + reset "" \ + mode "v" \ + next_mode "" \ + url_referring "" \ + qf_security_hash "" \ + model_ref "" \ + spec1ref "" \ + spec1default "" \ + spec2ref "" \ + spec2default "" \ + spec3ref "" \ + spec3default "" \ + image_name "" \ + image_width "" \ + image_height "" \ + thumbnail_name "" \ + thumbnail_width "" \ + thumbnail_height "" \ + price "" \ + dimensions "" \ + ship_wt "" \ + actual_wt "" \ + unit "" \ + ] + +set user_message_list [list ] +set title $input_array(page_title) + +# get previous form inputs if they exist +set form_posted [qf_get_inputs_as_array input_array2] +if { $form_posted && ( $input_array2(mode) eq "w" || $input_array2(mode) eq "d" ) } { + # do this again for hash_check to avoid irreversable cases. + # left off "delete" cases, as these need to be converted to forms in menu.. $input_array2(mode) eq "d" + array unset input_array2 + set form_posted [qf_get_inputs_as_array input_array hash_check 1] + +} else { + array set input_array [array get input_array2] +} +set page_id $input_array(page_id) +set page_template_id $input_array(page_template_id) + +set page_name $input_array(page_name) +set page_title $input_array(page_title) +set page_flags $input_array(page_flags) +set keywords $input_array(keywords) +set description $input_array(description) +set page_comments $input_array(page_comments) +set page_contents $input_array(page_contents) +set mode $input_array(mode) +set next_mode $input_array(next_mode) + +set model_ref $input_array(model_ref) +set spec1ref $input_array(spec1ref) +set spec1default $input_array(spec1default) +set spec2ref $input_array(spec2ref) +set spec2default $input_array(spec2default) +set spec3ref $input_array(spec3ref) +set spec3default $input_array(spec3default) +set image_name $input_array(image_name) +set image_width $input_array(image_width) +set image_height $input_array(image_height) +set thumbnail_name $input_array(thumbnail_name) +set thumbnail_width $input_array(thumbnail_width) +set thumbnail_height $input_array(thumbnail_height) +set price $input_array(price) +set dimensions $input_array(dimensions) +set ship_wt $input_array(ship_wt) +set actual_wt $input_array(actual_wt) +set unit $input_array(unit) + + +# Is this a redirect from index.vuh ? +set file_name [file tail [ad_conn file]] +if { [ns_urldecode $input_array(url_referring)] eq "index.vuh" && $file_name eq "q-wiki.adp" } { + # To do, when write_p == 1: index.vuh value should be replaced with a session continuity key passed via db. + + # If url is internal_redirecting from index.vuh, url should be same as: + # set url [ad_conn path_info] + + # url_de-encode values + set url $input_array(url) + set page_name [ns_urldecode $page_name] + set page_title [ns_urldecode $page_title] + set page_flags [ns_urldecode $page_flags] + set keywords [ns_urldecode $keywords] + set description [ns_urldecode $description] + set page_comments [ns_urldecode $page_comments] + set page_contents [ns_urldecode $page_contents] + +set model_ref [ns_urldecode $model_ref] +set spec1ref [ns_urldecode $spec1ref] +set spec1default [ns_urldecode $spec1default] +set spec2ref [ns_urldecode $spec2ref] +set spec2default [ns_urldecode $spec2default] +set spec3ref [ns_urldecode $spec3ref] +set spec3default [ns_urldecode $spec3default] +set image_name [ns_urldecode $image_name] +set image_width [ns_urldecode $image_width] +set image_height [ns_urldecode $image_height] +set thumbnail_name [ns_urldecode $thumbnail_name] +set thumbnail_width [ns_urldecode $thumbnail_width] +set thumbnail_height [ns_urldecode $thumbnail_height] +set price [ns_urldecode $price] +set dimensions [ns_urldecode $dimensions] +set ship_wt [ns_urldecode $ship_wt] +set actual_wt [ns_urldecode $actual_wt] +set unit [ns_urldecode $unit] + + +} elseif { $file_name eq "index.vuh" } { + # is this code executing inside index.vuh? + set url [ad_conn path_info] + ns_log Notice "q-wiki.tcl(29): file_name ${file_name}. Setting url to $url" +} elseif { !$form_posted && $input_array(url_referring) eq "" } { + # this test is for cases where hash_check is required for form posts + # but no user form has been posted, default values still need to be passed. + set url [ad_conn path_info] + set file_name $url +} else { + # A serious assumption has broken. + ns_log Warning "q-wiki.tcl(75): quit with referr_url and file_name out of boundary. Check log for request details." + ns_returnnotfound + # rp_internal_redirect /www/global/404.adp + ad_script_abort +} + +if { $url eq "" || $url eq "/" } { + set url "index" +} + + +if { $write_p } { + set page_id_from_url [qw_page_id_from_url $url $package_id] +} else { + # user can only edit or see it if it is published (not trashed) + set page_id_from_url [qw_page_from_url $url $package_id] +} + + +if { $page_id_from_url ne "" && ![qf_is_natural_number $page_id_from_url] } { + ns_log Notice "q-wiki.tcl(62): page_id_from_url '$page_id_from_url'" +} +ns_log Notice "q-wiki.tcl(63): mode $mode next_mode $next_mode" +# Modes are views, or one of these compound action/views + # d delete (d x) then view as before (where x = l, r or v) + # t trash (d x) then view as before (where x = l, r or v) + # w write (d x) , then view page_id (v) + +# Actions + # d = delete template_id or page_id + # t = trash template_id or page_id + # w = write page_id,template_id, make new page_id for template_id + # a = make page_id the active revision for template_id +# Views + # e = edit page_url, presents defaults (new) if page doesn't exist + # v = view page_url + # l = list pages of instance + # r = view/edit page_url revisions + # default = 404 return + + # url has to come from form in order to pass info via index.vuh + # set conn_package_url [ad_conn package_url] + # set url [string range $url [string length $conn_package_url] end] + # get page_id from url, if any + +if { $form_posted } { + if { [info exists input_array(x) ] } { + unset input_array(x) + } + if { [info exists input_array(y) ] } { + unset input_array(y) + } + if { ![qf_is_natural_number $page_id] } { + set page_id "" + } + + set validated_p 0 + # validate input + # cleanse data, verify values for consistency + # determine input completeness + + + if { $page_id_from_url ne "" } { + # page exists + + + set page_stats_from_url_list [qw_page_stats $page_id_from_url $package_id $user_id] + set page_template_id_from_url [lindex $page_stats_from_url_list 5] + ns_log Notice "q-wiki.tcl(106): page_id_from_url '$page_id_from_url' page_template_id_from_url '$page_template_id_from_url'" + + # page_template_id and page_id gets checked against db for added security + # check for form/db descrepencies + set page_stats_from_form_list [qw_page_stats $page_id] + set page_template_id_from_form_pid [lindex $page_stats_from_form_list 5] + + # if mode is e etc, allow edit of page_id in set of page_id_from_url revisions: + # verify template_id from page_id and from url are consistent. + if { $page_id ne "" && [qf_is_natural_number $page_template_id_from_url ] && $page_template_id_from_url ne $page_template_id_from_form_pid } { + ns_log Notice "q-wiki/q-wiki.tcl: template_ids don't match. page_id '$page_id' page_id_from_url '$page_id_from_url', page_template_id_from_url '$page_template_id_from_url' page_template_id_from_form_pid '$page_template_id_from_form_pid'" + set page_id $page_id_from_url + set mode "" + set next_mode "" + lappend user_message_list "There has been an internal processing error. Try again or report issue to [ad_admin_owner]" + util_user_message -message [lindex $user_message_list end] + } + if { $page_template_id ne "" && [qf_is_natural_number $page_template_id ] && $page_template_id_from_url ne $page_template_id } { + ns_log Notice "q-wiki/q-wiki.tcl: template_ids don't match. page_template_id '$page_template_id' page_id_from_url '$page_id_from_url', page_template_id_from_url '$page_template_id_from_url'" + set page_template_id $page_template_id_from_url + set mode "" + set next_mode "" + lappend user_message_list "There has been an internal processing error. Try again or report issue to [ad_admin_owner]" + util_user_message -message [lindex $user_message_list end] + } + + # A blank referrer means a direct request + # otherwise make sure referrer is from same domain when editing + set referrer_url [get_referrer] + + + ns_log Notice "q-wiki.tcl(124): mode $mode next_mode $next_mode" + # get info to pass back to write proc + + # This is a place to enforce application specific permissions. + # If package parameter says each template_id is an object_id, + # check user_id against object_id, otherwise check against package_id + # However, original_page_creation_user_id is in the db, so that instance specific + # user permissions can be supported. + # set original_user_id \[lindex $page_stats_list_of_template_id 11\] + + } else { + # page does not exist + if { $write_p && $mode ne "l" && $mode ne "w" } { + # present an edit/new page + set mode "e" + set next_mode "" + set validated_p 1 + } + } + # else should default to 404 at switch in View section. + + # validate input values for specific modes + # failovers for permissions follow reverse order (skipping ok): admin_p delete_p write_p create_p read_p + # possibilities are: d, t, w, e, v, l, r, "" where "" is invalid input or unreconcilable error condition. + # options include d, l, r, t, e, "", w, v + set http_header_method [ad_conn method] + ns_log Notice "q-wiki.tcl(141): initial mode $mode, next_mode $next_mode, http_header_method ${http_header_method}" + if { ( $next_mode eq "v" || $next_mode eq "l" ) && [string match -nocase GET $http_header_method] } { + # redirect when viewing, to clean the url + ns_log Notice "q-wiki.tcl(223): Setting redirect_before_v_p " + set redirect_before_v_p 1 + } + if { $mode eq "d" } { + if { $delete_p } { + ns_log Notice "q-wiki.tcl validated for d" + set validated_p 1 + } elseif { $read_p } { + set mode "l" + set next_mode "" + } else { + set mode "" + set next_mode "" + } + } + ns_log Notice "q-wiki.tcl(157): mode $mode next_mode $next_mode" + if { $mode eq "w" } { + if { $write_p } { + set validated_p 1 + } elseif { $read_p } { + # give the user a chance to save their changes elsewhere instead of erasing the input + set mode "e" + } else { + set mode "" + set next_mode "" + } + } + ns_log Notice "q-wiki.tcl(169): mode $mode next_mode $next_mode" + if { $mode eq "r" || $mode eq "a" } { + if { $write_p } { + if { [qf_is_natural_number $page_template_id_from_url ] } { + set validated_p 1 + ns_log Notice "q-wiki.tcl validated for $mode" + } elseif { $read_p } { + # This is a 404 return, but we list pages for more convenient UI + lappend user_message_list "Page not found. Showing a list of pages." + util_user_message -message [lindex $user_message_list end] + set mode "l" + } + } else { + set mode "" + set next_mode "" + } + } + ns_log Notice "q-wiki.tcl(185): mode $mode next_mode $next_mode" + if { $mode eq "t" } { + if { ( $write_p || $user_id > 0 ) && ([qw_page_id_exists $page_id $package_id] || [qw_page_id_exists $page_id_from_url $package_id] ) } { + # complete validation occurs while trashing. + set validated_p 1 + ns_log Notice "q-wiki.tcl validated for t" + } elseif { $read_p } { + set mode "l" + } else { + set mode "" + } + } + + if { $page_id_from_url eq "" && $write_p && $mode eq "" && $next_mode eq "" } { + # page is blank + # switch to edit mode automatically for users with write_p + set mode "e" + } + + ns_log Notice "q-wiki.tcl(197): mode $mode next_mode $next_mode" + if { $mode eq "e" } { + # validate for new and existing pages. + # For new pages, template_id will be blank (template_exists_p == 0) + # For revisions, page_id will be blank. + set template_exists_p [qw_page_id_exists $page_template_id] + if { !$template_exists_p } { + set page_template_id "" + } + if { $write_p || ( $create_p && !$template_exists_p ) } { + + # page_title cannot be blank + if { $page_title eq "" && $page_template_id eq "" } { + set page_title "[clock format [clock seconds] -format %Y%m%d-%X]" + } elseif { $page_title eq "" } { + set page_title "${page_template_id}" + } else { + set page_title_length [parameter::get -package_id $package_id -parameter PageTitleLen -default 80] + incr page_title_length -1 + set page_title [string range $page_title 0 $page_title_length] + } + + if { $page_template_id eq "" && $page_name ne "" } { + # this is a new page + set url [ad_urlencode $page_name] + set page_id "" + } elseif { $page_template_id eq "" } { + if { [regexp -nocase -- {[^a-z0-9\%\_\-\.]} $url] } { + # url contains unencoded characters + set url [ad_urlencode $url] + set page_id "" + } + + # Want to enforce unchangeable urls for pages? + # If so, set url from db for template_id here. + } + ns_log Notice "q-wiki.tcl(226): url $url" + # page_name is pretty version of url, cannot be blank + if { $page_name eq "" } { + set page_name $url + } else { + set page_name_length [parameter::get -package_id $package_id -parameter PageNameLen -default 40] + incr page_name_length -1 + set page_name [string range $page_name 0 $page_name_length] + } + set validated_p 1 + ns_log Notice "q-wiki.tcl validated for $mode" + } elseif { $read_p && $template_exists_p } { + set mode v + set next_mode "" + } else { + set mode "" + set next_mode "" + } + } + ns_log Notice "q-wiki.tcl(252): mode $mode next_mode $next_mode" + if { $mode eq "l" } { + if { $read_p } { + set validated_p 1 + ns_log Notice "q-wiki.tcl validated for l" + } else { + set mode "" + set next_mode "" + } + } + ns_log Notice "q-wiki.tcl(262): mode $mode next_mode $next_mode" + if { $mode eq "v" } { + if { $read_p } { + # url vetted previously + set validated_p 1 + if { $page_id_from_url ne "" } { + # page exists + } else { + set mode "l" + ns_log Notice "q-wiki.tcl(405): mode = $mode ie. list of pages, index" + } + } else { + set mode "" + set next_mode "" + } + } + + # ACTIONS, PROCESSES / MODEL + ns_log Notice "q-wiki.tcl(268): mode $mode next_mode $next_mode validated $validated_p" + if { $validated_p } { + ns_log Notice "q-wiki.tcl ACTION mode $mode validated_p 1" + # execute process using validated input + # IF is used instead of SWITCH, so multiple sub-modes can be processed in a single mode. + if { $mode eq "d" } { + # delete.... removes context + ns_log Notice "q-wiki.tcl mode = delete" + if { $delete_p } { + qw_page_delete $page_id $page_template_id $package_id $user_id +# qw_page_delete $page_id $page_template_id_from_url $package_id $user_id + } + set mode $next_mode + set next_mode "" + } + ns_log Notice "q-wiki.tcl(358): mode $mode" + if { $mode eq "a" } { + # change active revision of page_template_id_from_url to page_id + if { $write_p } { + if { [qw_change_page_id_for_url $page_id $url $package_id] } { + set mode $next_mode + set page_id_from_url $page_id + } else { + lappend user_message_list "Revision could not be made active. Try again or report issue to [ad_admin_owner]" + util_user_message -message [lindex $user_message_list end] + set mode "r" + } + } + set next_mode "" + } + ns_log Notice "q-wiki.tcl(344): mode $mode" + if { $mode eq "t" } { + # toggle trash + ns_log Notice "q-wiki.tcl mode = trash" + # which page to trash page_id or page_id_from_url? + if { $page_id ne "" } { + set page_id_stats [qw_page_stats $page_id] + set trashed_p [lindex $page_id_stats 7] + set page_user_id [lindex $page_id_stats 11] + } elseif { $page_template_id ne "" } { + set page_id_stats [qw_page_stats $page_id_from_url] + set trashed_p [lindex $page_id_stats 7] + set page_user_id [lindex $page_id_stats 11] + } +# set template_id \[lindex $page_id_stats 5\] + set trash_done_p 0 + if { $write_p || $page_user_id eq $user_id } { + if { $trashed_p } { + set trash "0" + } else { + set trash "1" + } + ns_log Notice "q-wiki.tcl(419): qw_page_trash page_id $page_id trash_p $trash templat_id $page_template_id" + set trash_done_p [qw_page_trash $page_id $trash $page_template_id] + set mode $next_mode + } + if { !$trash_done_p } { + lappend user_message_list "Item could not be trashed. You don't have permission to trash this item." + util_user_message -message [lindex $user_message_list end] + } + set next_mode "" + # update the page_id + set page_id_from_url [qw_page_id_from_url $url $package_id] + if { $page_id_from_url ne "" && $mode eq "" } { + set mode "v" + } + } + ns_log Notice "q-wiki.tcl(374): mode $mode" + if { $mode eq "w" } { + if { $write_p } { + ns_log Notice "q-wiki.tcl permission to write the write.." + set page_contents_quoted $page_contents + set page_contents [ad_unquotehtml $page_contents] + set allow_adp_tcl_p [parameter::get -package_id $package_id -parameter AllowADPTCL -default 0] + set flagged_list [list ] + + if { $allow_adp_tcl_p } { + ns_log Notice "q-wki.tcl(311): adp tags allowed. Fine grain filtering.." + # filter page_contents for allowed and banned procs in adp tags + set banned_proc_list [split [parameter::get -package_id $package_id -parameter BannedProc]] + set allowed_proc_list [split [parameter::get -package_id $package_id -parameter AllowedProc]] + + set code_block_list [qf_get_contents_from_tags_list "<%" "%>" $page_contents] + foreach code_block $code_block_list { + # split into lines + set code_segments_list [split $code_block \n\r] + foreach code_segment $code_segments_list { + # see filters in accounts-finance/tcl/modeling-procs.tcl for inspiration + # split at the beginning of each open square bracket + set executable_fragment_list [split $code_segment \[] + set executable_list [list ] + foreach executable_fragment $executable_fragment_list { + # right-clip to just the executable for screening purposes + set space_idx [string first " " $executable_fragment] + if { $space_idx > -1 } { + set end_idx [expr { $space_idx - 1 } ] + set executable [string range $executable_fragment 0 $end_idx] + } else { + set executable $executable_fragment + } + # screen executable + if { $executable eq "" } { + # skip an empty executable + # ns_log Notice "q-wiki.tcl(395): executable is empty. Screening incomplete?" + } else { + # see if this proc is allowed + set proc_allowed_p 0 + foreach allowed_proc $allowed_proc_list { + if { [string match $allowed_proc $executable] } { + set proc_allowed_p 1 + } + } + # see if this proc is banned. Banned takes precedence over allowed. + if { $proc_allowed_p } { + foreach banned_proc $banned_proc_list { + if { [string match $banned_proc $executable] } { + # banned executable found + set proc_allowed_p 0 + lappend flagged_list $executable + lappend user_message_list "'$executable' is banned from use." + util_user_message -message [lindex $user_message_list end] + } + } + } else { + lappend flagged_list $executable + lappend user_message_list "'$executable' is not allowed at this time." + util_user_message -message [lindex $user_message_list end] + } + } + } + } + } + if { [llength $flagged_list] == 0 } { + # content passed filters + set page_contents_filtered $page_contents + } else { + set page_contents_filtered $page_contents_quoted + } + } else { + # filtering out all adp tags (allow_adp_tcl_p == 0) + ns_log Notice "q-wiki.tcl(358): filtering out adp tags" + # ns_log Notice "q-wiki.tcl(359): range page_contents 0 120: '[string range ${page_contents} 0 120]'" + set page_contents_list [qf_remove_tag_contents "<%" "%>" $page_contents] + set page_contents_filtered [join $page_contents_list ""] + # ns_log Notice "q-wiki.tcl(427): range page_contents_filtered 0 120: '[string range ${page_contents_filtered} 0 120]'" + } + # use $page_contents_filtered, was $page_contents + set page_contents [ad_quotehtml $page_contents_filtered] + + if { [llength $flagged_list ] > 0 } { + ns_log Notice "q-wiki.tcl(369): content flagged, changing to edit mode." + set mode e + } else { + # write the data + # a different user_id makes new context based on current context, otherwise modifies same context + # or create a new context if no context provided. + # given: + + # create or write page + if { $page_id eq "" } { + # create page + set page_id [qw_page_create $url $page_name $page_title $page_contents_filtered $keywords $description $page_comments $page_template_id $page_flags $package_id $user_id] + if { $page_id == 0 } { + ns_log Warning "q-wiki/q-wiki.tcl page write error for url '${url}'" + lappend user_messag_list "There was an error creating the wiki page at '${url}'." + } else { + qwbw_page_create $package_id $page_id $model_ref $spec1ref $spec1default $spec2ref $spec2default $spec3ref $spec3default $image_name $image_width $image_height $thumbnail_name $thumbnail_width $thumbnail_height $price $dimensions $ship_wt $actual_wt $unit + } + } else { + # write page + set page_id [qw_page_write $page_name $page_title $page_contents_filtered $keywords $description $page_comments $page_id $page_template_id $page_flags $package_id $user_id] + if { $page_id eq "" } { + ns_log Warning "q-wiki/q-wiki.tcl page write error for url '${url}'" + lappend user_messag_list "There was an error creating the wiki page at '${url}'." + } else { + qwbw_page_write $package_id $page_id $model_ref $spec1ref $spec1default $spec2ref $spec2default $spec3ref $spec3default $image_name $image_width $image_height $thumbnail_name $thumbnail_width $thumbnail_height $price $dimensions $ship_wt $actual_wt $unit + } + } + + # rename existing pages? + if { $url ne $page_name } { + # rename url, but first post the page + if { [qw_page_rename $url $page_name $package_id ] } { + # if success, update url and redirect + set redirect_before_v_p 1 + set url $page_name + set next_mode "v" + } + } + + # switch modes.. + ns_log Notice "q-wiki.tcl(396): activating next mode $next_mode" + set mode $next_mode + } + } else { + # does not have permission to write + lappend user_message_list "Write operation could not be completed. You don't have permission." + util_user_message -message [lindex $user_message_list end] + ns_log Notice "q-wiki.tcl(402) User attempting to write content without permission." + if { $read_p } { + set mode "v" + } else { + set mode "" + } + } + # end section of write + set next_mode "" + } + } +} else { + # form not posted + ns_log Warning "q-wiki.tcl(451): Form not posted. This shouldn't happen via index.vuh." +} + + +#set menu_list \[list \[list Q-Wiki index\]\] +set menu_list [list ] + +# OUTPUT / VIEW +# using switch, because there's only one view at a time +ns_log Notice "q-wiki.tcl(508): OUTPUT mode $mode" +switch -exact -- $mode { + l { + # list...... presents a list of pages (Branch this off as a procedure and/or lib page fragment to be called by view action) + if { $read_p } { + if { $redirect_before_v_p } { + ns_log Notice "q-wiki.tcl(587): redirecting to url $url for clean url view" + ad_returnredirect "$url?mode=l" + ad_script_abort + } + + ns_log Notice "q-wiki.tcl(427): mode = $mode ie. list of pages, index" + lappend menu_list [list label edit url ${url} mode e] + + append title " index" + # show page + # sort by template_id, columns + + set page_ids_list [qw_pages $package_id] + set pages_stats_lists [list ] + # we get the entire data set, 1 row(list) per page as table pages_stats_lists + foreach page_id $page_ids_list { + set stats_mod_list [list $page_id] + set stats_orig_list [qw_page_stats $page_id] + # a list: name, title, comments, keywords, description, template_id, flags, trashed, popularity, time last_modified, time created, user_id + foreach stat $stats_orig_list { + lappend stats_mod_list $stat + } + lappend stats_mod_list [qw_page_url_from_id $page_id] + # new: page_id, name, title, comments, keywords, description, template_id, flags, trashed, popularity, time last_modified, time created, user_id, url + lappend pages_stats_lists $stats_mod_list + } + set pages_stats_lists [lsort -index 2 $pages_stats_lists] + # build tables (list_of_lists) stats_list and their html filtered versions page_*_lists for display + set page_scratch_lists [list] + set page_stats_lists [list ] + set page_trashed_lists [list ] + + foreach stats_mod_list $pages_stats_lists { + set stats_list [lrange $stats_mod_list 0 2] + lappend stats_list [lindex $stats_mod_list 5] + lappend stats_list [lindex $stats_mod_list 3] + + set page_id [lindex $stats_mod_list 0] + set name [lindex $stats_mod_list 1] + set template_id [lindex $stats_mod_list 6] + set page_user_id [lindex $stats_mod_list 12] + set trashed_p [lindex $stats_mod_list 8] + set page_url [lindex $stats_mod_list 13] + + # convert stats_list for use with html + + # change Name to an active link and add actions if available + set active_link "$name" + set active_link_list [list $active_link] + set active_link2 "" + + if { $write_p } { + # trash the page + if { $trashed_p } { + set active_link2 " \"untrash\"" + } else { + set active_link2 " \"trash\"" + } + } elseif { $page_user_id == $user_id } { + # trash the revision + if { $trashed_p } { + set active_link2 " \"untrash\"" + } else { + set active_link2 " \"trash\"" + } + } + + if { $delete_p && $trashed_p } { + #append active_link2 "     \"delete\"   " + set form_id 2013-list-${template_id}-d + qf_form form_id $form_id action $page_url method post id 2013-list-${template_id}-d hash_check 1 + qf_input form_id $form_id type hidden name mode value d + qf_input form_id $form_id type hidden name next_mode value l + qf_input form_id $form_id type hidden name page_template_id value $template_id + qf_input form_id $form_id type submit value delete + qf_close form_id $form_id + append active_link2 "   [qf_read form_id $form_id]  " + + } + set stats_list [lreplace $stats_list 0 0 $active_link] + set stats_list [lreplace $stats_list 1 1 $active_link2] + + # add stats_list to one of the tables for display + if { $trashed_p && ( $write_p || $page_user_id eq $user_id ) } { + lappend page_trashed_lists $stats_list + } elseif { $trashed_p } { + # ignore this row, but track for errors + } else { + lappend page_stats_lists $stats_list + } + } + + # convert table (list_of_lists) to html table + set page_stats_sorted_lists $page_stats_lists + set page_stats_sorted_lists [linsert $page_stats_sorted_lists 0 [list Name " " Title Description Comments] ] + set page_tag_atts_list [list border 0 cellspacing 0 cellpadding 3] + set cell_formating_list [list ] + set page_stats_html [qss_list_of_lists_to_html_table $page_stats_sorted_lists $page_tag_atts_list $cell_formating_list] + # trashed table + if { [llength $page_trashed_lists] > 0 } { + set page_trashed_sorted_lists $page_trashed_lists + set page_trashed_sorted_lists [linsert $page_trashed_sorted_lists 0 [list Name " " Title Description Comments] ] + set page_tag_atts_list [list border 0 cellspacing 0 cellpadding 3] + + set page_trashed_html [qss_list_of_lists_to_html_table $page_trashed_sorted_lists $page_tag_atts_list $cell_formating_list] + } + } else { + # does not have permission to read. This should not happen. + ns_log Warning "q-wiki.tcl:(465) user did not get expected 404 error when not able to read page." + } + } + r { + # revisions...... presents a list of page revisions + lappend menu_list [list label index url index mode l] + + if { $write_p } { + ns_log Notice "q-wiki.tcl mode = $mode ie. revisions" + # build menu options + lappend menu_list [list label edit url ${url} mode e] + + # show page revisions + # sort by template_id, columns + set template_id $page_template_id_from_url + # these should be sorted by last_modified + set page_ids_list [qw_pages $package_id $user_id $template_id] + + set pages_stats_lists [list ] + # we get the entire data set, 1 row(list) per revision as table pages_stats_lists + # url is same for each + set page_id_active [qw_page_id_from_url $url $package_id] + foreach list_page_id $page_ids_list { + set stats_mod_list [list $list_page_id] + set stats_orig_list [qw_page_stats $list_page_id] + set page_list [qw_page_read $list_page_id] + # a list: name, title, comments, keywords, description, template_id, flags, trashed, popularity, time last_modified, time created, user_id + foreach stat $stats_orig_list { + lappend stats_mod_list $stat + } + lappend stats_mod_list $url + lappend stats_mod_list [string length [lindex $page_list 11]] + lappend stats_mod_list [expr { $list_page_id == $page_id_active } ] + # new: page_id, name, title, comments, keywords, description, template_id, flags, trashed, popularity, time last_modified, time created, user_id, url, content_length, active_revision + lappend pages_stats_lists $stats_mod_list + } + # build tables (list_of_lists) stats_list and their html filtered versions page_*_lists for display + set page_stats_lists [list ] + + # stats_list should contain page_id, user_id, size (string_length) ,last_modified, comments,flags, live_revision_p, trashed? , actions: untrash delete + + set contributor_nbr 0 + set contributor_last_id "" + set page_name [lindex [lindex $pages_stats_lists 0] 1] + append title "${page_name} - page revisions" + + foreach stats_mod_list $pages_stats_lists { + set stats_list [list] + # create these vars: + set index_list [list page_id 0 page_user_id 12 size 14 last_modified 10 created 11 comments 3 flags 7 live_revision_p 15 trashed_p 8] + foreach {list_item_name list_item_index} $index_list { + set list_item_value [lindex $stats_mod_list $list_item_index] + set $list_item_name $list_item_value + lappend stats_list $list_item_value + } + # convert stats_list for use with html + + set active_link "${page_id}" + set stats_list [lreplace $stats_list 0 0 $active_link] + + if { $page_user_id ne $contributor_last_id } { + set contributor_last_id $page_user_id + incr contributor_nbr + } + set contributor_title ${contributor_nbr} + set active_link3 "   ${contributor_title}" + set stats_list [lreplace $stats_list 1 1 $active_link3] + + if { $live_revision_p } { + # no links or actions. It's live, whatever its status + if { $trashed_p } { + set stats_list [lreplace $stats_list 7 7 "\"inactive\""] + } else { + set stats_list [lreplace $stats_list 7 7 "\"active\""] + } + } else { + if { $trashed_p } { + set stats_list [lreplace $stats_list 7 7 " "] + } else { + # it's untrashed, user can make it live. + set stats_list [lreplace $stats_list 7 7 "\"activate\""] + } + } + + set active_link_list [list $active_link] + set active_link2 "" + if { ( $write_p || $page_user_id == $user_id ) && $trashed_p } { + set active_link2 " \"untrash\"" + } elseif { $page_user_id == $user_id || $write_p } { + set active_link2 " \"trash\"" + } + if { ( $delete_p || $page_user_id == $user_id ) && $trashed_p } { +# append active_link2 "     \"delete\"   " + set form_id 2013-revisions-${page_id}-d + qf_form form_id $form_id action $url method post id 2013-revisions-${page_id}-d hash_check 1 + qf_input form_id $form_id type hidden name mode value d + qf_input form_id $form_id type hidden name next_mode value r + qf_input form_id $form_id type hidden name page_id value $page_id + qf_input form_id $form_id type submit value delete + qf_close form_id $form_id + append active_link2 "   [qf_read form_id $form_id]  " + + } + set stats_list [lreplace $stats_list 8 8 $active_link2] + + + + # if the user can delete or trash this stats_list, display it. + if { $write_p || $page_user_id eq $user_id } { + lappend page_stats_lists $stats_list + } + } + + # convert table (list_of_lists) to html table + set page_stats_sorted_lists $page_stats_lists + set page_stats_sorted_lists [linsert $page_stats_sorted_lists 0 [list "ID" "Contributor" "Length" "Last Modified" "Created" "Comments" "Flags" "Live?" "Trash status"] ] + set page_tag_atts_list [list border 0 cellspacing 0 cellpadding 3] + set cell_formating_list [list ] + set page_stats_html [qss_list_of_lists_to_html_table $page_stats_sorted_lists $page_tag_atts_list $cell_formating_list] + } else { + # does not have permission to read. This should not happen. + ns_log Warning "q-wiki.tcl:(465) user did not get expected 404 error when not able to read page." + } + + } + e { + + + if { $write_p } { + # edit...... edit/form mode of current context + + ns_log Notice "q-wiki.tcl mode = edit" + set cancel_link_html "Cancel" + + # for existing pages, add template_id + set conn_package_url [ad_conn package_url] + set post_url [file join $conn_package_url $url] + + ns_log Notice "q-wiki.tcl(636): conn_package_url $conn_package_url post_url $post_url" + if { $page_id_from_url ne "" && [llength $user_message_list ] == 0 } { + + # get page info + set page_list [qw_page_read $page_id_from_url $package_id $user_id ] + set page_name [lindex $page_list 0] + set page_title [lindex $page_list 1] + set keywords [lindex $page_list 2] + set description [lindex $page_list 3] + set page_template_id [lindex $page_list 4] + set page_flags [lindex $page_list 5] + set page_contents [lindex $page_list 11] + set page_comments [lindex $page_list 12] + + set page_bw_list [qwbw_page_read $page_id_from_url $package_id] + set model_ref [lindex $page_bw_list 0] + set spec1ref [lindex $page_bw_list 1] + set spec1default [lindex $page_bw_list 2] + set spec2ref [lindex $page_bw_list 3] + set spec2default [lindex $page_bw_list 4] + set spec3ref [lindex $page_bw_list 5] + set spec3default [lindex $page_bw_list 6] + set image_name [lindex $page_bw_list 7] + set image_width [lindex $page_bw_list 8] + set image_height [lindex $page_bw_list 9] + set thumbnail_name [lindex $page_bw_list 10] + set thumbnail_width [lindex $page_bw_list 11] + set thumbnail_height [lindex $page_bw_list 12] + set price [lindex $page_bw_list 13] + set dimensions [lindex $page_bw_list 14] + set ship_wt [lindex $page_bw_list 15] + set actual_wt [lindex $page_bw_list 16] + set unit [lindex $page_bw_list 17] + + set cancel_link_html "Cancel" + } + + append title "${page_name} - edit" + + set rows_list [split $page_contents "\n\r"] + set rows_max [llength $rows_list] + set columns_max 40 + foreach row $rows_list { + set col_len [string length $row] + if { $col_len > $columns_max } { + set columns_max $col_len + } + } + if { $rows_max > 200 } { + set rows_max [expr { int( sqrt( hypot( $columns_max, $rows_max ) ) ) } ] + } + set columns_max [f::min 200 $columns_max] + set rows_max [f::min 800 $rows_max] + set rows_max [f::max $rows_max 6] + + qf_form action $post_url method post id 20130309 hash_check 1 + qf_input type hidden value w name mode + qf_input type hidden value v name next_mode + qf_input type hidden value $page_flags name page_flags + qf_input type hidden value $page_template_id name page_template_id + # qf_input type hidden value $page_id name page_id label "" + qf_append html "

    Q-Wiki page edit

    " + qf_append html "
    " + set page_name_unquoted [ad_unquotehtml $page_name] + qf_input type text value $page_name_unquoted name page_name label "Name:" size 40 maxlength 40 + qf_append html "
    " + set page_title_unquoted [ad_unquotehtml $page_title] + qf_input type text value $page_title_unquoted name page_title label "Title:" size 40 maxlength 80 + qf_append html "
    " + set description_unquoted [ad_unquotehtml $description] + qf_textarea value $description_unquoted cols 40 rows 1 name description label "Description:" + qf_append html "
    " + set page_comments_unquoted [ad_unquotehtml $page_comments] + qf_textarea value $page_comments_unquoted cols 40 rows 3 name page_comments label "Comments:" + qf_append html "
    " + set page_contents_unquoted [ad_unquotehtml $page_contents] + qf_textarea value $page_contents_unquoted cols $columns_max rows $rows_max name page_contents label "Contents:" + qf_append html "
    " + set keywords_unquoted [ad_unquotehtml $keywords] + qf_input type text value $keywords_unquoted name keywords label "Keywords:" size 40 maxlength 80 + qf_append html "
    " + set model_ref_unquoted [ad_unquotehtml $model_ref] + qf_input type text value $model_ref_unquoted name model_ref label "Model ref:" size 40 maxlength 80 + qf_append html "
    " + set spec1ref_unquoted [ad_unquotehtml $spec1ref] + qf_input type text value $spec1ref_unquoted name spec1ref label "Spec1 ref:" size 40 maxlength 80 + qf_append html "
    " + set spec1default_unquoted [ad_unquotehtml $spec1default] + qf_input type text value $spec1default_unquoted name spec1default label "Spec1 default value:" size 40 maxlength 80 + qf_append html "
    " + set spec2ref_unquoted [ad_unquotehtml $spec2ref] + qf_input type text value $spec2ref_unquoted name spec2ref label "Spec2 ref:" size 40 maxlength 80 + qf_append html "
    " + set spec2default_unquoted [ad_unquotehtml $spec2default] + qf_input type text value $spec2default_unquoted name spec2default label "Spec2 default value:" size 40 maxlength 80 + qf_append html "
    " + set spec3ref_unquoted [ad_unquotehtml $spec3ref] + qf_input type text value $spec3ref_unquoted name spec3ref label "Spec3 ref:" size 40 maxlength 80 + qf_append html "
    " + set spec3default_unquoted [ad_unquotehtml $spec3default] + qf_input type text value $spec3default_unquoted name spec3default label "Spec3 default value:" size 40 maxlength 80 + qf_append html "
    " + set image_name_unquoted [ad_unquotehtml $image_name] + qf_input type text value $image_name_unquoted name image_name label "Image name:" size 40 maxlength 80 + qf_append html "
    " + set image_width_unquoted [ad_unquotehtml $image_width] + qf_input type text value $image_width_unquoted name image_width label "Image width:" size 40 maxlength 80 + qf_append html "
    " + set image_height_unquoted [ad_unquotehtml $image_height] + qf_input type text value $image_height_unquoted name image_height label "Image height:" size 40 maxlength 80 + qf_append html "
    " + set thumbnail_name_unquoted [ad_unquotehtml $thumbnail_name] + qf_input type text value $thumbnail_name_unquoted name thumbnail_name label "Thumbnail name:" size 40 maxlength 80 + qf_append html "
    " + set thumbnail_width_unquoted [ad_unquotehtml $thumbnail_width] + qf_input type text value $thumbnail_width_unquoted name thumbnail_width label "Thumbnail width:" size 40 maxlength 80 + qf_append html "
    " + set thumbnail_height_unquoted [ad_unquotehtml $thumbnail_height] + qf_input type text value $thumbnail_height_unquoted name thumbnail_height label "Thumbnail height:" size 40 maxlength 80 + qf_append html "
    " + set price_unquoted [ad_unquotehtml $price] + qf_input type text value $price_unquoted name price label "Price:" size 40 maxlength 80 + qf_append html "
    " + set dimensions_unquoted [ad_unquotehtml $dimensions] + qf_input type text value $dimensions_unquoted name dimensions label "Dimensions:" size 40 maxlength 80 + qf_append html "
    " + set ship_wt_unquoted [ad_unquotehtml $ship_wt] + qf_input type text value $ship_wt_unquoted name ship_wt label "Shipping weight:" size 40 maxlength 80 + qf_append html "
    " + set actual_wt_unquoted [ad_unquotehtml $actual_wt] + qf_input type text value $ship_wt_unquoted name ship_wt label "Actual weight:" size 40 maxlength 80 + qf_append html "
    Weight in decimal pounds, 5.5 for example.
    " + set unit_unquoted [ad_unquotehtml $unit] + qf_input type text value $unit_unquoted name unit label "Unit:" size 40 maxlength 80 +# qf_append html "
    " + + qf_append html "
    " + qf_input type submit value "Save" + qf_append html "       ${cancel_link_html}" + qf_close + set form_html [qf_read] + } else { + lappend user_message_list "Edit operation could not be completed. You don't have permission." + util_user_message -message [lindex $user_message_list end] + } + } + v { + # view page(s) (standard, html page document/report) + if { $read_p } { + # if $url is different than ad_conn url stem, 303/305 redirect to page_id's primary url + + if { $redirect_before_v_p } { + ns_log Notice "q-wiki.tcl(835): redirecting to url $url for clean url view" + ad_returnredirect $url + ad_script_abort + } + ns_log Notice "q-wiki.tcl(667): mode = $mode ie. view" + + lappend menu_list [list label index url index mode l] + + # get page info + if { $page_id eq "" } { + # cannot use previous $page_id_from_url, because it might be modified from an ACTION + # Get it again. + set page_id_from_url [qw_page_id_from_url $url $package_id] + set page_list [qw_page_read $page_id_from_url $package_id $user_id ] + set page_bw_list [qwbw_page_read $page_id_from_url $package_id] + } else { + set page_list [qw_page_read $page_id $package_id $user_id ] + set page_bw_list [qwbw_page_read $page_id $package_id] + } + + if { $create_p } { + if { $page_id_from_url ne "" || $page_id ne "" } { + lappend menu_list [list label revisions url ${url} mode r] + } + lappend menu_list [list label edit url ${url} mode e] + } + + if { [llength $page_list] > 1 } { + set page_title [lindex $page_list 1] + set keywords [lindex $page_list 2] + set description [lindex $page_list 3] + set page_contents [lindex $page_list 11] + set trashed_p [lindex $page_list 6] + set template_id [lindex $page_list 4] + # trashed pages cannot be viewed by public, but can be viewed with permission + if { $delete_p && $trashed_p } { + lappend menu_list [list label delete url ${url} mode d next_mode l page_template_id ${template_id}] + + } elseif { $delete_p && !$trashed_p } { + lappend menu_list [list label trash url ${url} mode t next_mode v page_template_id ${template_id}] + } + + if { $keywords ne "" } { + template::head::add_meta -name keywords -content $keywords + } + if { $description ne "" } { + template::head::add_meta -name description -content $description + } + set title $page_title + + # page_contents_filtered + set page_contents_unquoted [ad_unquotehtml $page_contents] + +#---- insert extended view +# When extending, you can insert values here, or reference with an include via q-wiki.adp +# such as this included example: +# alternately, one could treat the extended fields similar to the wiki ones. +# for this example, uncomment these lines: + + set model_ref [lindex $page_bw_list 0] +# set spec1ref [lindex $page_bw_list 1] +# set spec1default [lindex $page_bw_list 2] +# set spec2ref [lindex $page_bw_list 3] +# set spec2default [lindex $page_bw_list 4] +# set spec3ref [lindex $page_bw_list 5] +# set spec3default [lindex $page_bw_list 6] +# set image_name [lindex $page_bw_list 7] +# set image_width [lindex $page_bw_list 8] +# set image_height [lindex $page_bw_list 9] +# set thumbnail_name [lindex $page_bw_list 10] +# set thumbnail_width [lindex $page_bw_list 11] +# set thumbnail_height [lindex $page_bw_list 12] +# set price [lindex $page_bw_list 13] +# set dimensions [lindex $page_bw_list 14] +# set ship_wt [lindex $page_bw_list 15] +# set actual_wt [lindex $page_bw_list 16] +# set unit [lindex $page_bw_list 17] + +# append page_contents_unquoted "
    Model ref: $model_ref
    " +# append page_contents_unquoted "Spec1 ref: $spec1ref
    " +# append page_contents_unquoted "Spec1 default $spec1default
    " +# append page_contents_unquoted "Spec2 ref: $spec2ref
    " +# append page_contents_unquoted "Spec2 default: $spec2default
    " +# append page_contents_unquoted "Spec3 ref: $spec3ref
    " +# append page_contents_unquoted "Spec3 default $spec3default
    " +# append page_contents_unquoted "Image name: $image_name
    " +# append page_contents_unquoted "Image width: $image_width
    " +# append page_contents_unquoted "Image height: $image_height
    " +# append page_contents_unquoted "Thumbnail name: $thumbnail_name
    " +# append page_contents_unquoted "Thumbnail width: $thumbnail_width
    " +# append page_contents_unquoted "Thumbnail height: $thumbnail_height
    " +# append page_contents_unquoted "Price: $price
    " +# append page_contents_unquoted "Dimensions: $dimensions
    " +# append page_contents_unquoted "Ship wt: $ship_wt
    " +# append page_contents_unquoted "Actual wt: $actual_wt
    " +# append page_contents_unquoted "Unit: $unit
    " + +#---- end of extended view + + + + + set page_main_code [template::adp_compile -string $page_contents_unquoted] + set page_main_code_html [template::adp_eval page_main_code] + + + } + } else { + # no permission to read page. This should not happen. + ns_log Warning "q-wiki.tcl:(619) user did not get expected 404 error when not able to read page." + } + } + w { + # save..... (write) page_id + # should already have been handled above + ns_log Warning "q-wiki.tcl(575): mode = save/write THIS SHOULD NOT BE CALLED." + # it's called in validation section. + } + default { + # return 404 not found or not validated (permission or other issue) + # this should use the base from the config.tcl file + if { [llength $user_message_list ] == 0 } { + ns_returnnotfound + # rp_internal_redirect /www/global/404.adp + ad_script_abort + } + } +} +# end of switches + +# using OpenACS built-in util_get_user_messages feature +#set user_message_html "" +#foreach user_message $user_message_list { +# append user_message_html "
  • ${user_message}
  • " +#} + +set menu_html "" +set validated_p_exists [info exists validated_p] +if { $validated_p_exists && $validated_p || !$validated_p_exists } { + set menu_html "
      " + foreach item_list $menu_list { + set item_list_len [llength $item_list] + if { $item_list_len > 3 && [expr { ( $item_list_len / 2. ) - floor( $item_list_len / 2 ) } ] == 0 } { + # list pairs + # lindex $item_list 0 is label + set menu_label [lindex $item_list 1] + # lindex $item_list 2 is url + set menu_url [lindex $item_list 3] + set form_id "2013-${menu_label}" + if { $menu_label eq "delete" } { + qf_form form_id $form_id action $menu_url method post id 2013-$menu_label hash_check 1 + #qf_form action $menu_url method post id 2013-$menu_label hash_check 1 + } else { + # security_hash not significant or expected + qf_form form_id $form_id action $menu_url method post id 2013-$menu_label + #qf_form action $menu_url method post id 2013-$menu_label + } + foreach {menu_name menu_value} [lrange $item_list 4 end] { + qf_input form_id $form_id type hidden name $menu_name value $menu_value + #qf_input type hidden name $menu_name value $menu_value + } + qf_input form_id $form_id type submit value $menu_label + qf_close form_id $form_id + #qf_close + append menu_html "
    • [qf_read form_id $form_id]
    • " + # append menu_html "${menu_label}   " + } + } + append menu_html "
    " +} +set doc(title) $title +set context [list $title] Index: openacs-4/packages/q-wiki/www/doc/qwbw-wiki-procs-tcl.txt =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-wiki/www/doc/qwbw-wiki-procs-tcl.txt,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/q-wiki/www/doc/qwbw-wiki-procs-tcl.txt 2 Jan 2017 10:26:28 -0000 1.1 @@ -0,0 +1,148 @@ +ad_library { + + API for integrating bw with q-wiki + @creation-date 17 Jul 2012 + @cs-id $Id: +} + + +ad_proc -public qwbw_page_create { + instance_id + page_id + model_ref + spec1ref + spec1default + spec2ref + spec2default + spec3ref + spec3default + image_name + image_width + image_height + thumbnail_name + thumbnail_width + thumbnail_height + price + dimensions + ship_wt + actual_wt + unit +} { + Creates extension to wiki page. returns page_id, or 0 if error. instance_id is usually package_id +} { +# $template_id $page_id $model_ref $spec1ref $spec1default $spec2ref $spec2default $spec3ref $spec3default $image_name $image_width $image_height $thumbnail_name $thumbnail_width $thumbnail_height $price $dimensions $ship_wt $actual_wt $unit + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + set page_id_exists [db_0or1row qwbw_get_page_id "select page_id as page_id_fra_db from qwbw_catalog where instance_id = :instance_id and page_id = :page_id" ] + if { $page_id_exists } { + db_dml qwbw_wiki_page_update { update qwbw_catalog + set model_ref = :model_ref, + spec1ref =:spec1ref, + spec1default=:spec1default, + spec2ref =:spec2ref, + spec2default=:spec2default, + spec3ref =:spec3ref, + spec3default =:spec3default, + image_name =:image_name, + image_width=:image_width, + image_height=:image_height, + thumbnail_name=:thumbnail_name, + thumbnail_width=:thumbnail_width, + thumbnail_height=:thumbnail_height, + price=:price, + dimensions=:dimensions, + ship_wt=:ship_wt, + actual_wt=:actual_wt, + unit=:unit + where instance_id = :instance_id and page_id = :page_id } + + } else { + db_dml qwbw_wiki_page_create { insert into qwbw_catalog + (instance_id, page_id, model_ref, spec1ref, spec1default, spec2ref, spec2default, spec3ref, spec3default, image_name, image_width, image_height, thumbnail_name, thumbnail_width, thumbnail_height, price, dimensions, ship_wt, actual_wt, unit) + values (:instance_id,:page_id,:model_ref,:spec1ref,:spec1default,:spec2ref,:spec2default,:spec3ref,:spec3default,:image_name,:image_width,:image_height,:thumbnail_name,:thumbnail_width,:thumbnail_height,:price,:dimensions,:ship_wt,:actual_wt,:unit ) } + } + return 1 +} + + +ad_proc -public qwbw_page_read { + page_id + {instance_id ""} +} { + Returns page contents of page_id. Returns page as list of attribute values: model_ref, spec1ref, spec1default, spec2ref, spec2default, spec3ref, spec3default, image_name, image_width, image_height, thumbnail_name, thumbnail_width, thumbnail_height, price, dimensions, ship_wt, actual_wt, unit +} { + #set page_bw_list \[qwbw_page_read $page_id \] +# $model_ref $spec1ref $spec1default $spec2ref $spec2default $spec3ref $spec3default $image_name $image_width $image_height $thumbnail_name $thumbnail_width $thumbnail_height $price $dimensions $ship_wt $actual_wt $unit + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + set return_list_of_lists [db_list_of_lists qwbw_wiki_page_get { select model_ref, spec1ref, spec1default, spec2ref, spec2default, spec3ref, spec3default, image_name, image_width, image_height, thumbnail_name, thumbnail_width, thumbnail_height, price, dimensions, ship_wt, actual_wt, unit from qwbw_catalog where page_id = :page_id and instance_id = :instance_id } ] + # convert return_lists_of_lists to return_list + set return_list [lindex $return_list_of_lists 0] + return $return_list +} + +ad_proc -public qwbw_page_write { + instance_id + page_id + model_ref + spec1ref + spec1default + spec2ref + spec2default + spec3ref + spec3default + image_name + image_width + image_height + thumbnail_name + thumbnail_width + thumbnail_height + price + dimensions + ship_wt + actual_wt + unit +} { + Creates extension to wiki page. returns page_id, or 0 if error. instance_id is usually package_id +} { +# $template_id $page_id $model_ref $spec1ref $spec1default $spec2ref $spec2default $spec3ref $spec3default $image_name $image_width $image_height $thumbnail_name $thumbnail_width $thumbnail_height $price $dimensions $ship_wt $actual_wt $unit + if { $instance_id eq "" } { + # set instance_id package_id + set instance_id [ad_conn package_id] + } + set page_id_exists [db_0or1row qwbw_get_page_id "select page_id as page_id_fra_db from qwbw_catalog where instance_id = :instance_id and page_id = :page_id" ] + if { $page_id_exists } { + db_dml qwbw_wiki_page_update { update qwbw_catalog + set model_ref = :model_ref, + spec1ref =:spec1ref, + spec1default=:spec1default, + spec2ref =:spec2ref, + spec2default=:spec2default, + spec3ref =:spec3ref, + spec3default =:spec3default, + image_name =:image_name, + image_width=:image_width, + image_height=:image_height, + thumbnail_name=:thumbnail_name, + thumbnail_width=:thumbnail_width, + thumbnail_height=:thumbnail_height, + price=:price, + dimensions=:dimensions, + ship_wt=:ship_wt, + actual_wt=:actual_wt, + unit=:unit + where instance_id = :instance_id and page_id = :page_id } + + } else { + db_dml qwbw_wiki_page_create { insert into qwbw_catalog + (instance_id, page_id, model_ref, spec1ref, spec1default, spec2ref, spec2default, spec3ref, spec3default, image_name, image_width, image_height, thumbnail_name, thumbnail_width, thumbnail_height, price, dimensions, ship_wt, actual_wt, unit) + values (:instance_id,:page_id,:model_ref,:spec1ref,:spec1default,:spec2ref,:spec2default,:spec3ref,:spec3default,:image_name,:image_width,:image_height,:thumbnail_name,:thumbnail_width,:thumbnail_height,:price,:dimensions,:ship_wt,:actual_wt,:unit ) } + } + return 1 +} + +