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.332.2.15 -r1.332.2.16 --- openacs-4/packages/xowiki/tcl/package-procs.tcl 25 Jun 2019 11:27:20 -0000 1.332.2.15 +++ openacs-4/packages/xowiki/tcl/package-procs.tcl 26 Jun 2019 11:07:19 -0000 1.332.2.16 @@ -232,7 +232,13 @@ } - Package instproc get_parent_and_name {-path:required -lang:required -parent_id:required vparent vlocal_name} { + Package instproc get_parent_and_name { + -path:required + -lang:required + -parent_id:required + vparent + vlocal_name + } { :upvar $vparent parent $vlocal_name local_name if {[regexp {^([^/]+)/(.+)$} $path _ parent local_name]} { @@ -442,6 +448,7 @@ {-context_url ""} {-folder_ids ""} {-path_encode:boolean true} + {-page ""} name } { @@ -460,7 +467,7 @@ #:msg "input name=$name, lang=$lang parent_id=$parent_id" set default_lang [:default_language] - :get_lang_and_name -default_lang $lang -name $name lang stripped_name + :get_lang_and_name -default_lang $lang -name $name lang name set host [expr {$absolute ? ($siteurl ne "" ? $siteurl : [ad_url]) : ""}] if {$anchor ne ""} {set anchor \#$anchor} @@ -508,10 +515,31 @@ # } #:log "h=${host}, prefix=${package_prefix}, folder=$folder, name=$encoded_name anchor=$anchor download=$download" - #:msg folder=$folder,lang=$lang,default_lang=$default_lang + + # + # Lookup plain page name. If we succeed, there is a danger of a + # name clash between a folder and a language prefixed page. In + # case, the lookup succeeds, add a language prefix to the page, + # although it could be omitted otherwise. This way, we can + # disambiguate between a folder named "foo" and a page named + # "en:foo" in the same folder. + # + # Note: such a naming disambiguation is probably needed in the + # general case as well on path segments, when arbitrary objects + # can have children and same-named folders exist. + # + set found_id [:lookup -parent_id $parent_id -name $name] + if {$found_id != 0 && $page ne ""} { + #:log "named page named <$name> exists, $page is folder: [$page is_folder_page], path <$folder>" + if {[$page is_folder_page]} { + :log "... on the folder page." + set found_id 0 + } + } + #:log "-pretty_link: found_id=$found_id name=$name,folder=$folder,lang=$lang,default_lang=$default_lang" if {$download} { # - # use the special download (file) syntax + # Use the special download (file) syntax. # set url ${host}${package_prefix}download/file/$folder$encoded_name$query$anchor } elseif {$lang ne $default_lang || [[self class] exists www-file($name)]} { @@ -520,9 +548,11 @@ # language prefix # set url ${host}${package_prefix}${lang}/$folder$encoded_name$query$anchor + } elseif {$found_id != 0} { + set url ${host}${package_prefix}$folder${lang}:$encoded_name$query$anchor } else { # - # Use the short notation without language prefix + # Use the short notation without language prefix. # set url ${host}${package_prefix}$folder$encoded_name$query$anchor } @@ -1051,7 +1081,7 @@ set lang [:default_language] :log "no lang specified for '$object', use default_language <$lang>" } - #:log "resolve_page '$object', default-lang $lang" + #:log "--o resolve_page '$object', default-lang $lang" # # First, resolve package level methods, @@ -1107,6 +1137,7 @@ #:log "item_info_from_url returns [array get {}]" } + #:log "object <$object>" if {$(item_id) == 0 && [:get_parameter fallback_languages ""] ne ""} { foreach fallback_lang [:get_parameter fallback_languages ""] { if {$fallback_lang ne $lang} { @@ -1277,21 +1308,31 @@ } - Package instproc prefixed_lookup {{-default_lang ""} -lang:required -stripped_name:required -parent_id:required} { + Package instproc prefixed_lookup { + {-default_lang ""} + -lang:required + -stripped_name:required + -parent_id:required + } { # todo unify with package->lookup # # This method tries a direct lookup of stripped_name under # parent_id followed by a prefixed lookup. The direct lookup is # only performed, when $default-lang == $lang. The prefixed lookup # might change lang in the result set. # + # Note that the "stripped_name" should be called "local_name" (or + # path segment), since it might contain language prefixes as well. + # # @return item-ref info # + #:log "incoming stripped name <$stripped_name>" set item_id 0 if {$lang eq $default_lang || [string match "*:*" $stripped_name]} { # try a direct lookup; ($lang eq "file" needed for links to files) set item_id [::xo::db::CrClass lookup -name $stripped_name -parent_id $parent_id] + #:log "direct lookup of <$stripped_name> -> $item_id" if {$item_id != 0} { set name $stripped_name regexp {^(..):(.+)$} $name _ lang stripped_name @@ -1314,6 +1355,8 @@ } if {$item_id == 0} { + #:log "last chance stripped name <$stripped_name>" + :get_lang_and_name -default_lang $lang -name $stripped_name lang stripped_name set name ${lang}:$stripped_name set item_id [::xo::db::CrClass lookup -name $name -parent_id $parent_id] #:log "comp $name" @@ -1675,13 +1718,14 @@ } if {$default_lang eq ""} {set default_lang [:default_language]} :get_lang_and_name -default_lang $default_lang -path $url (lang) stripped_url + :log "get_lang_and_name -default_lang $default_lang -path $url -> $(lang) '$stripped_url'" + set (parent_id) [:get_parent_and_name \ -lang $(lang) -path $stripped_url \ -parent_id [:folder_id] \ - parent (stripped_name)] + parent local_name] + #:log "get_parent_and_name '$stripped_url' returns [array get {}]" - #:msg "get_parent_and_name '$stripped_url' returns [array get {}]" - if {![regexp {^(download)/(.+)$} $(lang) _ (method) (lang)]} { set (method) "" # The lang value "tag" is used for allowing tag-URLs without @@ -1707,15 +1751,15 @@ } set tag_kind [expr {$popular ? "ptag" :"tag"}] set weblog_page [:get_parameter weblog_page] - :get_lang_and_name -default_lang $default_lang -name $weblog_page (lang) (stripped_name) - #set name $(lang):$(stripped_name) + :get_lang_and_name -default_lang $default_lang -name $weblog_page (lang) local_name set :object $weblog_page ::xo::cc set actual_query $tag_kind=$tag&summary=$summary } } array set "" [:prefixed_lookup -parent_id $(parent_id) \ - -default_lang $default_lang -lang $(lang) -stripped_name $(stripped_name)] - #:log "prefixed_lookup '$(stripped_name)' returns [array get {}]" + -default_lang $default_lang -lang $(lang) \ + -stripped_name $local_name] + #:log "prefixed_lookup '$local_name' returns [array get {}]" if {$(item_id) == 0} { # @@ -1742,6 +1786,7 @@ # } } + #:log "final returns [array get {}]" return [array get ""] } Index: openacs-4/packages/xowiki/tcl/xowiki-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/xowiki-procs.tcl,v diff -u -r1.542.2.27 -r1.542.2.28 --- openacs-4/packages/xowiki/tcl/xowiki-procs.tcl 24 Jun 2019 05:51:00 -0000 1.542.2.27 +++ openacs-4/packages/xowiki/tcl/xowiki-procs.tcl 26 Jun 2019 11:07:19 -0000 1.542.2.28 @@ -2273,7 +2273,7 @@ # return the pretty_link for the current page ${:package_id} pretty_link -parent_id ${:parent_id} \ -anchor $anchor -query $query -absolute $absolute -siteurl $siteurl \ - -lang $lang -download $download [:name] + -lang $lang -download $download -page [self] [:name] } Page instproc detail_link {} { @@ -3917,10 +3917,10 @@ # # First check for invalid meta characters for security reasons. # - if {[regexp {[\[\]]} $form_constraints]} { - :uplevel [list set errorMsg [_ xowiki.error-form_constraint-invalid_characters]] - return 0 - } + #if {[regexp {[\[\]]} $form_constraints]} { + # :uplevel [list set errorMsg [_ xowiki.error-form_constraint-invalid_characters]] + # return 0 + #} # # Create from fields from all specs and report, if there are any errors # @@ -4569,7 +4569,7 @@ File instproc render_icon {} { return {text " " is_richtext true} } - + FormPage instproc render_icon {} { set page_template [:page_template] if {[$page_template istype ::xowiki::FormPage]} { Index: openacs-4/packages/xowiki/tcl/test/xowiki-test-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/test/Attic/xowiki-test-procs.tcl,v diff -u -r1.1.2.15 -r1.1.2.16 --- openacs-4/packages/xowiki/tcl/test/xowiki-test-procs.tcl 26 Jun 2019 04:17:39 -0000 1.1.2.15 +++ openacs-4/packages/xowiki/tcl/test/xowiki-test-procs.tcl 26 Jun 2019 11:07:19 -0000 1.1.2.16 @@ -40,34 +40,105 @@ set instance $_test_instance_name set testfolder .testfolder set locale [lang::system::locale] + set lang [string range $locale 0 1] ::xowiki::Package initialize -url $_test_instance_name set root_folder_id [::$package_id folder_id] + aa_log "package_id $package_id system locale $locale" - set f1_id [xowiki::test::require_folder "f1" $root_folder_id $package_id] - set f3_id [xowiki::test::require_folder "f3" $f1_id $package_id] - set subf3_id [xowiki::test::require_folder "subf3" $f3_id $package_id] + set f1_id [xowiki::test::require_folder "f1" $root_folder_id $package_id] + set f3_id [xowiki::test::require_folder "f3" $f1_id $package_id] + set subf3_id [xowiki::test::require_folder "subf3" $f3_id $package_id] + set enpage_id [xowiki::test::require_page en:page $root_folder_id $package_id] + set f1_p1_id [xowiki::test::require_page en:p1 $f1_id $package_id] + ::xo::db::CrClass get_instance_from_db -item_id $enpage_id + set enpage_pl [::$enpage_id pretty_link] + aa_equals "Pretty link of en:page: $enpage_pl" $enpage_pl "/xowiki-test/page" - aa_log "package_id=$package_id system locale $locale" + ::xo::db::CrClass get_instance_from_db -item_id $f1_p1_id + set f1_p1_pl [::$f1_p1_id pretty_link] + aa_equals "Pretty link of f1/page $f1_p1_pl" $f1_p1_pl "/xowiki-test/f1/p1" - set enpage_id [xowiki::test::require_page en:page $root_folder_id $package_id] + # + # Try to resolve folders, pages and inherited folder.form via URL. + # The method resolve_page receives the "object" instance variable + # initialized via "Package initialize" ALWAYS without a leading "/". + # + aa_section "resolve_pagel" + foreach url { + f1 page f1/p1 + en:folder.form folder.form + } { + set page [$package_id resolve_page $url m] + aa_true "can resolve url $url -> $page" {$page ne ""} + } + + # + # Try to obtain item_info from URLs pointing to folders, + # pages and inherited folder.form via URL. This function + # is a helper function of resolve_page, so same rules + # apply here as well. + # + aa_section "item_info_from_url -with_package_prefix false" + foreach url { + f1 page f1/p1 + } { + set info [$package_id item_info_from_url \ + -with_package_prefix false \ + -default_lang $lang \ + $url] + aa_true "can get item_info from url $url -> $info" {[dict get $info item_id] ne "0"} + } + + aa_section "item_info_from_url -with_package_prefix true" + foreach url { + /xowiki-test/f1 /xowiki-test/page /xowiki-test/f1/p1 + } { + set info [$package_id item_info_from_url \ + -with_package_prefix true \ + -default_lang $lang \ + $url] + aa_true "can get item_info from url $url -> $info" {[dict get $info item_id] ne "0"} + } + + # + # item_refs are different to URLs, but look similar. The + # item refs can be used to navigate in the tree and they + # are allow symbolic names not necessarily possible via + # URLs (e.g. prefixed names). + # + aa_section "resolve item refs" + foreach item_ref { + f1 page f1/p1 + ./f1 ./page ./f1/p1 + /f1 /page /f1/p1 + } { + set info [$package_id item_ref -parent_id $root_folder_id -default_lang $lang $item_ref] + aa_true "can resolve item_ref $item_ref -> $info" {[dict get $info item_id] ne "0"} + } + + aa_section "bi-directional resolving via URLs" + ::xo::db::CrClass get_instance_from_db -item_id $enpage_id set pretty_link1 [::$enpage_id pretty_link] set item_info1 [$package_id item_info_from_url $pretty_link1] - aa_true "can resolve $pretty_link1 => $enpage_id" [expr {[dict get $item_info1 item_id] eq $enpage_id}] + aa_true "can resolve $pretty_link1 => $enpage_id" \ + [expr {[dict get $item_info1 item_id] eq $enpage_id}] - set folder_clash_id [xowiki::test::require_page page $root_folder_id $package_id] + set folder_clash_id [xowiki::test::require_folder page $root_folder_id $package_id] ::xo::db::CrClass get_instance_from_db -item_id $folder_clash_id set pretty_link2 [::$folder_clash_id pretty_link] set item_info2 [$package_id item_info_from_url $pretty_link2] - aa_true "can resolve $pretty_link2 => $folder_clash_id" [expr {[dict get $item_info2 item_id] eq $folder_clash_id}] + aa_true "same-named folder: can resolve $pretty_link2 => $folder_clash_id" \ + [expr {[dict get $item_info2 item_id] eq $folder_clash_id}] + + set pretty_link1 [::$enpage_id pretty_link] set item_info1 [$package_id item_info_from_url $pretty_link1] - aa_true "can resolve $pretty_link1 => $enpage_id" [expr {[dict get $item_info1 item_id] eq $enpage_id}] + aa_true "same-named page: can resolve $pretty_link1 => $enpage_id" \ + [expr {[dict get $item_info1 item_id] eq $enpage_id}] - } - }