- Publicity:
Public Only
All
static-pages-procs.tcl
Procedures in this file
Detailed information
[
hide source ]
| [
make this
the default ]
Content File Source
ad_library {
Utilities for static pages.
@author Brandoch Calef (bcalef@arsdigita.com)
@creation-date 2001-01-22
@cvs-id static-pages-procs.tcl,v 1.11.2.13 2003/02/06 13:05:51 jeffd Exp
}
ad_proc -public sp_sync_cr_with_filesystem_scheduled {{}} {} {
set proc_name {sp_sync_cr_with_filesystem_scheduled}
ns_log Notice "$proc_name: Starting"
proc sp_sch_old_item { path id } {}
proc sp_sch_new_item { path id } {}
proc sp_sch_changed_item { path id } {
sp_flush_page $id
}
set package_key [sp_package_key_is]
db_foreach each_apm_package_instance {
select package_id, instance_name
from apm_packages
where package_key = :package_key
order by package_id
} {
set root_folder_id [sp_root_folder_id $package_id]
set fs_root "[acs_root_dir][parameter::get -package_id $package_id -parameter {fs_root}]"
ns_log Debug "$proc_name: About to scan the filesystem for: package_id '$package_id', instance_name '$instance_name', fs_root '$fs_root':"
set sync_proc {sp_sync_cr_with_filesystem}
if { [catch {
set result [$sync_proc -package_id $package_id \
-file_unchanged_proc sp_sch_old_item \
-file_add_proc sp_sch_new_item \
-file_change_proc sp_sch_changed_item \
-folder_add_proc sp_sch_new_item \
-folder_unchanged_proc sp_sch_old_item \
$fs_root $root_folder_id]
} errmsg] } {
global errorInfo
ns_log Error "$proc_name: For package_id: '$package_id', $sync_proc failed with error:\n${errorInfo}"
} else {
ns_log Debug "$proc_name: For package_id: '$package_id': $result"
}
} if_no_rows {
ns_log Warning "$proc_name: NO package ids found for package key: '$package_key'."
}
ns_log Debug "$proc_name: Done."
}
d_proc -public sp_sync_cr_with_filesystem {
{
-file_add_proc ""
-file_change_proc ""
-file_unchanged_proc ""
-file_read_error_proc ""
-folder_add_proc ""
-folder_unchanged_proc ""
-package_id ""
}
fs_root
root_folder_id
{
static_page_regexp {}
}
} {
Synchronize the content repository with the file system.
This creates entries in sp_folders and static_pages, so the static_page
functions must be used to delete entries.
@param file_add_proc The name of a Tcl proc to be called for each file
added. The full file path and the page_id will be
passed to it.
@param file_change_proc The name of a Tcl proc to be called for each file
changed in the database.
@param file_unchanged_proc The name of a Tcl proc to be called for each file
unchanged in the database.
@param folder_add_proc The name of a Tcl proc to be called for each folder
added. The full file path and the folder_id will be
passed to it.
@param folder_unchanged_proc The name of a Tcl proc to be called for each folder
unchanged in the database.
@param fs_root The starting path in the filesystem. Files below this point will
be scanned.
@param root_folder_id The id of the root folder in the static-pages system (and in
the content repository) obtained from
<code>static_page.get_root_folder</code>.
@param static_page_regexp A regexp to identify static pages.
@param package_id Optionally, the package id of the Static Pages
instance. If not specified, determined from ad_conn.
@author Andrew Piskorski (atp@piskorski.com)
@creation-date 2001/08/27
} {
if { $package_id eq "" } {
set package_id [ad_conn package_id]
}
if { [catch { set return_val [sp_sync_cr_with_filesystem_internal \
-file_add_proc $file_add_proc \
-file_change_proc $file_change_proc \
-file_unchanged_proc $file_unchanged_proc \
-file_read_error_proc $file_read_error_proc \
-folder_add_proc $folder_add_proc \
-folder_unchanged_proc $folder_unchanged_proc \
-package_id $package_id \
-stack_depth 2 \
{return_mesg} $fs_root $root_folder_id $static_page_regexp ]
} result] } {
sp_sync_cr_with_filesystem_unlock $package_id
global errorInfo
error $result $errorInfo
} else {
return $return_mesg
}
}
ad_proc -private sp_sync_cr_with_filesystem_unlock {package_id} {} {
set mutex [nsv_get . {sp_sync_cr_fs_mutex}]
ns_mutex lock $mutex
nsv_set {sp_sync_cr_fs_times} $package_id {}
ns_mutex unlock $mutex
}
d_proc -private sp_sync_cr_with_filesystem_internal {
{
-file_add_proc ""
-file_change_proc ""
-file_unchanged_proc ""
-file_read_error_proc ""
-folder_add_proc ""
-folder_unchanged_proc ""
-package_id ""
-stack_depth 1
}
return_mesg_var
fs_root
root_folder_id
{
static_page_regexp {}
}
} {
This procedure was originally named sp_sync_cr_with_filesystem
procedure, but has been renamed and modified so that it can be
wrapped inside the new sp_sync_cr_with_filesystem, to support the
mutex locking.
<p>
We wrap it because at the end of this proc, we must set
sp_sync_cr_with_filesystem_times($package_id) back to empty string.
But if we hit some random untrapped error partway through, we'll
never get there. Therefore, we wrap this proc inside another, and
have the wrapper proc catch any errors thrown by this proc, set the
var back to empty string, then re-throw the error.
<p>
This procedure takes the exact same arguments as its
sp_sync_cr_with_filesystem wrapper proc, except for the addition of
return_mesg_var.
<p>
You should <em>never</em> call this procedure, except from
sp_sync_cr_with_filesystem.
@param return_mesg_var Name of variable in which to return text
message, for presentation on a web page to the user.
@param package_id <em>Must</em> be passed in, for this internal
version of the proc.
@author Brandoch Calef (bcalef@arsdigita.com)
@author Andrew Piskorski (atp@piskorski.com)
@creation-date 2001-02-07
} {
set proc_name {sp_sync_cr_with_filesystem_internal}
if { $package_id eq "" } {
error "package_id '$package_id' is not valid."
}
upvar $return_mesg_var return_mesg
set return_mesg {}
set mutex [nsv_get . {sp_sync_cr_fs_mutex}]
set nsv {sp_sync_cr_fs_times}
ns_mutex lock $mutex
if { ![nsv_exists $nsv $package_id] } {
set other_start_time {}
} else {
set other_start_time [nsv_get sp_sync_cr_fs_times $package_id]
}
if { $other_start_time eq "" } {
nsv_set $nsv $package_id [ns_time]
set run_p 1
} else {
set run_p 0
}
ns_mutex unlock $mutex
if { ! $run_p } {
set time_diff [expr {[ns_time] - $other_start_time}]
set other_time_pretty [ns_httptime $other_start_time]
set mesg "sp_sync_cr_with_filesystem: Already running. sp_sync_cr_fs_times($package_id) == $other_time_pretty, $time_diff seconds ago."
ns_log Warning $mesg
set return_mesg "Another copy of this procedure is already running for
this package instance. It started running $time_diff seconds
ago, at $other_time_pretty. Only one copy may run at a time.
Please wait and then try again."
return 0
}
set sync_session_id [db_nextval sp_session_id_seq]
set fs_trimmed [string trimright $fs_root "/"]
set fs_trimmed_length [string length $fs_trimmed]
set static_page_regexp "\\.[join [split [string trim [parameter::get -package_id $package_id -parameter AllowedExtensions]] " "] "$|\\."]$"
foreach file [ad_find_all_files $fs_root] {
if { [regexp -nocase $static_page_regexp $file match] } {
set path [split [string range $file $fs_trimmed_length end] "/"]
set path [lrange $path 1 [expr {[llength $path]-2}]]
set cumulative_path ""
set parent_folder_id $root_folder_id
foreach directory $path {
append cumulative_path "$directory/"
if (![info exists path_exists($cumulative_path)]) {
set folder_id [db_string get_folder_id {
select nvl(content_item.get_id(:cumulative_path,:root_folder_id),0)
from dual
}]
if { $folder_id == 0} {
set folder_id [db_exec_plsql create_new_folder {}]
if { [string length $folder_add_proc] > 0 } {
uplevel $stack_depth "$folder_add_proc $cumulative_path $folder_id"
}
} else {
if { [string length $folder_unchanged_proc] > 0 } {
uplevel $stack_depth "$folder_unchanged_proc $cumulative_path $folder_id"
}
}
set path_exists($cumulative_path) $folder_id
db_dml insert_path {
insert into sp_extant_folders (session_id,folder_id)
values (:sync_session_id,:folder_id)
}
} else {
set folder_id $path_exists($cumulative_path)
}
set parent_folder_id $folder_id
}
set sp_filename [sp_get_relative_file_path $file]
set mtime_from_fs [file mtime $file]
if [db_0or1row check_db_for_page {
select static_page_id, mtime as mtime_from_db from static_pages
where filename = :sp_filename
}] {
if { [catch {
set fp [open $file r]
set file_from_fs [read $fp]
close $fp
} errmsg]} {
set mesg "$proc_name: Error reading file: '$file': [ns_quotehtml $errmsg]"
ns_log Error $mesg
if { $file_read_error_proc ne "" } {
uplevel $stack_depth [list $file_read_error_proc $file $static_page_id $mesg]
}
continue
}
set file_updated 0
set storage_type [db_string get_storage_type ""]
switch $storage_type {
"file" {
if {$mtime_from_fs != $mtime_from_db} {
set file_updated 1
}
}
"lob" {
db_1row get_db_page {
select content as file_from_db from cr_revisions
where revision_id = content_item.get_live_revision(:static_page_id)
}
if {$file_from_db != $file_from_fs} {
set file_updated 1
}
}
}
if {$file_updated == 1} {
db_dml update_db_file {
update cr_revisions set content = empty_blob()
where revision_id = content_item.get_live_revision(:static_page_id)
returning content into :1
} -blob_files [list $file]
if {$storage_type=="file"} {
db_dml update_static_page {
update static_pages set mtime = :mtime_from_fs
where static_page_id = :static_page_id
}
}
if { [string length $file_change_proc] > 0 } {
uplevel $stack_depth "$file_change_proc $file $static_page_id"
}
} else {
if { [string length $file_unchanged_proc] > 0 } {
uplevel $stack_depth "$file_unchanged_proc $file $static_page_id"
}
}
db_dml insert_file {
insert into sp_extant_files (session_id,static_page_id)
values (:sync_session_id,:static_page_id)
}
} else {
set static_page_id {}
if { [catch {
set fp [open $file r]
set file_contents [read $fp]
close $fp
} errmsg]} {
set mesg "$proc_name: Error reading file: '$file': [ns_quotehtml $errmsg]"
ns_log Error $mesg
if { $file_read_error_proc ne "" } {
uplevel $stack_depth [list $file_read_error_proc $file $static_page_id $mesg]
}
continue
}
if { ![regexp -nocase {<title.*?>(.+?)</title} $file_contents match page_title] } {
regexp {[^/]*$} $file page_title
}
set mime_type [cr_filename_to_mime_type -create $sp_filename]
if { [catch {
set static_page_id [db_exec_plsql do_sp_new {}]
} errmsg] } {
set mesg "$proc_name: do_sp_new failed for file '$file' with error: [ns_quotehtml $errmsg]"
ns_log Error $mesg
if { $file_read_error_proc ne "" } {
uplevel $stack_depth [list $file_read_error_proc $file $static_page_id $mesg]
}
continue
} else {
db_dml insert_file_contents {} -blob_files [list $file]
if { [string length $file_add_proc] > 0 } {
uplevel $stack_depth "$file_add_proc $file $static_page_id"
}
db_dml insert_file {
insert into sp_extant_files (session_id,static_page_id)
values (:sync_session_id,:static_page_id)
}
}
}
}
}
db_exec_plsql delete_old_files {
begin
static_page.delete_stale_items(:sync_session_id,:package_id);
delete from sp_extant_folders where session_id = :sync_session_id;
delete from sp_extant_files where session_id = :sync_session_id;
end;
}
sp_sync_cr_with_filesystem_unlock $package_id
set return_mesg "Done."
return 0
}
ad_proc -public sp_root_folder_id { package_id } {} {
return [db_exec_plsql get_root_folder_id {
begin
:1 := static_page.get_root_folder(:package_id);
end;
}]
}
d_proc -public sp_change_matching_permissions {
root_folder_id
contained_string
grant_or_revoke
} {
Grant or revoke permissions on all files below root_folder_id
whose filenames contain contained_string.
@author Brandoch Calef (bcalef@arsdigita.com)
@creation-date 2001-02-23
} {
if { $grant_or_revoke != "grant" && $grant_or_revoke != "revoke" } {
ns_log Warning "sp_change_matching_permissions called with grant_or_revoke = $grant_or_revoke"
return
}
db_exec_plsql grant_or_revoke_matching_permissions "
begin
for file_row in (
select static_page_id from static_pages
where folder_id in (
select folder_id from sp_folders
start with folder_id = :root_folder_id
connect by parent_id = prior folder_id)
and filename like '%${contained_string}%'
) loop
acs_permission.${grant_or_revoke}_permission(
object_id => file_row.static_page_id,
grantee_id => acs.magic_object_id('the_public'),
privilege => 'general_comments_create'
);
end loop;
end;
"
}
d_proc -public sp_change_matching_display {
root_folder_id
contained_string
show_full_comments_p
} {
Set all files below root_folder_id whose filenames contain
contained_string to have comments either shown (full contents of
comments are displayed on the page) or summarized (title line of
comments are listed).
@author Brandoch Calef (bcalef@arsdigita.com)
@creation-date 2001-02-23
} {
if { $show_full_comments_p != "t" && $show_full_comments_p != "f" } {
ns_log Warning "sp_change_matching_permissions called with show_full_comments_p = $show_full_comments_p"
return
}
db_foreach matching_static_page "
select static_page_id from static_pages
where folder_id in (
select folder_id from sp_folders
start with folder_id = :root_folder_id
connect by parent_id = prior folder_id)
and filename like '%${contained_string}%'
" {
sp_flush_page $static_page_id
}
db_dml show_or_summarize_comments_matching "
update static_pages set show_comments_p = :show_full_comments_p
where static_page_id in (
select static_page_id from static_pages
where folder_id in (
select folder_id from sp_folders
start with folder_id = :root_folder_id
connect by parent_id = prior folder_id)
and filename like '%${contained_string}%'
)
"
}
ad_proc -private sp_get_full_file_path { file } {} {
set full_path [cr_fs_path STATIC_PAGES]
append full_path $file
return $full_path
}
ad_proc -private sp_get_relative_file_path { file } {} {
set relative_path [string range $file [string length [cr_fs_path STATIC_PAGES]] end]
ns_log debug "**[cr_fs_path STATIC_PAGES]**"
ns_log debug "relative path:$relative_path"
return $relative_path
}
ad_proc -private sp_get_page_info_query { page_id } {} {
return [db_string get_page_info "select '{'||content_item.get_title($page_id)||'} '||decode(show_comments_p,'t',1,0) from static_pages where static_page_id = $page_id"]
}
ad_proc -private sp_get_page_id { filename } {} {
set package_key [sp_package_key_is]
if { [db_0or1row page_and_package_ids {}] } {
set results [list $static_page_id $package_id]
} else {
set results [list -1 -1]
}
return $results
}
ad_proc -public sp_flush_page { page_id } {} {
util_memoize_flush [list sp_get_page_info_query $page_id]
}
ad_proc -public sp_package_key_is {} {} {
return {static-pages}
}
ad_proc -private sp_package_url {package_key} {} {
set proc_name {sp_package_url}
set found_p [db_0or1row get_any_package_instance {
select min(package_id) as package_id
from apm_packages
where package_key = :package_key
}]
if { !$found_p } {
error "$proc_name: the '$package_key' package is not instantiated."
}
set found_p [db_0or1row get_mount_point {}]
if { !$found_p } {
error "$proc_name: the '$package_key' package is not mounted."
}
return $url
}
ad_proc -public sp_serve_html_page { } {} {
set filename [ad_conn file]
set sp_filename [sp_get_relative_file_path $filename]
foreach [list page_id package_id] \
[util_memoize [list sp_get_page_id $sp_filename]] { break }
set templating_enabled_p [parameter::get -package_id $package_id -parameter TemplatingEnabledP -default 0]
set comment_p [parameter::get -package_id $package_id -parameter CommentsDisplayedP -default 1]
set file [ad_conn file]
ad_conn -set subsite_id [site_node::closest_ancestor_package -include_self -package_key "acs-subsite"]
if { $page_id >= 0 } {
set page_info [util_memoize [list sp_get_page_info_query $page_id]]
set comment_link ""
if { $comment_p } {
if { [permission::permission_p -party_id [acs_magic_object the_public] -object_id $page_id -privilege general_comments_create] } {
append comment_link "<center>[general_comments_create_link -object_name [lindex $page_info 0] $page_id [ad_conn url]]</center>"
}
append comment_link "[general_comments_get_comments -print_content_p [lindex $page_info 1] $page_id [ad_conn url]]"
}
if { $comment_link eq ""
&& ! $templating_enabled_p } {
ns_returnfile 200 text/html $filename
return
} else {
if { [catch {
set fp [open $filename r]
set file_contents [read $fp]
close $fp
} errmsg] } {
ad_return_error "Error reading file" \
"This error was encountered while reading $filename: $errmsg"
ad_script_abort
}
set body_close [string first "</body" [string tolower $file_contents]]
if { $body_close >= 0 } {
set body "[string range $file_contents 0 [expr {$body_close-1}]]${comment_link}[string range $file_contents $body_close end]"
} else {
set body "${file_contents}$comment_link"
}
}
} else {
if { ! $templating_enabled_p } {
ns_returnfile 200 text/html $file
return {}
} else {
set body [template::util::read_file $file]
}
}
if { $templating_enabled_p } {
set headers ""
set sp_scripts ""
set title ""
if {[regexp -nocase {(.*?)<body.*?>(.*)</body.*?>} $body match headers bodyless]} {
set body $bodyless
}
regexp -nocase {<title.*?>(.*?)</title.*?>} $headers match title
while {[regexp -nocase {(<script.*?>.*?</script.*?>)(.*$)} $headers match ascript headers]} {
append sp_scripts "\n$ascript"
}
set file_mtime [clock format [file mtime $file]]
set body [template::adp_parse [acs_root_dir]/[parameter::get -package_id $package_id -parameter TemplatePath] [list body $body sp_scripts $sp_scripts title "$title" file_mtime $file_mtime page_id $page_id] ]
}
ns_return 200 text/html $body
}
ad_proc -private sp_register_extension {} {} {
set proc_name {sp_register_extension}
set package_key [sp_package_key_is]
set package_ids [db_list all_static_pages_package_instances {
select package_id
from apm_packages
where package_key = :package_key
}]
array set extensions_arr [list]
foreach package_id $package_ids {
foreach extension [split [string tolower [string trim [parameter::get -package_id $package_id -parameter AllowedExtensions]]] " "] {
set extensions_arr($extension) {}
}
}
foreach extension [array names extensions_arr] {
if { [regexp {htm} $extension] } {
set handler_proc {sp_serve_html_page}
rp_register_extension_handler $extension $handler_proc
rp_register_extension_handler [string toupper $extension] $handler_proc
} else {
ns_log Warning "$proc_name: NOT registering any proc to handle files with extension '$extension'."
}
}
}