Index: openacs-4/packages/xowiki/tcl/package-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/package-procs.tcl,v diff -u -r1.7 -r1.8 --- openacs-4/packages/xowiki/tcl/package-procs.tcl 10 Aug 2006 01:14:41 -0000 1.7 +++ openacs-4/packages/xowiki/tcl/package-procs.tcl 17 Aug 2006 01:44:26 -0000 1.8 @@ -1,123 +1,171 @@ namespace eval ::xowiki { - Class create Package -parameter {{folder_id 0} url package_url {use_ns_conn 1}} + ::xo::PackageMgr create Package \ + -superclass ::xo::Package \ + -parameter {{folder_id "[::xo::cc query_parameter folder_id 0]"}} - #Package instproc create {name args} {if {![my isobject $name]} {next}} - - Package proc process_query {{-defaults ""}} { - my instvar queryparm form_parameter - array unset queryparm - array unset form_parameter - array set queryparm $defaults - - set query [ns_conn query] - foreach querypart [split $query &] { - set att_val [split $querypart =] - if {[llength $att_val] == 1} { - set queryparm([ns_urldecode [lindex $att_val 0]]) 1 - } else { - set queryparm([ns_urldecode [lindex $att_val 0]]) \ - [ns_urldecode [lindex $att_val 1]] - } - } - foreach key [array names queryparm] {uplevel [list set $key $queryparm($key)]} - } - - Package proc instantiate_page_from_id {{-revision_id 0} {-item_id 0}} { + Package ad_proc instantiate_page_from_id { + {-revision_id 0} + {-item_id 0} + {-user_id -1} + {-parameter ""} + } { + Instantiate a page in situations, where the context is not set up + (e.g. we have no package object or folder obect). This call is convenient + when testing e.g. from the developer shell + } { + #TODO can most probably further simplified set page [::Generic::CrItem instantiate -item_id $item_id -revision_id $revision_id] - set folder_id [$page set parent_id] - set package_id [db_string get_pid "select package_id from cr_folders where folder_id = $folder_id"] - $page set package_id $package_id - my create ::$package_id -folder_id $folder_id -use_ns_conn false - ::$package_id set_url -url [Page pretty_link -package_id $package_id [$page name]] + my log "--I instantiate i=$item_id revision_id=$revision_id page=$page" + $page folder_id [$page set parent_id] + set package_id [$page set package_id] + ::xowiki::Package initialize \ + -package_id $package_id -user_id $user_id \ + -parameter $parameter -init_url false -actual_query "" + ::$package_id set_url -url [::$package_id pretty_link [$page name]] return $page } - Package proc get_url_from_id {{-item_id 0} {-revision_id 0}} { - set page [::xowiki::Package instantiate_page_from_id -item_id $item_id -revision_id $revision_id] + Package ad_proc get_url_from_id {{-item_id 0} {-revision_id 0}} { + Get the full URL from a page in situations, where the context is not set up. + @see instantiate_page_from_id + } { + set page [::xowiki::Package instantiate_page_from_id \ + -item_id $item_id -revision_id $revision_id] $page volatile return [::[$page package_id] url] } - Package instproc init args { - my instvar id - set id [namespace tail [self]] - my package_url [site_node::get_url_from_object_id -object_id $id] - my set policy ::xowiki::policy1 ;# hard-coded for now, could be made configurable - my require_folder_object - if {[my use_ns_conn]} {my set_url -url [ns_conn url]} + # + # URL and naming management + # + + Package instproc normalize_name {string} { + set string [string trim $string] + # if subst_blank_in_name is turned on, turn spaces into _ + if {[my get_parameter subst_blank_in_name 1] != 0} { + regsub -all { +} $string "_" string + } + return $string } + + Package instproc pretty_link { + {-absolute:boolean false} {-lang ""} name + } { + #my log "--u name=<$name>" + if {$lang eq ""} { + if {![regexp {^(..):(.*)$} $name _ lang name]} { + regexp {^(file|image):(.*)$} $name _ lang name + } + } + if {$lang eq "" && ![regexp {^(:|(file|image))} $name]} { + #my log "--u name=<$name> need lang" + set lang [string range [lang::conn::locale -package_id [my id]] 0 1] + } - Package instproc set_url {-url} { - my instvar id - my url $url - my set object [string range [my url] [string length [my package_url]] end] - my log "--url=[my url] package_url=[my package_url] package_id=$id fo=[my folder_id]" + set host [expr {$absolute ? [ad_url] : ""}] + if {$lang ne ""} { + return $host[my package_url]$lang/[ad_urlencode $name] + } else { + return $host[my package_url][ad_urlencode $name] + } } + Package instproc init {} { + next + my require_folder_object + my set policy [my get_parameter security_policy ::xowiki::policy1] + } + Package instproc get_parameter {attribute {default ""}} { - my instvar id folder_id - set value [$folder_id get_payload $attribute] - if {$value eq ""} { - set value [parameter::get -parameter $attribute -package_id $id -default $default] - } + set value [::[my folder_id] get_payload $attribute] + if {$value eq ""} {set value [next]} return $value } Package instproc invoke {-method} { - my instvar object folder_id id policy my set mime_type text/html my set delivery ns_return - my log "--object = '$object'" + set page [my resolve_page [my set object] method] + if {$page ne ""} { + return [my call $page $method] + } else { + return [my error_msg "No page '[my set object]' available."] + #ad_returnredirect "[my package_url]admin/list" + } + } + + Package instproc error_msg {error_msg} { + my instvar id + set template_file error-template + if {![regexp {^[./]} $template_file]} { + set template_file /packages/xowiki/www/$template_file + } + set context [list [$id instance_name]] + set title Error + $id return_page -adp $template_file -variables { + context title error_msg + } + } + + Package instproc resolve_page {object method_var} { + upvar $method_var method + my instvar folder_id id policy if {$object eq ""} { set exported [$policy defined_methods Package] foreach m $exported { - if {[my exists_query_parameter $m]} { - return [my call $policy [self] $m] - } + #my log "--QP my exists_query_parameter $m = [my exists_query_parameter $m]" + if {[::xo::cc exists_query_parameter $m]} { + set method $m ;# the only reason for the upvar + return [self] + } } } if {$object eq ""} { - # we should change this to the new interface with query_parameter - #if {[ns_queryget summary] eq ""} {rp_form_put summary 1} - #set object [$id get_parameter weblog_page "en:weblog"] - #ad_returnredirect "admin/list" + # we have no object, but as well no method callable on the package set object index } set page [my resolve_request -path $object] if {$page ne ""} { - return [my call $policy $page $method] + return $page } + # try standard page set standard_page [$id get_parameter ${object}_page] - my log "--standard page '$standard_page' from ${object}_page" if {$standard_page ne ""} { set page [my resolve_request -path $standard_page] if {$page ne ""} { - my log "--found standard page $standard_page => $page" - return [my call $policy $page $method] + return $page } } else { - set standard_page "en:index" + regexp {../([^/]+)$} $object _ object + set standard_page "en:$object" } - set fn [get_server_root]/packages/xowiki/www/default-pages/$object.page + + my log "--W object='$object'" + set fn [get_server_root]/packages/xowiki/www/prototypes/$object.page if {[file readable $fn]} { # create from default page my log "--sourcing page definition $fn" set page [source $fn] - $page configure -volatile -name $standard_page \ - -title $object -parent_id $folder_id -package_id $id \ - -text [list [string map [list >> "\n
>>" << "<<\n"] \ - [string trim [$page text] " \n"]] text/html] + $page configure -name $standard_page \ + -parent_id $folder_id -package_id $id + if {![$page exists title]} { + $page set title $object + } + $page destroy_on_cleanup + $page set_content [string trim [$page text] " \n"] + $page initialize_loaded_object $page save_new - return [my call $policy $page $method] + return $page } else { - ad_returnredirect "[my package_url]admin/list" + my log "no prototype for '$object' found" + return "" } } - Package instproc call {policy object method} { - my log "--p $policy check_permissions $object $method = [$policy check_permissions $object $method] delivery=[my set delivery]" + Package instproc call {object method} { + my instvar policy if {[$policy check_permissions $object $method]} { my log "--p calling $object ([$object info class]) '$method'" $object $method @@ -138,52 +186,44 @@ my log "--try $path -> $item_id" if {$item_id == 0} { - if {[regexp {^pages/(..)/(.*)$} $path _ lang local_name]} { - } elseif {[regexp {^(..)/(.*)$} $path _ lang local_name]} { - } elseif {[regexp {^(..):(.*)$} $path _ lang local_name]} { - } elseif {[regexp {^(file|image)/(.*)$} $path _ lang local_name]} { - } else { - set key queryparm(lang) - set lang [expr {[info exists $key] ? [set $key] : \ - [string range [lang::conn::locale] 0 1]}] - set local_name $path - } - set name ${lang}:$local_name - if {[info exists name]} { - set item_id [::Generic::CrItem lookup -name $name -parent_id $folder_id] - my log "--try $name -> $item_id" - } - if {$item_id == 0} { - set nname [Page normalize_name -package_id [my set id] $name] - set item_id [::Generic::CrItem lookup -name $nname -parent_id $folder_id] - my log "--try $nname -> $item_id" - } + if {[regexp {^pages/(..)/(.*)$} $path _ lang local_name]} { + } elseif {[regexp {^(..)/(.*)$} $path _ lang local_name]} { + } elseif {[regexp {^(..):(.*)$} $path _ lang local_name]} { + } elseif {[regexp {^(file|image)/(.*)$} $path _ lang local_name]} { + } else { + set key queryparm(lang) + set lang [expr {[info exists $key] ? [set $key] : \ + [string range [lang::conn::locale] 0 1]}] + set local_name $path + } + set name ${lang}:$local_name + if {[info exists name]} { + set item_id [::Generic::CrItem lookup -name $name -parent_id $folder_id] + my log "--try $name -> $item_id" + } + if {$item_id == 0} { + set nname [my normalize_name $name] + set item_id [::Generic::CrItem lookup -name $nname -parent_id $folder_id] + my log "--try $nname -> $item_id" + } } } if {$item_id != 0} { - set key queryparm(revision_id) - if {[info exists $key]} {set revision_id [set $key]} - if {[info exists revision_id]} { - set item_id 0 - } else { - set revision_id 0 - } - my log "--instantiate item_id $item_id revision_id $revision_id" + set revision_id [my query_parameter revision_id 0] + set [expr {$revision_id ? "item_id" : "revision_id"}] 0 + #my log "--instantiate item_id $item_id revision_id $revision_id" set r [::Generic::CrItem instantiate -item_id $item_id -revision_id $revision_id] - my log "--instantiate done " + #my log "--instantiate done CONTENT\n[$r serialize]" $r set package_id [namespace tail [self]] return $r } else { return "" } } - Package instproc require_folder_object { - {-store_folder_id:boolean true} - } { + Package instproc require_folder_object { } { my instvar id folder_id - # the flag store_folder_id should not be necessary, when the id is - # always stored in the package TODO + my log "--f [::xotcl::Object isobject ::$folder_id] folder_id=$folder_id" if {$folder_id == 0} { set folder_id [::xowiki::Page require_folder -name xowiki -package_id $id] @@ -192,42 +232,39 @@ if {![::xotcl::Object isobject ::$folder_id]} { # if we can't get the folder from the cache, create it if {[catch {eval [nsv_get xotcl_object_cache ::$folder_id]}]} { - while {1} { - set item_id [ns_cache eval xotcl_object_type_cache item_id-of-$folder_id { - set myid [CrItem lookup -name ::$folder_id -parent_id $folder_id] - if {$myid == 0} break; # don't cache ID - return $myid - }] - break - } - if {[info exists item_id]} { - # we have a valid item_id and get the folder object - #my log "--f fetch folder object -object ::$folder_id -item_id $item_id" - ::xowiki::Object fetch_object -object ::$folder_id -item_id $item_id - } else { - # we have no folder object yet. so we create one... - ::xowiki::Object create ::$folder_id - ::$folder_id set text "# this is the payload of the folder object\n\n\ - set index_page \"en:index\"\n" - ::$folder_id set parent_id $folder_id - ::$folder_id set name ::$folder_id - ::$folder_id set title ::$folder_id - ::$folder_id set package_id $id - ::$folder_id save_new - ::$folder_id initialize_loaded_object - } + while {1} { + set item_id [ns_cache eval xotcl_object_type_cache item_id-of-$folder_id { + set myid [CrItem lookup -name ::$folder_id -parent_id $folder_id] + if {$myid == 0} break; # don't cache ID if invalid + return $myid + }] + break + } + if {[info exists item_id]} { + # we have a valid item_id and get the folder object + #my log "--f fetch folder object -object ::$folder_id -item_id $item_id" + ::xowiki::Object fetch_object -object ::$folder_id -item_id $item_id + } else { + # we have no folder object yet. so we create one... + ::xowiki::Object create ::$folder_id + ::$folder_id set text "# this is the payload of the folder object\n\n\ + set index_page \"en:index\"\n" + ::$folder_id set parent_id $folder_id + ::$folder_id set name ::$folder_id + ::$folder_id set title ::$folder_id + ::$folder_id set package_id $id + ::$folder_id save_new + ::$folder_id initialize_loaded_object + } } - #$o proc destroy {} {my log "--f "; next} + #::$folder_id proc destroy {} {my log "--f "; next} ::$folder_id set package_id $id - uplevel #0 [list ::$folder_id volatile] + ::$folder_id destroy_on_cleanup } else { #my log "--f reuse folder object $folder_id [::Serializer deepSerialize ::$folder_id]" } - if {$store_folder_id} { - Page set folder_id $folder_id - } - + my set folder_id $folder_id } @@ -236,22 +273,22 @@ set __vars [list] foreach _var $variables { if {[llength $_var] == 2} { - lappend __vars [lindex $_var 0] [uplevel subst [lindex $_var 1]] + lappend __vars [lindex $_var 0] [uplevel subst [lindex $_var 1]] } else { - set localvar local.$_var - upvar $_var $localvar - if {[info exists $localvar]} { - # ignore undefined variables - lappend __vars $_var [set $localvar] - } + set localvar local.$_var + upvar $_var $localvar + if {[info exists $localvar]} { + # ignore undefined variables + lappend __vars $_var [set $localvar] + } } } if {[info exists form]} { set level [template::adp_level] foreach f [uplevel #$level info vars ${form}:*] { - lappend __vars &$f $f - upvar #$level $f $f + lappend __vars &$f $f + upvar #$level $f $f } } my log "--before adp" ;#$__vars @@ -260,60 +297,68 @@ return $text } - Package instproc query_parameter {name {default ""}} { - [self class] instvar queryparm - return [expr {[info exists queryparm($name)] ? $queryparm($name) : $default}] - } - Package instproc exists_query_parameter {name} { - [self class] exists queryparm($name) - } - Package instproc form_parameter {name {default ""}} { - [self class] instvar form_parameter - if {![info exists form_parameter]} {array set form_parameter [ns_set array [ns_getform]]} - return [expr {[info exists form_parameter($name)] ? $form_parameter($name) : $default}] - } - Package instproc exists_form_parameter {name} { - [self class] instvar form_parameter - if {![info exists form_parameter]} {array set form_parameter [ns_set array [ns_getform]]} - [self class] exists form_parameter($name) - } - - Package ad_instproc reindex {} { reindex all items of this package } { my instvar folder_id - db_foreach get_pages "select page_id from xowiki_page, cr_revisions r, cr_items i \ - where page_id = r.revision_id and i.item_id = r.item_id and i.parent_id = $folder_id \ - and i.live_revision = page_id" { - #search::queue -object_id $page_id -event DELETE - search::queue -object_id $page_id -event INSERT - } + set pages [db_list get_pages "select page_id from xowiki_page, cr_revisions r, cr_items i \ + where page_id = r.revision_id and i.item_id = r.item_id and i.parent_id = $folder_id \ + and i.live_revision = page_id"] + foreach page_id $pages { + #search::queue -object_id $page_id -event DELETE + search::queue -object_id $page_id -event INSERT + } } Package instproc rss {} { my instvar id set cmd [list ::xowiki::Page rss -package_id $id] - set rss [my query_parameter rss] - if {[regexp {[^0-9]*([0-9]+)d} $rss _ days]} {lappend cmd -days $days} + if {[regexp {[^0-9]*([0-9]+)d} [my query_parameter rss] _ days]} { + lappend cmd -days $days + } eval $cmd } Package instproc edit-new {} { my instvar folder_id id set object_type [my query_parameter object_type "::xowiki::Page"] set page [$object_type new -volatile -parent_id $folder_id -package_id $id] - set html [$page edit -new true] - my log "--e html length [string length $html]" - return $html + return [$page edit -new true] } + + Package instproc delete {-item_id -name} { + my instvar folder_id id + if {![info exists item_id]} { + set item_id [my query_parameter item_id] + my log "--D item_id from query parameter $item_id" + set name [my query_parameter name] + } + if {$item_id ne ""} { + my log "--D trying to delete $item_id $name" + ::Generic::CrItem delete -item_id $item_id + ns_cache flush xotcl_object_cache ::$item_id + # we should probably flush as well cached revisions + if {$name eq "::$folder_id"} { + my log "--D deleting folder object ::$folder_id" + ns_cache flush xotcl_object_cache ::$folder_id + ns_cache flush xotcl_object_type_cache item_id-of-$folder_id + ::$folder_id destroy + } + set key link-*-$name-$folder_id + foreach n [ns_cache names xowiki_cache $key] {ns_cache flush xowiki_cache $n} + } else { + my log "--D nothing to delete!" + } + ad_returnredirect [my query_parameter "return_url" [$id package_url]] + } + Package instproc condition {method attr value} { switch $attr { has_class {set result [expr {[my query_parameter object_type ""] eq $value}]} default {set result 0} } - my log "--c [self args] returns $result" + #my log "--c [self args] returns $result" return $result } @@ -329,23 +374,27 @@ if {![my isclass $c]} continue set key require_permission($method) if {[$c exists $key]} { - set permission [$c set $key] - if {$permission eq "login" || $permission eq "none"} { - return 1 - } - foreach cond_permission $permission { - my log "--cond_permission = $cond_permission" - switch [llength $cond_permission] { - 3 {foreach {condition attribute privilege} $cond_permission break - if {[eval $object condition $method $condition]} break - } - 2 {foreach {attribute privilege} $cond_permission break - break - } - } - } - my log "--p checking permission::permission_p -object_id [$object set $attribute] -privilege $privilege" - return [permission::permission_p -object_id [$object set $attribute] -privilege $privilege] + set permission [$c set $key] + if {$permission eq "login" || $permission eq "none"} { + return 1 + } + if {$permission eq "swa"} { + return [acs_user::site_wide_admin_p] + } + foreach cond_permission $permission { + #my log "--cond_permission = $cond_permission" + switch [llength $cond_permission] { + 3 {foreach {condition attribute privilege} $cond_permission break + if {[eval $object condition $method $condition]} break + } + 2 {foreach {attribute privilege} $cond_permission break + break + } + } + } + set id [$object set $attribute] + #my log "--p checking permission::permission_p -object_id $id -privilege $privilege" + return [::xo::cc permission -object_id $id -privilege $privilege] } } return 0 @@ -358,29 +407,47 @@ if {![my isclass $c]} continue set key require_permission($method) if {[$c exists $key]} { - set permission [$c set $key] - puts "checking $permission for $c $key" - switch $permission { - none {set allowed 1; break} - login {auth::require_login; set allowed 1; break} - default { - foreach cond_permission $permission { - my log "--c check $cond_permission" - switch [llength $cond_permission] { - 3 {foreach {condition attribute privilege} $cond_permission break - if {[eval $object condition $method $condition]} break - } - 2 {foreach {attribute privilege} $cond_permission break - break - } - } - } - my log "--c require_permission -object_id [$object set $attribute] -privilege $privilege" - permission::require_permission -object_id [$object set $attribute] -privilege $privilege - set allowed 1 - break - } - } + set permission [$c set $key] + my log "checking $permission for $c $key" + switch $permission { + none {set allowed 1; break} + login {auth::require_login; set allowed 1; break} + swa { + set allowed [acs_user::site_wide_admin_p] + if {!$allowed} { + ad_return_warning "Insufficient Permissions" \ + "Only side wide admins are allowed for this operation!" + ad_script_abort + } + } + default { + foreach cond_permission $permission { + my log "--c check $cond_permission" + switch [llength $cond_permission] { + 3 {foreach {condition attribute privilege} $cond_permission break + if {[eval $object condition $method $condition]} break + } + 2 {foreach {attribute privilege} $cond_permission break + break + } + } + } + set id [$object set $attribute] + #my log "--c require_permission -object_id $id -privilege $privilege" + set p [::xo::cc permission -object_id $id -privilege $privilege] + if {!$p} { + ns_log notice "permission::require_permission: [::xo::cc user_id]doesn't \ + have $privilege on object $id" + ad_return_forbidden "Permission Denied" "
+ You don't have permission to $privilege [$object name]. +
" + ad_script_abort + } + #permission::require_permission -object_id $id -privilege $privilege + set allowed 1 + break + } + } } } return $allowed @@ -391,8 +458,9 @@ Policy policy1 -contains { Class Package -array set require_permission { - reindex {{id admin}} + reindex swa rss none + delete {{id admin}} edit-new {{{has_class ::xowiki::Object} id admin} {id create}} } @@ -414,5 +482,38 @@ download {{package_id read}} } } + + + Policy policy2 -contains { + # + # we require side wide admin rights for deletions + # + + Class Package -array set require_permission { + reindex {{id admin}} + rss none + delete swa + edit-new {{{has_class ::xowiki::Object} id admin} {id create}} + } + + Class Page -array set require_permission { + view {{package_id read}} + revisions {{package_id write}} + edit {{package_id write}} + make-live-revision {{package_id write}} + delete-revision swa + delete swa + save-tags login + popular-tags login + } + + Class Object -array set require_permission { + edit {{package_id admin}} + } + Class File -array set require_permission { + download {{package_id read}} + } + } + }