Index: openacs-4/packages/file-storage/www/download-zip.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/file-storage/www/download-zip.tcl,v diff -u -r1.10 -r1.11 --- openacs-4/packages/file-storage/www/download-zip.tcl 21 Jan 2019 17:58:10 -0000 1.10 +++ openacs-4/packages/file-storage/www/download-zip.tcl 3 Sep 2024 15:37:38 -0000 1.11 @@ -3,64 +3,99 @@ } { object_id:naturalnum,notnull,multiple {confirm_p:optional,boolean 0} - {return_url:localurl ""} + {return_url:localurl,verify ""} } -errors {object_id:,notnull,integer,multiple {Please select at least one item to download.} } auth::require_login -set user_id [ad_conn user_id] -# publish the object to the file system -set in_path [ad_tmpnam] -file mkdir $in_path - -if {[llength $object_id] == 1} { - set object_name_id $object_id -} else { - set object_name_id [fs::get_parent -item_id [lindex $object_id 0]] +# Make sure all selected objects exist. This is the minimal +# requirement. Don't throw hard errors on following outdated links. We +# could test for supported object_types. +set n_objects [llength $object_id] +if {[db_string objects_do_not_exist " + select :n_objects <> (select count(*) + from cr_items + where item_id in ([join $object_id ,])) + from dual +"]} { + ns_returnnotfound + ad_script_abort } -set download_name [fs::get_file_system_safe_object_name -object_id $object_name_id] -append download_name ".zip" +ad_try { -foreach fs_object_id $object_id { - # The minimal requirement is that the object exists. Don't throw - # hard errors on following outdated links. We could test for - # supported object_types. - if {![acs_object::object_p -id $fs_object_id]} { - ns_returnnotfound - file delete -force -- $in_path - ad_script_abort - } - set file [fs::publish_object_to_file_system -object_id $fs_object_id -path $in_path -user_id $user_id] -} + ad_progress_bar_begin \ + -title [_ file-storage.download_zip_creating_archive_msg] -# create a temp dir to put the archive in -set out_path [ad_tmpnam] -file mkdir $out_path + set user_id [ad_conn user_id] -set out_file [file join ${out_path} ${download_name}] + # copy all files together in a temporary folder on the filesystem + set in_path [ad_mktmpdir] -# create the archive -ad_try { + foreach fs_object_id $object_id { + permission::require_permission -object_id $fs_object_id -privilege read + fs::publish_object_to_file_system \ + -object_id $fs_object_id \ + -path $in_path \ + -user_id $user_id + } + + set out_file [ad_tmpnam] + + # create the archive util::zip -source $in_path -destination $out_file + +} on ok {d} { + + # compute the archive download filename + if {$n_objects == 1} { + set object_name_id $object_id + } else { + set object_name_id [fs::get_parent -item_id [lindex $object_id 0]] + } + set download_name [fs::get_file_system_safe_object_name -object_id $object_name_id].zip + + set n $download_name + set f $out_file + set u $user_id + # The download URL always points to the file-storage instance of + # the file, unlike the return_url, which might be arbitrary. + set package_id [fs::get_file_package_id -file_id $object_name_id] + set package_url [site_node::get_url_from_object_id -object_id $package_id] + set file_url [export_vars -base ${package_url}/download-zip-2 { + f:sign(max_age=300) + n:sign(max_age=300) + u:sign(max_age=300) + }] + + set message "#file-storage.download_zip_file_is_ready_msg# + " + + util_user_message \ + -html \ + -message $message + + if {$return_url eq ""} { + # Return URL must be not-empty or we will redirect to + # ourselves... + set return_url $package_url + } + + ad_progress_bar_end \ + -url $return_url + } on error {errorMsg} { - # some day we'll do something useful here - file delete -force -- $in_path - file delete -force -- $out_path + error $errorMsg -} -# return the archive to the connection. -ns_set put [ad_conn outputheaders] Content-Disposition "attachment;filename=\"$download_name\"" -ns_set put [ad_conn outputheaders] Content-Type "application/zip" -ns_set put [ad_conn outputheaders] Content-Size "[file size $out_file]" -ns_returnfile 200 application/octet-stream $out_file +} finally { -# clean everything up -file delete -force -- $in_path -file delete -force -- $out_path + # clean everything up + file delete -force -- $in_path +} + # Local variables: # mode: tcl # tcl-indent-level: 4