bug-tracker-procs.tcl
Does not contain a contract.
- Location:
- /packages/bug-tracker/tcl/bug-tracker-procs.tcl
Related Files
- packages/bug-tracker/tcl/bug-tracker-procs.xql
- packages/bug-tracker/tcl/bug-tracker-procs.tcl
- packages/bug-tracker/tcl/bug-tracker-procs-postgresql.xql
- packages/bug-tracker/tcl/bug-tracker-procs-oracle.xql
[ hide source ] | [ make this the default ]
File Contents
ad_library { Bug Tracker Library @creation-date 2002-05-03 @author Lars Pind <lars@collaboraid.biz> @cvs-id bug-tracker-procs.tcl,v 1.13.2.7 2003/03/05 18:13:39 lars Exp } namespace eval bug_tracker {} ad_proc bug_tracker::conn { args } { global bt_conn set flag [lindex $args 0] if { [string index $flag 0] ne "-" } { set var $flag set flag "-get" } else { set var [lindex $args 1] } switch -- $flag { -set { set bt_conn($var) [lindex $args 2] } -get { if { [info exists bt_conn($var)] } { return $bt_conn($var) } else { switch -- $var { bug - bugs - Bug - Bugs - component - components - Component - Components - patch - patches - Patch - Patches { if { ![info exists bt_conn($var)] } { get_pretty_names -array bt_conn } return $bt_conn($var) } project_name - project_description - project_root_keyword_id - project_folder_id - current_version_id - current_version_name { array set info [get_project_info] foreach name [array names info] { set bt_conn($name) $info($name) } return $bt_conn($var) } user_first_names - user_last_name - user_email - user_version_id - user_version_name { if { [ad_conn user_id] == 0 } { return "" } else { array set info [get_user_prefs] foreach name [array names info] { set bt_conn($name) $info($name) } return $bt_conn($var) } } component_id - filter - filter_human_readable - filter_where_clauses - filter_order_by_clause - filter_from_bug_clause { return {} } default { error "[_ bug-tracker.Unknown_variable]" } } } } default { error "[_ bug-tracker.Unknown_flag]" } } } d_proc bug_tracker::get_pretty_names { -array:required {-package_id ""} } { upvar $array row if { $package_id eq "" } { set package_id [ad_conn package_id] } set row(bug) [lang::util::localize [parameter::get -package_id $package_id -parameter "TicketPrettyName" -default "bug"]] set row(bugs) [lang::util::localize [parameter::get -package_id $package_id -parameter "TicketPrettyPlural" -default "bugs"]] set row(Bug) [string totitle $row(bug)] set row(Bugs) [string totitle $row(bugs)] set row(component) [lang::util::localize [parameter::get -package_id $package_id -parameter "ComponentPrettyName" -default "component"]] set row(components) [lang::util::localize [parameter::get -package_id $package_id -parameter "ComponentPrettyPlural" -default "components"]] set row(Component) [string totitle $row(component)] set row(Components) [string totitle $row(components)] set row(patch) [lang::util::localize [parameter::get -package_id $package_id -parameter "PatchPrettyName" -default "patch"]] set row(patches) [lang::util::localize [parameter::get -package_id $package_id -parameter "PatchPrettyPlural" -default "patches"]] set row(Patch) [string totitle $row(patch)] set row(Patches) [string totitle $row(patches)] } d_proc bug_tracker::get_bug_id { {-bug_number:required} {-project_id:required} } { return [db_string bug_id {}] } d_proc bug_tracker::get_page_variables { {extra_spec ""} } { Adds the bug listing filter variables for use in the page contract. ad_page_contract { doc } [bug_tracker::get_page_variables { foo:integer { bar "" } }] } { set filter_vars { page:naturalnum,optional f_state:integer,optional f_fix_for_version:integer,optional f_distribution:integer,optional f_component:integer,optional orderby:token,optional project_id:naturalnum,optional {format:word "table"} } foreach { parent_id parent_heading } [bug_tracker::category_types] { lappend filter_vars "f_category_$parent_id:naturalnum,optional" } try { bug_tracker::bug::get_instance_workflow_id } on ok {workflow_id} { foreach action_id [workflow::get_actions -workflow_id $workflow_id] { lappend filter_vars "f_action_$action_id:naturalnum,optional" } } on error {errorMsg} { ns_log notice "bug_tracker::get_page_variables called on non-workflow package" } return [concat $filter_vars $extra_spec] } d_proc bug_tracker::get_export_variables { {-package_id ""} {extra_vars ""} } { Gets a list of variables to export for the bug list } { if { $package_id eq "" } { set package_id [ad_conn package_id] } set export_vars { f_state f_fix_for_version f_distribution f_component orderby format page } foreach { parent_id parent_heading } [bug_tracker::category_types] { lappend export_vars "f_category_$parent_id" } foreach action_id [workflow::get_actions \ -workflow_id [bug_tracker::bug::get_instance_workflow_id \ -package_id $package_id]] { lappend export_vars "f_action_$action_id" } return [concat $export_vars $extra_vars] } ##### # # Cached project info procs # ##### d_proc bug_tracker::get_project_info_internal { package_id } { db_1row project_info {} -column_array result return [array get result] } d_proc bug_tracker::get_project_info { {-package_id ""} } { if { $package_id eq "" } { set package_id [ad_conn package_id] } return [util_memoize [list bug_tracker::get_project_info_internal $package_id]] } d_proc bug_tracker::get_project_info_flush { {-package_id ""} } { if { $package_id eq "" } { set package_id [ad_conn package_id] } util_memoize_flush [list bug_tracker::get_project_info_internal $package_id] } d_proc bug_tracker::set_project_name { {-package_id ""} project_name } { if { $package_id eq "" } { set package_id [ad_conn package_id] } db_dml project_name_update {} # Flush cache util_memoize_flush [list bug_tracker::get_project_info_internal $package_id]] } ##### # # Stats procs # ##### d_proc -public bug_tracker::bugs_exist_p { {-package_id {}} } { Returns whether any bugs exist in a project } { if { $package_id eq "" } { set package_id [ad_conn package_id] } return [util_memoize [list bug_tracker::bugs_exist_p_not_cached -package_id $package_id]] } d_proc -public bug_tracker::bugs_exist_p_set_true { {-package_id {}} } { Sets bug_exists_p true. Useful for when you add a new bug, so you know that a bug will exist. } { if { $package_id eq "" } { set package_id [ad_conn package_id] } return [util_memoize_seed [list bug_tracker::bugs_exist_p_not_cached -package_id $package_id] 1] } d_proc -public bug_tracker::bugs_exist_p_not_cached { -package_id:required } { Returns whether any bugs exist in a project. Not cached. } { return [db_string select_bugs_exist_p {} -default 0] } ##### # # Cached user prefs procs # ##### d_proc bug_tracker::get_user_prefs_internal { package_id user_id } { set found_p [db_0or1row user_info { } -column_array result] if { !$found_p } { set count [db_string count_user_prefs {}] if { $count == 0 } { db_dml create_user_prefs {} # we call ourselves again, so we'll get the info this time return [get_user_prefs_internal $package_id $user_id] } else { error "[_ bug-tracker.No_user_in_database]" } } else { return [array get result] } } d_proc bug_tracker::get_user_prefs { {-package_id ""} -user_id } { if { $package_id eq "" } { set package_id [ad_conn package_id] } if { ![info exists user_id] } { set user_id [ad_conn user_id] } return [util_memoize [list bug_tracker::get_user_prefs_internal $package_id $user_id]] } d_proc bug_tracker::get_user_prefs_flush { {-package_id ""} -user_id } { if { $package_id eq "" } { set package_id [ad_conn package_id] } if { ![info exists user_id] } { set user_id [ad_conn user_id] } util_memoize_flush [list bug_tracker::get_user_prefs_internal $package_id $user_id] } ##### # # Status # ##### d_proc bug_tracker::status_get_options { {-package_id ""} } { if { $package_id eq "" } { set package_id [ad_conn package_id] } set workflow_id [bug_tracker::bug::get_instance_workflow_id -package_id $package_id] set state_ids [workflow::fsm::get_states -workflow_id $workflow_id] set option_list [list] foreach state_id $state_ids { workflow::state::fsm::get -state_id $state_id -array state lappend option_list [list "$state(pretty_name)" $state(short_name)] } return $option_list } d_proc bug_tracker::status_pretty { status } { set workflow_id [bug_tracker::bug::get_instance_workflow_id] if { [catch {set state_id [workflow::state::fsm::get_id -workflow_id $workflow_id -short_name $status]} error] } { return "" } workflow::state::fsm::get -state_id $state_id -array state return $state(pretty_name) } ad_proc bug_tracker::patch_status_get_options {} { return \ [list \ [list "[_ bug-tracker.Open]" open ] \ [list "[_ bug-tracker.Accepted]" accepted ] \ [list "[_ bug-tracker.Refused]" refused ] \ [list "[_ bug-tracker.Deleted]" deleted ] \ ] } d_proc bug_tracker::patch_status_pretty { status } { array set status_codes { open bug-tracker.Open accepted bug-tracker.Accepted refused bug-tracker.Refused deleted bug-tracker.Deleted } if { [info exists status_codes($status)] } { return [_ $status_codes($status)] } else { return {} } } ##### # # Resolution # ##### ad_proc bug_tracker::resolution_get_options {} { return \ [list \ [list [_ bug-tracker.Fixed] fixed ] \ [list [_ bug-tracker.By_Design] bydesign ] \ [list [_ bug-tracker.Wont_Fix] wontfix ] \ [list [_ bug-tracker.Postponed] postponed ] \ [list [_ bug-tracker.Duplicate] duplicate ] \ [list [_ bug-tracker.Not_Reproducible] norepro ] \ [list [_ bug-tracker.Need_Info] needinfo ] \ ] } d_proc bug_tracker::resolution_pretty { resolution } { array set resolution_codes { fixed bug-tracker.Fixed bydesign bug-tracker.By_Design wontfix bug-tracker.Wont_Fix postponed bug-tracker.Postponed duplicate bug-tracker.Duplicate norepro bug-tracker.Not_Reproducible needinfo bug-tracker.Need_Info } if { [info exists resolution_codes($resolution)] } { return [_ $resolution_codes($resolution)] } else { return "" } } ##### # # Categories/Keywords # ##### d_proc bug_tracker::category_parent_heading { {-package_id ""} -keyword_id:required } { return [bug_tracker::category_parent_element -package_id $pcakage_id -keyword_id $keyword_id -element heading] } # TODO: This could be made faster if we do a reverse mapping array from child to parent d_proc bug_tracker::category_parent_element { {-package_id ""} -keyword_id:required {-element "heading"} } { foreach elm [get_keywords -package_id $package_id] { set child_id [lindex $elm 0] if { $child_id == $keyword_id } { set parent(id) [lindex $elm 2] set parent(heading) [lindex $elm 3] return $parent($element) } } } d_proc bug_tracker::category_heading { {-package_id ""} -keyword_id:required } { foreach elm [get_keywords -package_id $package_id] { lassign $elm child_id child_heading parent_id parent_heading if { $child_id == $keyword_id } { return $child_heading } elseif { $parent_id == $keyword_id } { return $parent_heading } } } d_proc bug_tracker::category_types { {-package_id ""} } { @return Returns the category types for this instance as an array-list of { parent_id1 heading1 parent_id2 heading2 ... } } { array set heading [list] set parent_ids [list] set last_parent_id {} foreach elm [get_keywords -package_id $package_id] { lassign $elm child_id child_heading parent_id parent_heading if { $parent_id != $last_parent_id } { set heading($parent_id) $parent_heading lappend parent_ids $parent_id set last_parent_id $parent_id } } set result [list] foreach parent_id $parent_ids { lappend result $parent_id $heading($parent_id) } return $result } d_proc bug_tracker::category_get_filter_data_not_cached { {-package_id:required} {-parent_id:required} {-user_id ""} {-admin_p "f"} {-user_bugs_only_p "f"} } { @param package_id The package (project) to select from @param parent_id The category type's keyword_id @return list-of-lists with category data for filter } { return [db_list_of_lists select {}] } d_proc bug_tracker::category_get_filter_data { {-package_id:required} {-parent_id:required} {-user_id ""} {-admin_p "f"} } { @param package_id The package (project) to select from @param parent_id The category type's keyword_id @return list-of-lists with category data for filter } { set user_bugs_only_p [bug_tracker::user_bugs_only_p] return [util_memoize [list bug_tracker::category_get_filter_data_not_cached \ -package_id $package_id \ -parent_id $parent_id \ -user_id $user_id \ -admin_p $admin_p \ -user_bugs_only_p $user_bugs_only_p]] } d_proc bug_tracker::category_get_options { {-package_id ""} {-parent_id:required} } { @param parent_id The category type's keyword_id @return options-list for a select widget for the given category type } { set options [list] foreach elm [get_keywords -package_id $package_id] { lassign $elm elm_child_id elm_child_heading elm_parent_id if { $elm_parent_id == $parent_id } { lappend options [list $elm_child_heading $elm_child_id] } } return $options } ## Cache maintenance d_proc -private bug_tracker::get_keywords { {-package_id ""} } { if { $package_id eq "" } { set package_id [ad_conn package_id] } return [util_memoize [list bug_tracker::get_keywords_not_cached -package_id $package_id]] } d_proc -private bug_tracker::get_keywords_flush { {-package_id ""} } { if { $package_id eq "" } { set package_id [ad_conn package_id] } util_memoize_flush [list bug_tracker::get_keywords_not_cached -package_id $package_id] } d_proc -private bug_tracker::get_keywords_not_cached { -package_id:required } { return [db_list_of_lists select_package_keywords {}] } d_proc -public bug_tracker::set_default_keyword { {-package_id ""} {-parent_id:required} {-keyword_id:required} } { Set the default keyword for a given type (parent) } { if { $package_id eq "" } { set package_id [ad_conn package_id] } db_dml delete_existing { delete from bt_default_keywords where project_id = :package_id and parent_id = :parent_id } db_dml insert_new { insert into bt_default_keywords (project_id, parent_id, keyword_id) values (:package_id, :parent_id, :keyword_id) } get_default_keyword_flush -package_id $package_id -parent_id $parent_id } d_proc -public bug_tracker::get_default_keyword { {-package_id ""} {-parent_id:required} } { Get the default keyword for a given type (parent) } { if { $package_id eq "" } { set package_id [ad_conn package_id] } return [util_memoize [list bug_tracker::get_default_keyword_not_cached -package_id $package_id -parent_id $parent_id]] } d_proc -public bug_tracker::get_default_keyword_flush { {-package_id ""} {-parent_id:required} } { Flush the cache for } { if { $package_id eq "" } { set package_id [ad_conn package_id] } util_memoize_flush [list bug_tracker::get_default_keyword_not_cached -package_id $package_id -parent_id $parent_id] } d_proc -private bug_tracker::get_default_keyword_not_cached { {-package_id:required} {-parent_id:required} } { Get the default keyword for a given type (parent), not cached. } { return [db_string default { select keyword_id from bt_default_keywords where project_id = :package_id and parent_id = :parent_id } -default {}] } ad_proc -public bug_tracker::get_default_configurations {} { Get the package's default configurations for categories and parameters. } { return [list \ [_ bug-tracker.Bug_Tracker] [list \ categories [list \ "[_ bug-tracker.Bug_Type]" [list \ "[_ bug-tracker.Bug_Bug_cat]" \ "[_ bug-tracker.Bug_Sug_Cat]" \ ] \ "[_ bug-tracker.Priority]" [list \ "[_ bug-tracker.Prio_High_Cat]" \ "[_ bug-tracker.Prio_Norm_Cat]" \ "[_ bug-tracker.Prio_Low_Cat]" \ ] \ "[_ bug-tracker.Severity]" [list \ "[_ bug-tracker.Sev_Critical_Cat]" \ "[_ bug-tracker.Sev_Major_Cat]" \ "[_ bug-tracker.Sev_Normal_Cat]" \ "[_ bug-tracker.Sev_Minor_Cat]" \ ] \ ] \ parameters { TicketPrettyName "bug" TicketPrettyPlural "bugs" ComponentPrettyName "component" ComponentPrettyPlural "components" PatchesP "1" VersionsP "1" RelatedFilesP "1" } \ ] \ [_ bug-tracker.Ticket_Tracker] [list \ categories [list \ "[_ bug-tracker.Ticket_Type]" [list \ "[_ bug-tracker.Ticket_Todo_Cat]" \ "[_ bug-tracker.Ticket_Sugg_Cat]" \ ] \ "[_ bug-tracker.Priority]" [list \ "[_ bug-tracker.Prio_High_Cat]" \ "[_ bug-tracker.Prio_Norm_Cat]" \ "[_ bug-tracker.Prio_Low_Cat]" \ ] \ ] \ parameters { TicketPrettyName "ticket" TicketPrettyPlural "tickets" ComponentPrettyName "area" ComponentPrettyPlural "areas" PatchesP "0" VersionsP "0" RelatedFilesP "1" } \ ] \ [_ bug-tracker.Support_Center] [list \ categories [list \ "[_ bug-tracker.Message_Type]" [list \ "[_ bug-tracker.Support_Problem]" \ "[_ bug-tracker.Support_Suggestion]" \ "[_ bug-tracker.Support_Error]" \ ] \ "[_ bug-tracker.Priority]" [list \ "[_ bug-tracker.Prio_High_Cat]" \ "[_ bug-tracker.Prio_Norm_Cat]" \ "[_ bug-tracker.Prio_Low_Cat]" \ ] \ ] \ parameters { TicketPrettyName "message" TicketPrettyPlural "messages" ComponentPrettyName "area" ComponentPrettyPlural "areas" PatchesP "0" VersionsP "0" RelatedFilesP "1" } \ ] \ ] } d_proc -public bug_tracker::delete_all_project_keywords { {-package_id ""} } { Deletes all the keywords in a project } { if { $package_id eq "" } { set package_id [ad_conn package_id] } db_exec_plsql keywords_delete {} bug_tracker::get_keywords_flush -package_id $package_id } d_proc -public bug_tracker::install_keywords_setup { {-package_id ""} -spec:required } { @param spec is an array-list of { Type1 { cat1 cat2 cat3 } Type2 { cat1 cat2 cat3 } } Default category within type is denoted by letting the name start with a *, which is removed before creating the keyword. } { set root_keyword_id [bug_tracker::conn project_root_keyword_id -package_id $package_id] foreach { category_type categories } $spec { set category_type_id [content::keyword::get_keyword_id \ -parent_id $root_keyword_id \ -heading $category_type] if { $category_type_id eq "" } { set category_type_id [content::keyword::new \ -parent_id $root_keyword_id \ -heading $category_type] } foreach category $categories { if {[string index $category 0] eq "*"} { set default_p 1 set category [string range $category 1 end] } else { set default_p 0 } set category_id [content::keyword::get_keyword_id \ -parent_id $category_type_id \ -heading $category] if { $category_id eq "" } { set category_id [content::keyword::new \ -parent_id $category_type_id \ -heading $category] } if { $default_p } { bug_tracker::set_default_keyword \ -package_id $package_id \ -parent_id $category_type_id \ -keyword_id $category_id } } } bug_tracker::get_keywords_flush -package_id $package_id } d_proc -public bug_tracker::install_parameters_setup { {-package_id ""} -spec:required } { @param parameters as an array-list of { name value name value ... } } { foreach { name value } $spec { parameter::set_value -package_id $package_id -parameter $name -value $value } } ##### # # Versions # ##### d_proc bug_tracker::version_get_options { {-package_id ""} -include_unknown:boolean -include_undecided:boolean } { if { $package_id eq "" } { set package_id [ad_conn package_id] } set versions_list [util_memoize [list bug_tracker::version_get_options_not_cached $package_id]] if { $include_unknown_p } { set versions_list [concat [list [list [_ bug-tracker.Unknown] "" ] ] $versions_list] } if { $include_undecided_p } { set versions_list [concat [list [list [_ bug-tracker.Undecided] "" ] ] $versions_list] } return $versions_list } d_proc bug_tracker::assignee_get_options { -workflow_id -include_unknown:boolean -include_undecided:boolean } { Returns an option list containing all users that have submitted or assigned to a bug. Used for the add bug form. Added because the workflow api requires a case_id. (an item to evaluate is refactoring workflow to provide an assignee widget without a case_id) } { set assignee_list [db_list_of_lists assignees {}] if { $include_unknown_p } { set assignee_list [concat { { "Unknown" "" } } $assignee_list] } if { $include_undecided_p } { set assignee_list [concat { { "Undecided" "" } } $assignee_list] } return $assignee_list } d_proc bug_tracker::assignee_get_options { -workflow_id -include_unknown:boolean -include_undecided:boolean } { Returns an option list containing all users that have submitted or assigned to a bug. Used for the add bug form. Added because the workflow api requires a case_id. (an item to evaluate is refactoring workflow to provide an assignee widget without a case_id) } { set assignee_list [db_list_of_lists assignees {}] if { $include_unknown_p } { set assignee_list [concat { { "Unknown" "" } } $assignee_list] } if { $include_undecided_p } { set assignee_list [concat { { "Undecided" "" } } $assignee_list] } return $assignee_list } d_proc bug_tracker::versions_p { {-package_id ""} } { Is the versions feature turned on? } { if { $package_id eq "" } { set package_id [ad_conn package_id] } return [parameter::get -package_id $package_id -parameter "VersionsP" -default 1] } ad_proc bug_tracker::versions_flush {} { set package_id [ad_conn package_id] util_memoize_flush [list bug_tracker::version_get_options_not_cached $package_id] } d_proc bug_tracker::version_get_options_not_cached { package_id } { set versions_list [db_list_of_lists versions {}] return $versions_list } d_proc bug_tracker::version_get_name { {-package_id ""} {-version_id:required} } { if { $version_id eq "" } { return {} } foreach elm [version_get_options -package_id $package_id] { lassign $elm name id if {$id eq $version_id} { return $name } } error [_ bug-tracker.Version_id [list version_id $version_id]] } ##### # # Components # ##### d_proc bug_tracker::component_get_filter_data_not_cached { {-package_id:required} {-user_id ""} {-admin_p "f"} {-user_bugs_only_p "f"} } { @param package_id The project we're interested in @return list-of-lists with component data for filter } { return [db_list_of_lists select {}] } d_proc bug_tracker::component_get_filter_data { {-package_id:required} {-user_id ""} {-admin_p "f"} } { @param package_id The project we're interested in @return list-of-lists with component data for filter } { set user_bugs_only_p [bug_tracker::user_bugs_only_p] return [util_memoize [list bug_tracker::component_get_filter_data_not_cached \ -package_id $package_id \ -user_id $user_id \ -admin_p $admin_p \ -user_bugs_only_p $user_bugs_only_p]] } d_proc bug_tracker::components_get_options { {-package_id ""} -include_unknown:boolean } { if { $package_id eq "" } { set package_id [ad_conn package_id] } set components_list [util_memoize [list bug_tracker::components_get_options_not_cached $package_id]] if { $include_unknown_p } { set components_list [concat [list [list "[_ bug-tracker.Unknown]" {} ]] $components_list] } return $components_list } ad_proc bug_tracker::components_flush {} { set package_id [ad_conn package_id] util_memoize_flush [list bug_tracker::components_get_options_not_cached $package_id] util_memoize_flush [list bug_tracker::components_get_url_names_not_cached -package_id $package_id] } d_proc bug_tracker::components_get_options_not_cached { package_id } { set components_list [db_list_of_lists components {}] return $components_list } d_proc bug_tracker::component_get_name { {-package_id ""} {-component_id:required} } { if { $component_id eq "" } { return {} } foreach elm [components_get_options -package_id $package_id] { set id [lindex $elm 1] if {$id eq $component_id} { return [lindex $elm 0] } } error [_ bug-tracker.Component_id_not_found] } d_proc bug_tracker::component_get_url_name { {-package_id ""} {-component_id:required} } { if { $component_id eq "" } { return {} } foreach { id url_name } [components_get_url_names -package_id $package_id] { if {$id eq $component_id} { return $url_name } } return {} } d_proc bug_tracker::components_get_url_names { {-package_id ""} } { if { $package_id eq "" } { set package_id [ad_conn package_id] } return [util_memoize [list bug_tracker::components_get_url_names_not_cached -package_id $package_id]] } d_proc bug_tracker::components_get_url_names_not_cached { {-package_id:required} } { db_foreach select_component_url_names {} { lappend result $component_id $url_name } return $result } ##### # # Description (still used by the patch code, to be removed when they've moved to workflow) # ##### d_proc bug_tracker::bug_convert_comment_to_html { {-comment:required} {-format:required} } { return [ad_html_text_convert -from $format -to text/html -- $comment] } d_proc bug_tracker::bug_convert_comment_to_text { {-comment:required} {-format:required} } { return [ad_html_text_convert -from $format -to text/plain -- $comment] } ##### # # Actions # ##### d_proc bug_tracker::patch_action_pretty { action } { array set action_codes { open bug-tracker.Opened edit bug-tracker.Edited comment bug-tracker.Comment accept bug-tracker.Accepted reopen bug-tracker.Reopened refuse bug-tracker.Refused delete bug-tracker.Deleted } if { [info exists action_codes($action)] } { return [_ $action_codes($action)] } else { return "" } } ##### # # Maintainers # ##### d_proc ::bug_tracker::users_get_options { {-package_id ""} } { if { $package_id eq "" } { set package_id [ad_conn package_id] } set user_id [ad_conn user_id] # This picks out users who are already assigned to some bug in this set sql { select first_names || ' ' || last_name || ' (' || email || ')' as name, user_id from cc_users where user_id in ( select maintainer from bt_projects where project_id = :package_id union select maintainer from bt_versions where project_id = :package_id union select maintainer from bt_components where project_id = :package_id ) or user_id = :user_id order by name } set users_list [db_list_of_lists users $sql] set users_list [concat [list [list [_ bug-tracker.Unassigned] "" ]] $users_list] lappend users_list [list [_ bug-tracker.Search] ":search:"] return $users_list } ##### # # Patches # ##### ad_proc bug_tracker::patches_p {} { Is the patch submission feature turned on? } { return [parameter::get -package_id [ad_conn package_id] -parameter "PatchesP" -default 1] } d_proc bug_tracker::map_patch_to_bug { {-patch_id:required} {-bug_id:required} } { db_dml map_patch_to_bug {} } d_proc bug_tracker::unmap_patch_from_bug { {-patch_number:required} {-bug_number:required} } { set package_id [ad_conn package_id] db_dml unmap_patch_from_bug {} } d_proc bug_tracker::get_mapped_bugs { {-patch_number:required} {-only_open_p "0"} } { Return a list of lists with the bug number in the first element and the bug summary in the second. } { set bug_list [list] set package_id [ad_conn package_id] if { $only_open_p } { set workflow_id [bug_tracker::bug::get_instance_workflow_id] set initial_state [workflow::fsm::get_initial_state -workflow_id $workflow_id] set open_clause "\n and exists (select 1 from workflow_cases cas, workflow_case_fsm cfsm where cas.case_id = cfsm.case_id and cas.object_id = b.bug_id and cfsm.current_state = :initial_state)" } else { set open_clause "" } db_foreach get_bugs_for_patch {} { lappend bug_list [list "[bug_tracker::conn Bug] #$bug_number: $summary" "$bug_number"] } return $bug_list } d_proc bug_tracker::get_bug_links { {-patch_id:required} {-patch_number:required} {-write_or_submitter_p:required} } { set bug_list [get_mapped_bugs -patch_number $patch_number] set bug_link_list [list] if { [llength $bug_list] == 0} { return "" } else { foreach bug_item $bug_list { lassign $bug_item bug_summary bug_number set unmap_url [export_vars -base unmap-patch-from-bug -url { patch_number bug_number } ] if { $write_or_submitter_p } { set unmap_link [subst {(<a href="[ns_quotehtml $unmap_url]">[_ bug-tracker.unmap]</a>)}] } else { set unmap_link "" } lappend bug_link_list "<a href=\"bug?bug_number=$bug_number \">$bug_summary</a> $unmap_link" } if { [llength $bug_link_list] != 0 } { set bugs_string [join $bug_link_list "<br>"] } else { set bugs_name [bug_tracker::conn bugs] set bugs_string [_ bug-tracker.No_Bugs] } return $bugs_string } } d_proc bug_tracker::get_patch_links { {-bug_id:required} {-show_patch_status open} } { set patch_list [list] switch -- $show_patch_status { open { set status_where_clause "and bt_patches.status = :show_patch_status" } all { set status_where_clause "" } } db_foreach get_patches_for_bug {} { set status_indicator [expr {$show_patch_status eq "all" ? "($status)" : ""}] lappend patch_list "<a href=\"patch?patch_number=$patch_number\" title=\"patch $patch_number\">[ns_quotehtml $summary]</a> $status_indicator" } if_no_rows { set patches_name [bug_tracker::conn patches] set patches_string [_ bug-tracker.No_patches] } if { [llength $patch_list] != 0 } { set patches_string [join $patch_list ", "] } return $patches_string } d_proc bug_tracker::get_patch_submitter { {-patch_number:required} } { set package_id [ad_conn package_id] return [db_string patch_submitter_id {}] } d_proc bug_tracker::update_patch_status { {-patch_number:required} {-new_status:required} } { set package_id [ad_conn package_id] db_dml update_patch_status "" } d_proc bug_tracker::get_uploaded_patch_file_content { } { set patch_file [ns_queryget patch_file] if { $patch_file eq "" } { # No patch file was uploaded return "" } set tmp_file [ns_queryget patch_file.tmpfile] set tmp_file_channel [open $tmp_file r] set content [read $tmp_file_channel] close $tmp_file_channel return $content } d_proc bug_tracker::security_violation { -user_id:required -bug_id:required -action_id:required } { workflow::action::get -action_id $enabled_action(action_id) -array action bug_tracker::bug::get -bug_id $bug_id -array bug ns_log notice "bug_tracker::security_violation: $user_id doesn't have permission to '$action(pretty_name)' on bug $bug(summary)" ad_return_forbidden \ [_ bug-tracker.Permission_Denied] \ "<blockquote>[_ bug-tracker.No_Permission_to_do_action]</blockquote>" ad_script_abort } ##### # # Projects # ##### ad_proc bug_tracker::project_delete { project_id } { Delete a Bug Tracker project and all its data. @author Peter Marklund } { #manually delete all bugs to avoid weird integrity constraints while { [set bug_id [db_string min_bug_id {}]] > 0 } { bug_tracker::bug::delete $bug_id } db_exec_plsql delete_project {} } ad_proc bug_tracker::project_new { project_id } { Create a new Bug Tracker project for a package instance. @author Peter Marklund } { if {![db_0or1row already_there {select 1 from bt_projects where project_id = :project_id} ] } { if {[db_0or1row instance_info { *SQL* } ]} { set folder_id [content::folder::new -name "bug_tracker_$project_id" \ -package_id $project_id \ -parent_id $project_id \ -context_id $project_id] content::folder::register_content_type -folder_id $folder_id -content_type {bt_bug_revision} -include_subtypes t content::folder::register_content_type -folder_id $folder_id -content_type "content_revision" content::folder::register_content_type -folder_id $folder_id -content_type "image" set keyword_id [content::keyword::new -heading "$instance_name"] set component_keyword_id [content::keyword::new -heading "Components $instance_name"] # Inserts into bt_projects set component_id [db_nextval acs_object_id_seq] db_dml bt_projects_insert {} db_dml bt_components_insert {} } } } d_proc bug_tracker::version_get_filter_data_not_cached { {-package_id:required} {-user_id ""} {-admin_p "f"} {-user_bugs_only_p "f"} } { @param package_id The package (project) to select from @return list-of-lists with fix-for-version data for filter } { return [db_list_of_lists select {}] } d_proc bug_tracker::version_get_filter_data { {-package_id:required} {-user_id ""} {-admin_p "f"} } { @param package_id The package (project) to select from @param user_id The user to filter by for the ShowMyBugsOnlyP parameter @return list-of-lists with fix-for-version data for filter } { set user_bugs_only_p [bug_tracker::user_bugs_only_p] return [util_memoize [list bug_tracker::version_get_filter_data_not_cached \ -package_id $package_id \ -user_id $user_id \ -admin_p $admin_p \ -user_bugs_only_p $user_bugs_only_p]] } d_proc bug_tracker::assignee_get_filter_data_not_cached { {-package_id:required} {-workflow_id:required} {-action_id:required} {-user_id ""} {-admin_p "f"} {-user_bugs_only_p "f"} } { @param package_id The package (project) to select from @param workflow_id The workflow we're interested in @param action_id The action we're interested in @param user_id User id for optional filtering for logged in user @return list-of-lists with assignee data for filter } { return [db_list_of_lists select {}] } d_proc bug_tracker::assignee_get_filter_data { {-package_id:required} {-workflow_id:required} {-action_id:required} {-user_id ""} {-admin_p "f"} } { @param package_id The package (project) to select from @param workflow_id The workflow we're interested in @param action_id The action we're interested in @param user_id Optional user for filtering by logged in user. @return list-of-lists with assignee data for filter } { set user_bugs_only_p [bug_tracker::user_bugs_only_p] return [util_memoize [list bug_tracker::assignee_get_filter_data_not_cached \ -package_id $package_id \ -workflow_id $workflow_id \ -action_id $action_id \ -user_id $user_id \ -admin_p $admin_p \ -user_bugs_only_p $user_bugs_only_p]] } d_proc bug_tracker::state_get_filter_data_not_cached { {-package_id:required} {-workflow_id:required} {-user_id ""} {-admin_p "f"} {-user_bugs_only_p "f"} } { @param package_id The package (project) to select from @param workflow_id The workflow we're interested in @return list-of-lists with state data for filter } { return [db_list_of_lists select {}] } d_proc bug_tracker::state_get_filter_data { {-package_id:required} {-workflow_id:required} {-user_id ""} {-admin_p "f"} } { @param package_id The package (project) to select from @param workflow_id The workflow we're interested in @return list-of-lists with state data for filter } { set user_bugs_only_p [bug_tracker::user_bugs_only_p] return [util_memoize [list bug_tracker::state_get_filter_data_not_cached \ -package_id $package_id \ -workflow_id $workflow_id \ -user_id $user_id \ -admin_p $admin_p \ -user_bugs_only_p $user_bugs_only_p]] } ##### # # Related Files # ##### ad_proc bug_tracker::related_files_p {} { Is the related files submission feature turned on? } { return [parameter::get -package_id [ad_conn package_id] -parameter "RelatedFilesP" -default 1] } d_proc bug_tracker::get_related_files_links { {-bug_id:required} } { set related_files_list [list] set user_id [ad_conn user_id] set admin_p [permission::permission_p \ -party_id $user_id \ -object_id [ad_conn package_id] \ -privilege "admin"] set return_url [ad_return_url] db_foreach get_related_files_for_bug {} { set view_url [export_vars -base related-file-download {bug_id related_object_id {t $related_revision_id}}] set properties_url [export_vars -base "related-file-properties" {bug_id related_object_id}] set delete_url [export_vars -base "related-file-delete" {bug_id related_object_id return_url}] set new_version_url [export_vars -base "related-file-update" {bug_id related_object_id return_url}] if { $related_creation_user == $user_id || $admin_p } { set extra_actions [subst { | <a href="[ns_quotehtml $new_version_url]">[_ bug-tracker.upload_new_version]</a> | <a href="[ns_quotehtml $delete_url]">[_ bug-tracker.delete]</a> }] } else { set extra_actions "" } lappend related_files_list [subst {$related_title <a href="[ns_quotehtml $view_url]">[_ bug-tracker.download]</a> | <a href="[ns_quotehtml $properties_url]">[_ bug-tracker.properties]</a>$extra_actions }] } if_no_rows { set related_files_string [_ bug-tracker.No_related_files] } if { [llength $related_files_list] != 0 } { set related_files_string [join $related_files_list "<br>"] } return $related_files_string } ##### # # Related Files # ##### ad_proc bug_tracker::related_files_p {} { Is the related files submission feature turned on? } { return [parameter::get -package_id [ad_conn package_id] -parameter "RelatedFilesP" -default 1] } d_proc bug_tracker::get_related_files_links { {-bug_id:required} } { set related_files_list [list] set user_id [ad_conn user_id] set admin_p [permission::permission_p \ -party_id $user_id \ -object_id [ad_conn package_id] \ -privilege "admin"] set return_url [ad_return_url] db_foreach get_related_files_for_bug {} { set view_url [export_vars -base related-file-download {bug_id related_object_id {t $related_revision_id}}] set properties_url [export_vars -base "related-file-properties" {bug_id related_object_id}] set delete_url [export_vars -base "related-file-delete" {bug_id related_object_id return_url}] set new_version_url [export_vars -base "related-file-update" {bug_id related_object_id return_url}] if { $related_creation_user == $user_id || $admin_p } { set extra_actions [subst { | <a href="[ns_quotehtml $new_version_url]">upload new version</a> | <a href="[ns_quotehtml $delete_url]">delete</a> }] } else { set extra_actions "" } lappend related_files_list [subst {$related_title <a href="[ns_quotehtml $view_url]">download</a> | <a href="[ns_quotehtml $properties_url]">properties</a>$extra_actions }] } if_no_rows { set related_files_string [_ bug-tracker.No_related_files] } if { [llength $related_files_list] != 0 } { set related_files_string [join $related_files_list "<br>"] } return $related_files_string } ad_proc -public bug_tracker::user_bugs_only_p {} { Is the user bugs only feature turned on? Admins always see all bugs. } { return [expr {[lindex [bug_tracker::access_policy] 1] eq "user_bugs"}] } d_proc -private bug_tracker::set_access_policy { {-all_bugs:boolean "f"} {-user_bugs:boolean "f"} } { Set/unset direct permissions on existing bugs. @param all_bugs The user can see all bugs @param user_bugs The user can only see the bugs they are participating in. } { if {$all_bugs_p && $user_bugs_p} { error "Select either -all_bugs or -user_bugs but not both" } set package_id [ad_conn package_id] set all_users [db_list get_all_users {}] if {$all_bugs_p} { set bug_ids [db_list get_all_bugs {}] foreach user_id $all_users { foreach bug_id $bug_ids { bug_tracker::inherit -bug_id $bug_id -party_id $user_id } } } elseif {$user_bugs_p} { foreach user_id $all_users { set bug_ids [db_list get_user_bugs {}] foreach bug_id $bug_ids { bug_tracker::grant_direct_read_permission -bug_id $bug_id -party_id $user_id } } } } d_proc -private bug_tracker::grant_direct_read_permission { {-bug_id:required} {-party_id:required} } { Grant direct read permissions } { permission::set_not_inherit -object_id $bug_id permission::grant -object_id $bug_id -party_id $party_id -privilege read } d_proc -private bug_tracker::inherit { {-bug_id:required} {-party_id:required} } { Grant direct read permissions } { permission::set_inherit -object_id $bug_id permission::revoke -object_id $bug_id -party_id $party_id -privilege read } ad_proc -public bug_tracker::access_policy {} { Detect and return the current access policy. } { set package_id [ad_conn package_id] db_1row get_bug {} if {[permission::inherit_p -object_id $bug_id]} { return [list "#bug-tracker.Show_all_bugs#" all_bugs] } else { return [list "#bug-tracker.Show_user_bugs_only#" user_bugs] } } ad_proc -private bug_tracker::user_bugs_only_where_clause {} { Return the where clause fragment if only user's bugs should appear } { if {[bug_tracker::user_bugs_only_p]} { return [db_map user_bugs_only] } } d_proc bug_tracker::get_component_keyword { {-package_id:required} } { @param package_id The package (project) to select from } { return [db_string get_component_keyword { select component_keyword_id from bt_projects where project_id = :package_id }] } # Local variables: # mode: tcl # tcl-indent-level: 4 # indent-tabs-mode: nil # End: