Index: openacs-4/contrib/packages/project-manager/tcl/project-manager-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/tcl/Attic/project-manager-procs.tcl,v diff -u -r1.3 -r1.4 --- openacs-4/contrib/packages/project-manager/tcl/project-manager-procs.tcl 27 Apr 2004 00:49:28 -0000 1.3 +++ openacs-4/contrib/packages/project-manager/tcl/project-manager-procs.tcl 30 Apr 2004 01:42:58 -0000 1.4 @@ -59,3 +59,125 @@ return $new_string } + + +ad_proc -private pm::util::word_diff { + {-old:required} + {-new:required} + {-split_by {}} + {-filter_proc {ad_quotehtml}} + {-start_old {}} + {-end_old {}} + {-start_new {}} + {-end_new {}} +} { + This procedure has been BACKPORTED from OpenACS HEAD. That means + you should not use it in your own applications. If you do, you'll + need to update your application once OpenACS 5.2 is available, and + create a dependency on OpenACS 5.2 in your .info file. + + Does a word (or character) diff on two lines of text and indicates text + that has been deleted/changed or added by enclosing it in + start/end_old/new. + + @param old The original text. + @param new The modified text. + + @param split_by If split_by is a space, the diff will be made + on a word-by-word basis. If it is the empty string, it will be made on + a char-by-char basis. + + @param filter_proc A filter to run the old/new text through before + doing the diff and inserting the HTML fragments below. Keep in mind + that if the input text is HTML, and the start_old, etc... fragments are + inserted at arbitrary locations depending on where the diffs are, you + might end up with invalid HTML unless the original HTML is quoted. + + @param start_old HTML fragment to place before text that has been removed. + @param end_old HTML fragment to place after text that has been removed. + @param start_new HTML fragment to place before new text. + @param end_new HTML fragment to place after new text. + + @see ad_quotehtml + @author Gabriel Burca +} { + + if {$filter_proc != ""} { + set old [$filter_proc $old] + set new [$filter_proc $new] + } + + set old_f [ns_tmpnam] + set new_f [ns_tmpnam] + set old_fd [open $old_f "w"] + set new_fd [open $new_f "w"] + puts $old_fd [join [split $old $split_by] "\n"] + puts $new_fd [join [split $new $split_by] "\n"] + close $old_fd + close $new_fd + + # Diff output is 1 based, our lists are 0 based, so insert a dummy + # element to start the list with. + set old_w [linsert [split $old $split_by] 0 {}] + set sv 1 + +# For debugging purposes: +# set diff_pipe [open "| diff -f $old_f $new_f" "r"] +# while {![eof $diff_pipe]} { +# append res "[gets $diff_pipe]
" +# } + + set diff_pipe [open "| diff -f $old_f $new_f" "r"] + while {![eof $diff_pipe]} { + gets $diff_pipe diff + if {[regexp {^d(\d+)(\s+(\d+))?$} $diff full m1 m2]} { + if {$m2 != ""} {set d_end $m2} else {set d_end $m1} + for {set i $sv} {$i < $m1} {incr i} { + append res "${split_by}[lindex $old_w $i]" + } + for {set i $m1} {$i <= $d_end} {incr i} { + append res "${split_by}${start_old}[lindex $old_w $i]${end_old}" + } + set sv [expr $d_end + 1] + } elseif {[regexp {^c(\d+)(\s+(\d+))?$} $diff full m1 m2]} { + if {$m2 != ""} {set d_end $m2} else {set d_end $m1} + for {set i $sv} {$i < $m1} {incr i} { + append res "${split_by}[lindex $old_w $i]" + } + for {set i $m1} {$i <= $d_end} {incr i} { + append res "${split_by}${start_old}[lindex $old_w $i]${end_old}" + } + while {![eof $diff_pipe]} { + gets $diff_pipe diff + if {$diff == "."} { + break + } else { + append res "${split_by}${start_new}${diff}${end_new}" + } + } + set sv [expr $d_end + 1] + } elseif {[regexp {^a(\d+)$} $diff full m1]} { + set d_end $m1 + for {set i $sv} {$i < $m1} {incr i} { + append res "${split_by}[lindex $old_w $i]" + } + while {![eof $diff_pipe]} { + gets $diff_pipe diff + if {$diff == "."} { + break + } else { + append res "${split_by}${start_new}${diff}${end_new}" + } + } + set sv [expr $d_end + 1] + } + } + + for {set i $sv} {$i < [llength $old_w]} {incr i} { + append res "${split_by}[lindex $old_w $i]" + } + + file delete -- $old_f $new_f + + return $res +} Index: openacs-4/contrib/packages/project-manager/www/one.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/one.adp,v diff -u -r1.32 -r1.33 --- openacs-4/contrib/packages/project-manager/www/one.adp 27 Apr 2004 00:49:29 -0000 1.32 +++ openacs-4/contrib/packages/project-manager/www/one.adp 30 Apr 2004 01:42:58 -0000 1.33 @@ -85,19 +85,9 @@ - Deadline - - @project.planned_end_date@ - - - Ongoing - - - - Latest finish - @project.latest_finish_date@ + @project.latest_finish_date@ Ongoing Index: openacs-4/contrib/packages/project-manager/www/task-add-edit.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/task-add-edit.adp,v diff -u -r1.14 -r1.15 --- openacs-4/contrib/packages/project-manager/www/task-add-edit.adp 27 Apr 2004 00:49:29 -0000 1.14 +++ openacs-4/contrib/packages/project-manager/www/task-add-edit.adp 30 Apr 2004 01:42:58 -0000 1.15 @@ -18,7 +18,7 @@ -  #@num.rownum@   +  #@num.rownum@   @@ -30,7 +30,10 @@
Error -

+ + +

+ Subject:*
@@ -41,7 +44,7 @@

- Description:
+ Description:

@@ -50,13 +53,24 @@

+ + Comment:
+
+ + +
+ Error +
+
+

+ - @@ -105,18 +119,19 @@ - + - @@ -128,6 +143,18 @@ % + + + + + @@ -149,25 +176,31 @@ + + + + +
Work required: + Work required: *

-

- [i] - You must enter a number here (make your best - guess) -

-
+ +

+ [i] + You must enter a number here (make your best + guess) +

+

Log entry

+

Log entry:

+ +

+ [i] + Enter 100% to close the @task_term_lower@, or less + to open it. +

+
Time:
+ +

+ [i] + You can optionally log time worked here. +

+
+ Error - + - - - - - - - +
Deadline: @@ -188,10 +221,8 @@
+

- - - Index: openacs-4/contrib/packages/project-manager/www/task-add-edit.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/task-add-edit.tcl,v diff -u -r1.29 -r1.30 --- openacs-4/contrib/packages/project-manager/www/task-add-edit.tcl 27 Apr 2004 00:49:29 -0000 1.29 +++ openacs-4/contrib/packages/project-manager/www/task-add-edit.tcl 30 Apr 2004 01:42:58 -0000 1.30 @@ -37,6 +37,8 @@ task_title:array,optional {process_id:integer ""} description:html,array,optional + {old_description ""} + comment:html,array,optional name:array,optional end_date:array,optional percent_complete:array,optional @@ -91,7 +93,6 @@ set package_id [ad_conn package_id] - # --------------------------------------------------------------- # # terminology # --------------------------------------------------------------- # @@ -107,12 +108,6 @@ } - -# ns_log Notice "return_url: $return_url" - - - - # -------------------------------------------------------------------- # If we are using a process, then we need to get the information on # the process now. This is necessary because we need to do things like @@ -293,7 +288,79 @@ } +# ------------------------------------------------------- # +# The third evilest hack of all time. +# ------------------------------------------------------- +# This is a workaround the fact that using multiple richtext items +# with ad_form is extremely difficult. The comment field +# will come in like an array (if the task is edited), +# with values like +# comment.1 = 1234 bold +# comment.1.format = text/enhanced +# comment.1.spellcheck = :nospell: +# The problem is we want +# to have multiple comments. +# +# What this loop does is go through the array, and rename the +# values into other variables. We then feed these variables into +# the SQL function that creates the new tasks. This works. I'm +# sure there must be a better way to do it. +# ------------------------------------------------------- # +if {[string equal $edit_p t] && [info exists comment]} { + set searchToken [array startsearch comment] + + while {[array anymore comment $searchToken]} { + + # these next two lines are important + set element_num "" + set element_type "" + + set keyname [array nextelement comment $searchToken] + set keyvalu $comment($keyname) + + # ns_log Notice "keyname: $keyname keyvalu: $keyvalu" + + # element_num is 1...n, element_type is format, spellcheck + regexp {(.*)\.(.*)} $keyname match element_num element_type + + # if element_num is null, then this is actually the value for + # the comment + if {[empty_string_p $element_num]} { + set comment_[set keyname] $keyvalu + } + + # ns_log Notice "element_num: $element_num element_type: $element_type" + + set comment_[set element_type]($element_num) $keyvalu + + # ns_log notice "set comment_[set element_type] to $keyvalu" + + } + +} else { + + for {set i 1} {$i <= $number} {incr i} { + # we explicitly set all the values to plaintext and empty for + # new tasks + set comment_format($i) "text/plain" + set comment_$i "" + } +} + +for {set i 1} {$i <= $number} {incr i} { + + set format $comment_format($i) + set richtext_list [list [set comment_$i] $format] + lappend comment_list [ad_html_to_text [template::util::richtext::get_property html_value $richtext_list]] +} + + +# ns_log Notice "comment_list $comment_list" + + + + # --------------------------------------------------------------- # # permissions and title setup, etc # we should update the permissions to not just use package_id, so @@ -342,6 +409,10 @@ {value $task_id_pass} } + {edit_p:text(hidden) + {value $edit_p} + } + {return_url:text(hidden) {value $return_url} } @@ -370,12 +441,17 @@ if {![ad_form_new_p -key task_id]} { + # this form is being edited, not new + + # note we are indexing values from 1... set i 1 + set old_description [list] db_foreach get_old_tasks { *SQL* } { set task_title_arr($i) $my_task_title set description_arr($i) $my_description + lappend old_description $my_description set mime_type_arr($i) $my_mime_type set template_arr($i) [list $my_description $my_mime_type] set estimated_hours_arr($i) $my_estimated_work @@ -414,6 +490,11 @@ # log hours as well. # ----------------------------------------------------- + # we also want to pass throught he old description so that + # we can do a word diff on the next page, so people can see + # what has changed + + ad_form -extend \ -name add_edit \ -form \ @@ -444,9 +525,34 @@ ] \ ] + # ------------------------------------------------------ + # we allow people to enter general comments when editing + # ------------------------------------------------------ + ad_form -extend \ + -name add_edit \ + -form \ + [list [list \ + comment.$i:richtext,optional,nospell \ + {label "Comment"} \ + {html {rows 7 cols 40}} \ + ] \ + ] + incr i } + + # we want to add in the old_description values as well + ad_form -extend \ + -name add_edit \ + -form \ + [list [list \ + comment.$i:text(hidden) \ + {value {$old_description}} \ + ] \ + ] + + } else { # ---------------------------------------------------------- @@ -505,6 +611,7 @@ {help_text {If you skip this task, it will not be created}} \ ] \ ] + } else { @@ -535,7 +642,35 @@ ] \ ] + # ----------------------------------------------------------- + # we only allow people to enter general comments when editing + # we also want to pass throught he old description so that + # we can do a word diff on the next page, so people can see + # what has changed + # ----------------------------------------------------------- + ad_form -extend \ + -name add_edit \ + -form \ + [list [list \ + comment.$i:text(hidden) \ + {value ""} \ + ] \ + ] + + } + + # we want to add in the old_description values as well + ad_form -extend \ + -name add_edit \ + -form \ + [list [list \ + comment.$i:text(hidden) \ + {value {}} \ + ] \ + ] + + } # get dependency types @@ -691,9 +826,8 @@ {help} \ ] \ [list \ - dependency_type.$i:text(select),optional \ + dependency_type.$i:text(hidden),optional \ {label \"Dependency type\"} \ - {options {[join $options " "]}} \ {value {finish_before_start}} \ ] \ [list \ @@ -790,6 +924,9 @@ set p_parent_task_id $dependency_task_id($i) set p_skip_p $skip_task_p($i) + # we don't do anything for the comments field, because they + # are not added in for new tasks. + # ns_log Notice "end date: $p_end_date" # add in the new task @@ -874,6 +1011,9 @@ SELECT to_char(current_date, 'YYYY-MM-DD')"] + # insert the comment into the database + set is_live [ad_parameter AutoApproveCommentsP {general-comments} {t}] + # -------------------------------------------------------------- # each task we edit returns a task_revision_id # -------------------------------------------------------------- @@ -902,6 +1042,9 @@ set p_description $description($i) set p_mime_type $description_format($i) + set p_comment $comment($i) + set p_comment_type $comment_format($i) + set p_percent $percent_complete($i) set p_work $estimated_hours_work($i) set p_work_min $estimated_hours_work_min($i) @@ -971,13 +1114,80 @@ -project_item_id $project_item_id } + # add in general comments for the task + + if {![empty_string_p $p_comment]} { + + set comment_id [db_nextval acs_object_id_seq] + + db_transaction { + db_exec_plsql insert_comment { + select acs_message__new ( + :comment_id, -- 1 p_message_id + NULL, -- 2 p_reply_to + current_timestamp, -- 3 p_sent_date + NULL, -- 4 p_sender + NULL, -- 5 p_rfc822_id + :p_task_title, -- 6 p_title + NULL, -- 7 p_description + :p_comment_type, -- 8 p_mime_type + NULL, -- 9 p_text + NULL, -- empty_blob(), -- 10 p_data + 0, -- 11 p_parent_id + :p_task_item_id, -- 12 p_context_id + :user_id, -- 13 p_creation_user + :peeraddr, -- 14 p_creation_ip + 'acs_message', -- 15 p_object_type + :is_live -- 16 p_is_live + ) + } + + db_dml add_entry { + insert into general_comments + (comment_id, + object_id, + category) + values + (:comment_id, + :p_task_item_id, + null) + } + + db_1row get_revision { + select content_item__get_latest_revision(:comment_id) as revision_id + } + + db_dml set_content { + update cr_revisions + set content = :p_comment + where revision_id = :revision_id + } + + db_exec_plsql grant_permission { + begin + perform acs_permission__grant_permission ( + /* object_id => */ :comment_id, + /* grantee_id => */ :user_id, + /* privilege => */ 'read' + ); + perform acs_permission__grant_permission ( + /* object_id => */ :comment_id, + /* grantee_id => */ :user_id, + /* privilege => */ 'write' + ); + return 0; + end; + } + } + } + } } -after_submit { # ns_log Notice "tae: return_url: $return_url" - ad_returnredirect "task-assign-add-edit?[export_vars -url {project_item_id return_url process_task_id:multiple revisions:multiple task_id:multiple}]" + ad_returnredirect "task-assign-add-edit?[export_vars -url {project_item_id comment_list edit_p return_url process_task_id:multiple revisions:multiple task_id:multiple old_description}]" pm::project::compute_parent_status $project_item_id ad_script_abort Index: openacs-4/contrib/packages/project-manager/www/task-assign-add-edit.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/task-assign-add-edit.tcl,v diff -u -r1.10 -r1.11 --- openacs-4/contrib/packages/project-manager/www/task-assign-add-edit.tcl 27 Apr 2004 00:49:29 -0000 1.10 +++ openacs-4/contrib/packages/project-manager/www/task-assign-add-edit.tcl 30 Apr 2004 01:42:58 -0000 1.11 @@ -24,6 +24,9 @@ role_id:array,optional party_id:array,optional {return_url ""} + {edit_p "t"} + {comment_list ""} + {old_description:html ""} } -properties { @@ -36,24 +39,50 @@ } + # --------------------------------------------------------------- # +# hack to get around lack of multiple hidden support with ad_form +set old_description [string map {"-" " "} $old_description] +set comment_list [string map {"-" " "} $comment_list] +set process_task_id [string map {"-" " "} $process_task_id] +set revisions [string map {"-" " "} $revisions] +set task_id [string map {"-" " "} $task_id] + + +# We have passed in a list of comments and old_description. We will +# key them by task number + +set index 0 +foreach t_id $task_id { + set comment_value($t_id) [lindex $comment_list $index] + set old_description_value($t_id) [lindex $old_description $index] + incr index +} + + + + if {[string equal [llength task_id] 1] && [exists_and_not_null return_url]} { - # if the task is closed, then we don't need to reassign things - if {[string equal 0 [pm::task::open_p -task_item_id $task_id]]} { + set open_p 0 + foreach t_id $task_id { + + # if the task is closed, then we don't need to reassign things + if {[string equal 1 [pm::task::open_p -task_item_id $t_id]]} { + set open_p 1 + } + } + + if {[string equal $open_p 0]} { ad_returnredirect $return_url } + } -# hack to get around lack of multiple hidden support with ad_form -set process_task_id [string map {"-" " "} $process_task_id] -set revisions [string map {"-" " "} $revisions] -set task_id [string map {"-" " "} $task_id] - # The number of assignments is set to 9, or the number of assignees + # 2 if there are more than 5 assignees set NUMBER_OF_ASSIGNMENTS 9 @@ -93,8 +122,14 @@ # permissions -set title "Add $task_term_lower assignments" -set context [list [list "one?project_item_id=$project_item_id" "One $project_term"] "New $task_term dependency"] +if {[string equal $edit_p "t"]} { + set title "Edit $task_term_lower assignments" + set context [list [list "one?project_item_id=$project_item_id" "One $project_term"] "Edit $task_term assignments"] +} else { + set title "Add $task_term_lower assignments" + set context [list [list "one?project_item_id=$project_item_id" "One $project_term"] "Add $task_term assignments"] +} + permission::require_permission -party_id $user_id -object_id $package_id -privilege create @@ -107,6 +142,8 @@ set process_task_id_pass [string map {" " "-"} $process_task_id] set revisions_pass [string map {" " "-"} $revisions] +set comment_pass [string map {" " "-"} $comment_list] +set old_description_pass [string map {" " "-"} $old_description] set task_id_pass [string map {" " "-"} $task_id] ad_form -name add_edit -form { @@ -126,6 +163,15 @@ {task_id:text(hidden) {value $task_id_pass}} + {comment_list:text(hidden) + {value $comment_pass}} + + {old_description:text(hidden) + {value $old_description_pass}} + + {edit_p:text(hidden) + {value $edit_p}} + {project_item_id:text(hidden) {value $project_item_id}} @@ -222,7 +268,17 @@ # ideally, we want to replace this with notifications, but I never # got it working correctly, so I use acs_mail_lite - set from_address [db_string get_email "select email from parties where party_id = :user_id"] + db_1row get_from_address_and_more { + SELECT + p.email as from_address, + p2.first_names || ' ' || p2.last_name as mod_username + FROM + parties p, + persons p2 + WHERE + p.party_id = :user_id and + p.party_id = p2.person_id + } foreach pl $party_list { @@ -234,10 +290,36 @@ set to_address [db_string get_email "select email from parties where party_id = :p_id"] - set subject "Task \#$t_id: $one_lines($t_id)" + if {[string equal $edit_p "t"]} { + set subject "Edited $task_term \#$t_id: $one_lines($t_id)" + set intro_text "$mod_username edited this $task_term_lower" + } else { + set subject "New $task_term \#$t_id: $one_lines($t_id)" + set intro_text "$mod_username assigned you to a new $task_term_lower" + } + # If there is a comment for this task, then display it + # prominently in the email + set my_comment $comment_value($t_id) + set my_old_description $old_description_value($t_id) + + if {[empty_string_p $my_comment]} { + set comment_text "" + } else { + set comment_text "--------\nCOMMENT:\n--------\n$my_comment\n\n" + } + set task_url "[parameter::get_from_package_key -package_key acs-kernel -parameter SystemURL][ad_conn package_url]task-one?task_id=$t_id" + if {![string equal $descriptions($t_id) $my_old_description] && [string equal $edit_p t]} { + set description_out "$descriptions($t_id) \n\n-------\nCHANGES:\n-------\n\n[ad_html_to_text [pm::util::word_diff -old [ad_html_to_text $my_old_description] -new [ad_html_to_text $descriptions($t_id)] -split_by " " -start_new "" -end_new ""]]" + + append intro_text "\nSee below to see the changes in the description" + append description_out "\n\n\nkey: _deleted_ *new* text\n" + } else { + set description_out [ad_html_to_text $descriptions($t_id)] + } + if {[string equal $use_uncertain_completion_times_p 1]} { set estimated_work " Hrs work (min): $est_hours_work_min($t_id) @@ -247,15 +329,19 @@ Hrs work: $est_hours_work($t_id)" } - set notification_text "------------- + + + set notification_text "$intro_text\n\n$comment_text------------- Task overview ------------- Task ID: \#$t_id -Description: $one_lines($t_id) +Subject: $one_lines($t_id) Project: $project_name Your role: $role_oneline($r_id) Link: $task_url + + --------------- Estimated work: ---------------$estimated_work @@ -271,7 +357,7 @@ ----------- Description ----------- -$descriptions($t_id)" +$description_out" acs_mail_lite::send \ Index: openacs-4/contrib/packages/project-manager/www/task-one.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/task-one.adp,v diff -u -r1.25 -r1.26 --- openacs-4/contrib/packages/project-manager/www/task-one.adp 29 Apr 2004 17:44:51 -0000 1.25 +++ openacs-4/contrib/packages/project-manager/www/task-one.adp 30 Apr 2004 01:42:58 -0000 1.26 @@ -69,11 +69,6 @@ - - - - - @@ -90,7 +85,7 @@ - +
Deadline@task_info.end_date@
Earliest start @task_info.earliest_start@
Latest finish@task_info.latest_start@@task_info.latest_start@
Index: openacs-4/contrib/packages/project-manager/www/task-one.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/task-one.tcl,v diff -u -r1.25 -r1.26 --- openacs-4/contrib/packages/project-manager/www/task-one.tcl 27 Apr 2004 00:49:29 -0000 1.25 +++ openacs-4/contrib/packages/project-manager/www/task-one.tcl 30 Apr 2004 01:42:58 -0000 1.26 @@ -89,11 +89,7 @@ set package_id [ad_conn package_id] set user_id [ad_maybe_redirect_for_registration] -set comments [general_comments_get_comments -print_content_p 1 -print_attachments_p 1 $task_id "[ad_conn url]?task_id=$task_id"] -set comments_link [general_comments_create_link -object_name pm_task -link_text "Add a comment" -context_id $package_id $task_id "[ad_conn url]?task_id=$task_id"] - - # permissions permission::require_permission -party_id $user_id -object_id $package_id -privilege read @@ -123,6 +119,15 @@ set closed_message "" } + +# set link to comments + +set comments [general_comments_get_comments -print_content_p 1 -print_attachments_p 1 $task_id "[ad_conn url]?task_id=$task_id"] + +set comments_link [general_comments_create_link -object_name "$task_term: $task_info(task_title)" -link_text "Add a comment" -context_id $package_id $task_id "[ad_conn url]?task_id=$task_id"] + + + # how to get back here set return_url "[ad_conn url]?[ad_conn query]"