Index: openacs-4/packages/bug-tracker/bug-tracker.info =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/bug-tracker.info,v diff -u -r1.6.2.2 -r1.6.2.3 --- openacs-4/packages/bug-tracker/bug-tracker.info 9 Dec 2002 14:31:28 -0000 1.6.2.2 +++ openacs-4/packages/bug-tracker/bug-tracker.info 5 Mar 2003 18:12:19 -0000 1.6.2.3 @@ -6,17 +6,23 @@ Bug Trackers f f - - + + postgresql + oracle Lars Pind Tracks bugs and features, versions and maintainers, in software projects. Contains the best of SDM, Bugzilla, FogBUGZ, and bughost.com. - 2002-09-11 + 2003-02-28 Musea Technologies + + + + + @@ -90,8 +96,21 @@ + + + + + + + - + + + + + + + Index: openacs-4/packages/bug-tracker/lib/master.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/lib/master.adp,v diff -u -r1.2.2.1 -r1.2.2.2 --- openacs-4/packages/bug-tracker/lib/master.adp 10 Dec 2002 08:26:26 -0000 1.2.2.1 +++ openacs-4/packages/bug-tracker/lib/master.adp 5 Mar 2003 18:12:37 -0000 1.2.2.2 @@ -2,19 +2,115 @@ @title@ -@signatory +@signatory@ @focus@ /packages/bug-tracker/lib/version-bar -@context_bar@ + + @context_bar@ + + + @context@ + @@ -25,3 +121,4 @@

+ Index: openacs-4/packages/bug-tracker/lib/master.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/lib/master.tcl,v diff -u -r1.2 -r1.2.2.1 --- openacs-4/packages/bug-tracker/lib/master.tcl 11 Sep 2002 14:03:20 -0000 1.2 +++ openacs-4/packages/bug-tracker/lib/master.tcl 5 Mar 2003 18:12:37 -0000 1.2.2.1 @@ -8,10 +8,6 @@ set header $title } -if { ![info exists context_bar] } { - set header $context_bar -} - if { ![info exists notification_link] } { set notification_link "" } Index: openacs-4/packages/bug-tracker/lib/nav-bar.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/lib/nav-bar.tcl,v diff -u -r1.4.2.1 -r1.4.2.2 --- openacs-4/packages/bug-tracker/lib/nav-bar.tcl 13 Jan 2003 18:40:37 -0000 1.4.2.1 +++ openacs-4/packages/bug-tracker/lib/nav-bar.tcl 5 Mar 2003 18:12:37 -0000 1.4.2.2 @@ -11,12 +11,19 @@ set package_url [ad_conn package_url] set component_id [bug_tracker::conn component_id] -set admin_p [ad_permission_p $package_id admin] +set admin_p [permission::permission_p -object_id $package_id -privilege admin] +set create_p [expr { [ad_conn user_id] == 0 || [permission::permission_p -object_id [ad_conn package_id] -privilege create] }] set notification_url [lindex $notification_link 0] set notification_label [lindex $notification_link 1] set notification_title [lindex $notification_link 2] +# Paches enabled for this project? +set patches_p [bug_tracker::patches_p] + +# Is this project using multiple versions? +set versions_p [bug_tracker::versions_p] + regexp {/([^/]+)/[^/]*$} [ad_conn url] match last_dir if { [string equal $last_dir "admin"] } { @@ -30,23 +37,30 @@ array set filter [bug_tracker::conn filter] -multirow append links "Bugs" "${url_prefix}.?[export_vars { filter:array }]" +multirow append links "[bug_tracker::conn Bugs]" "${url_prefix}." -if { [ad_permission_p [ad_conn package_id] create] || [ad_conn user_id] == 0 } { - multirow append links "New Bug" "${url_prefix}bug-add" +if { $create_p } { + multirow append links "New [bug_tracker::conn Bug]" "${url_prefix}bug-add" } if { [ad_conn user_id] != 0 } { - multirow append links "My Bugs" "${url_prefix}.?[export_vars -url { { filter.actionby {[ad_conn user_id]} } }]" + multirow append links "My [bug_tracker::conn Bugs]" "${url_prefix}.?[export_vars -url { { filter.assignee {[ad_conn user_id]} } }]" } -multirow append links "Patches" "[ad_conn package_url]patch-list" +if { $patches_p } { + multirow append links "Patches" "[ad_conn package_url]patch-list" -if { [ad_permission_p [ad_conn package_id] create] || [ad_conn user_id] == 0 } { - multirow append links "New Patch" "[ad_conn package_url]patch-add" + if { $create_p } { + multirow append links "New Patch" "[ad_conn package_url]patch-add" + } } -multirow append links "Prefs" "[ad_conn package_url]prefs" +multirow append links "Notifications" "[ad_conn package_url]notifications" + +if { $versions_p } { + multirow append links "Prefs" "[ad_conn package_url]prefs" +} + if { $admin_p } { multirow append links "Admin" "[ad_conn package_url]admin/" } Index: openacs-4/packages/bug-tracker/lib/pagination.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/lib/pagination.adp,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/bug-tracker/lib/pagination.adp 11 Sep 2002 14:03:20 -0000 1.1 +++ openacs-4/packages/bug-tracker/lib/pagination.adp 5 Mar 2003 18:12:37 -0000 1.1.2.1 @@ -3,7 +3,7 @@
-Page with @pretty_plural@: [ @pagination_filter@ ]     Show @pretty_plural@ per page +Page with [ @pagination_filter@ ]     Show @pretty_plural@ per page
Index: openacs-4/packages/bug-tracker/lib/pagination.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/lib/pagination.tcl,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/bug-tracker/lib/pagination.tcl 11 Sep 2002 14:03:20 -0000 1.1 +++ openacs-4/packages/bug-tracker/lib/pagination.tcl 5 Mar 2003 18:12:37 -0000 1.1.2.1 @@ -17,8 +17,8 @@ lappend export_var_list $var_name } -set pagination_filter_base_url "[ad_conn url]?[export_vars -url -override { { offset 0 } } $export_var_list]" -set pagination_form_export_vars "[export_vars -form -override { { offset 0 } } $export_var_list]" +set pagination_filter_base_url "[ad_conn url]?[export_vars -url -exclude { offset } [concat $export_var_list interval_size]]" +set pagination_form_export_vars "[export_vars -form [concat $export_var_list offset]]" while { $interval_low <= $row_count } { Index: openacs-4/packages/bug-tracker/lib/version-bar.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/lib/version-bar.adp,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/bug-tracker/lib/version-bar.adp 3 May 2002 16:29:59 -0000 1.1 +++ openacs-4/packages/bug-tracker/lib/version-bar.adp 5 Mar 2003 18:12:37 -0000 1.1.2.1 @@ -5,22 +5,25 @@ Not logged in (log in) - - - - - Your version: @user_version_name@ - - | Current: @current_version_name@ + + + + + + Your version: @user_version_name@ + + | Current: @current_version_name@ + + + (current) + - (current) + Current version: @current_version_name@ - - - Current version: @current_version_name@ - - - - - \ No newline at end of file + + + + + + Index: openacs-4/packages/bug-tracker/lib/version-bar.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/lib/version-bar.tcl,v diff -u -r1.3 -r1.3.2.1 --- openacs-4/packages/bug-tracker/lib/version-bar.tcl 11 Sep 2002 14:03:20 -0000 1.3 +++ openacs-4/packages/bug-tracker/lib/version-bar.tcl 5 Mar 2003 18:12:37 -0000 1.3.2.1 @@ -17,8 +17,9 @@ set user_first_names [bug_tracker::conn user_first_names] set user_last_name [bug_tracker::conn user_last_name] +# Is this project using multiple versions? +set versions_p [bug_tracker::versions_p] - set package_url [ad_conn package_url] set user_version_url "[ad_conn package_url]prefs?[export_vars -url { return_url }]" Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `openacs-4/packages/bug-tracker/sql/postgresql/bug-tracker-code-stuff-cutout.sql'. Fisheye: No comparison available. Pass `N' to diff? Index: openacs-4/packages/bug-tracker/sql/postgresql/bug-tracker-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/sql/postgresql/bug-tracker-create.sql,v diff -u -r1.5.2.2 -r1.5.2.3 --- openacs-4/packages/bug-tracker/sql/postgresql/bug-tracker-create.sql 2 Mar 2003 22:39:33 -0000 1.5.2.2 +++ openacs-4/packages/bug-tracker/sql/postgresql/bug-tracker-create.sql 5 Mar 2003 18:13:18 -0000 1.5.2.3 @@ -14,73 +14,174 @@ email_subject_name text, maintainer integer constraint bt_projects_maintainer_fk - references users(user_id) + references users(user_id), + folder_id integer + constraint bt_projects_folder_fk + references cr_folders(folder_id), + root_keyword_id integer + constraint bt_projects_keyword_fk + references cr_keywords(keyword_id) ); -create function bt_project__new( +create or replace function bt_project__new( integer -- package_id ) returns integer as ' declare - new__package_id alias for $1; - rec record; - v_count integer; + p_package_id alias for $1; + v_count integer; + v_instance_name varchar; + v_creation_user integer; + v_creation_ip varchar; + v_folder_id integer; + v_keyword_id integer; begin select count(*) into v_count from bt_projects - where project_id = new__package_id; + where project_id = p_package_id; if v_count > 0 then return 0; end if; - -- insert the row into bt_projects - insert into bt_projects (project_id) values (new__package_id); + -- get instance name for the content folder + select p.instance_name, o.creation_user, o.creation_ip + into v_instance_name, v_creation_user, v_creation_ip + from apm_packages p join acs_objects o on (p.package_id = o.object_id) + where p.package_id = p_package_id; - -- copy over the default severity/priority codes - for rec in select * from bt_severity_codes where project_id is null loop - insert into bt_severity_codes - (severity_id, project_id, severity_name, sort_order, default_p) - select acs_object_id_seq.nextval, new__package_id, rec.severity_name, rec.sort_order, rec.default_p; - end loop; + -- create a root CR folder + v_folder_id := content_folder__new( + ''bug_tracker_''||p_package_id, -- name + v_instance_name, -- label + null, -- description + content_item_globals.c_root_folder_id -- parent_bi + ); - for rec in select * from bt_priority_codes where project_id is null loop - insert into bt_priority_codes - (priority_id, project_id, priority_name, sort_order, default_p) - select acs_object_id_seq.nextval, new__package_id, rec.priority_name, rec.sort_order, rec.default_p; - end loop; + -- register our content type + PERFORM content_folder__register_content_type ( + v_folder_id, -- folder_id + ''bt_bug_revision'', -- content_type + ''t'' -- include_subtypes + ); + -- create the instance root keyword + v_keyword_id := content_keyword__new( + v_instance_name, -- heading + null, -- description + null, -- parent_id + null, -- keyword_id + current_timestamp, -- creation_date + v_creation_user, -- creation_user + v_creation_ip, -- creation_ip + ''content_keyword'' -- object_type + ); + + -- insert the row into bt_projects + insert into bt_projects + (project_id, folder_id, root_keyword_id) + values + (p_package_id, v_folder_id, v_keyword_id); + -- Create a General component to start with insert into bt_components (component_id, project_id, component_name) - select acs_object_id_seq.nextval, new__package_id, ''General''; + select acs_object_id_seq.nextval, p_package_id, ''General''; return 0; end; ' language 'plpgsql'; -create function bt_project__delete( - integer -- package_id -) returns integer + +create or replace function bt_project__delete( + integer -- project_id +) returns integer as ' declare - delete__package_id alias for $1; + p_project_id alias for $1; + v_folder_id integer; + v_root_keyword_id integer; + rec record; begin - -- delete severity/priority codes - delete from bt_severity_codes where project_id = delete__package_id; - delete from bt_priority_codes where project_id = delete__package_id; + -- get the content folder for this instance + select folder_id, root_keyword_id + into v_folder_id, v_root_keyword_id + from bt_projects + where project_id = p_project_id; - -- delete the row from bt_projects - delete from bt_projects where project_id = delete__package_id; + -- This gets done in tcl before we are called ... for now + -- Delete the bugs + -- for rec in select item_id from cr_items where parent_id = v_folder_id + -- loop + -- perform bt_bug__delete(rec.item_id); + -- end loop; + -- Delete the patches + for rec in select patch_id from bt_patches where project_id = p_project_id + loop + perform bt_patch__delete(rec.patch_id); + end loop; + + -- delete the content folder + raise notice ''about to delete content_folder.''; + perform content_folder__delete(v_folder_id); + + -- delete the projects keywords + perform bt_projects__keywords_delete(p_project_id, ''t''); + + -- These tables should really be set up to cascade + delete from bt_versions where project_id = p_project_id; + delete from bt_components where project_id = p_project_id; + delete from bt_user_prefs where project_id = p_project_id; + + delete from bt_projects where project_id = p_project_id; + return 0; end; ' language 'plpgsql'; - +create or replace function bt_project__keywords_delete( + integer, -- project_id + bool -- delete_root_p +) returns integer +as ' +declare + p_project_id alias for $1; + p_delete_root_p alias for $1; + v_root_keyword_id integer; + rec record; +begin + -- get the content folder for this instance + select root_keyword_id + into v_root_keyword_id + from bt_projects + where project_id = p_project_id; - + -- if we are deleting the root, remove it from the project as well + if p_delete_root_p = 1 then + update bt_projects + set root_keyword_id = null + where project_id = p_project_id; + end if; + -- delete the projects keywords + for rec in + select k2.keyword_id + from cr_keywords k1, cr_keywords k2 + where k1.keyword_id = v_root_keyword_id + and k2.tree_sortkey between k1.tree_sortkey and tree_right(k1.tree_sortkey) + order by length(k2.tree_sortkey) desc + loop + if (p_delete_root_p = 1) or (rec.keyword_id != v_root_keyword_id) then + perform content_keyword__delete(rec.keyword_id); + end if; + end loop; + + return 0; +end; +' language 'plpgsql'; + + create table bt_versions ( version_id integer not null constraint bt_versions_pk @@ -114,7 +215,7 @@ -- but we just make a stored function that alters the active version -create function bt_version__set_active ( +create or replace function bt_version__set_active ( integer -- active_version_id ) returns integer as ' @@ -152,385 +253,349 @@ references users(user_id) ); +-- default keywords per keyword parent +-- e.g. default priority, default severity, etc. -create function bt_component__default_assignee( - integer -- component_id -) returns integer -as ' -declare - p_component_id alias for $1; - v_assignee integer; -begin - select maintainer - into v_assignee - from bt_components - where component_id = p_component_id; +create table bt_default_keywords ( + project_id integer not null + constraint bt_default_keywords_project_fk + references bt_projects(project_id) + on delete cascade, + parent_id integer not null + constraint bt_default_keyw_parent_keyw_fk + references cr_keywords(keyword_id) + on delete cascade, + keyword_id integer not null + constraint bt_default_keyw_keyword_fk + references cr_keywords(keyword_id) + on delete cascade, + constraint bt_default_keywords_prj_par_un + unique (project_id, parent_id) +); - if v_assignee is null then - select p.maintainer - into v_assignee - from bt_projects p, bt_components c - where p.project_id = c.project_id - and c.component_id = p_component_id; - end if; +create index bt_default_keyw_parent_id_idx on bt_default_keywords(parent_id); +create index bt_default_keyw_keyword_id_idx on bt_default_keywords(keyword_id); - return v_assignee; -end; -' language 'plpgsql'; - - -create table bt_severity_codes ( - severity_id integer not null - constraint bt_severity_codes_pk - primary key, - project_id integer - constraint bt_severity_codes_projects_fk - references bt_projects(project_id), - severity_name varchar(500) not null, - sort_order integer not null, - default_p char(1) not null - constraint bt_severity_codes_default_p_ck - check (default_p in ('t','f')) - default 'f', - constraint bt_severity_codes_name_un - unique(project_id, severity_name), - constraint bt_severity_codes_sort_order_un - unique(project_id, sort_order) +-- content_item subtype +create table bt_bugs( + bug_id integer + constraint bt_bug_pk + primary key + constraint bt_bug_bt_bug_fk + references cr_items(item_id) + on delete cascade, + -- this is the only column we really add here + bug_number integer, + -- the comment from the initial action + -- denormalized from a far-fetched workflow join + comment_content text, + comment_format varchar(200), + -- denormalized from cr_items + parent_id integer, + live_revision_id integer, + -- denormalized from cr_revisions.title + summary varchar(1000), + -- denormalized from bt_projects + project_id integer, + -- denormalized from bt_bug_revisions + component_id integer, + resolution varchar(50), + user_agent varchar(500), + found_in_version integer, + fix_for_version integer, + fixed_in_version integer, + -- denormalized from acs_objects + creation_date timestamp, + creation_user integer, + -- constraint + constraint bt_bug_parent_id_bug_number_un + unique (parent_id, bug_number) ); -insert into bt_severity_codes (severity_id, project_id, severity_name, sort_order, default_p) -select acs_object_id_seq.nextval, null, 'Critical', 1, 'f'; +-- LARS: +-- we need to figure out which ones of these will be used by the query optimizer -insert into bt_severity_codes (severity_id, project_id, severity_name, sort_order, default_p) -select acs_object_id_seq.nextval, null, 'Major', 2, 'f'; +create index bt_bugs_proj_id_bug_number_idx on bt_bugs(project_id, bug_number); +create index bt_bugs_bug_number_idx on bt_bugs(bug_number); -insert into bt_severity_codes (severity_id, project_id, severity_name, sort_order, default_p) -select acs_object_id_seq.nextval, null, 'Normal', 3, 't'; +create index bt_bugs_proj_id_fix_for_idx on bt_bugs(project_id, fix_for_version); +create index bt_bugs_fix_for_version_idx on bt_bugs(fix_for_version); -insert into bt_severity_codes (severity_id, project_id, severity_name, sort_order, default_p) -select acs_object_id_seq.nextval, null, 'Minor', 4, 'f'; +create index bt_bugs_proj_id_crea_date_idx on bt_bugs(project_id, creation_date); +create index bt_bugs_creation_date_idx on bt_bugs(creation_date); -insert into bt_severity_codes (severity_id, project_id, severity_name, sort_order, default_p) -select acs_object_id_seq.nextval, null, 'Trivial', 5, 'f'; +-- Create the bug content item object type -insert into bt_severity_codes (severity_id, project_id, severity_name, sort_order, default_p) -select acs_object_id_seq.nextval, null, 'Enhancement', 6, 'f'; - - -create table bt_priority_codes ( - priority_id integer not null - constraint bt_priority_codes_pk - primary key, - project_id integer - constraint bt_priority_codes_projects_fk - references bt_projects(project_id), - priority_name varchar(500) not null, - sort_order integer not null, - default_p char(1) not null - constraint bt_priority_codes_default_p_ck - check (default_p in ('t','f')) - default 'f', - constraint bt_priority_codes_name_un - unique(project_id, priority_name), - constraint bt_priority_codes_sort_order_un - unique(project_id, sort_order) +select acs_object_type__create_type ( + 'bt_bug', + 'Bug', + 'Bugs', + 'acs_object', + 'bt_bugs', + 'bug_id', + null, + 'f', + null, + null ); -insert into bt_priority_codes (priority_id, project_id, priority_name, sort_order, default_p) -select acs_object_id_seq.nextval, null, 'High', 1, 'f'; -insert into bt_priority_codes (priority_id, project_id, priority_name, sort_order, default_p) -select acs_object_id_seq.nextval, null, 'Normal', 2, 't'; - -insert into bt_priority_codes (priority_id, project_id, priority_name, sort_order, default_p) -select acs_object_id_seq.nextval, null, 'Low', 3, 'f'; - - - --- We maintain a public bug number, different from the --- bug_id, because bug_id is drawn on the acs_objects sequence --- which is used for tons of other things. This gives us cleaner --- bug numbers. - -create sequence t_bt_bug_number_seq; -create view bt_bug_number_seq as -select nextval('t_bt_bug_number_seq') as nextval; - -create table bt_bugs ( - bug_id integer - constraint bt_bugs_pk +-- content_revision specialization +create table bt_bug_revisions ( + bug_revision_id integer + constraint bt_bug_rev_pk primary key - constraint bt_bugs_bug_id_fk - references acs_objects(object_id), - project_id integer - constraint bt_bugs_projects_fk - references bt_projects(project_id), - + constraint bt_bug_rev_bug_id_fk + references cr_revisions(revision_id) + on delete cascade, component_id integer - constraint bt_bugs_components_fk + constraint bt_bug_rev_components_fk references bt_components(component_id), - bug_number integer not null, - status varchar(50) not null - constraint bt_bugs_status_ck - check (status in ('open', 'resolved', 'closed')) - default 'open', resolution varchar(50) - constraint bt_bugs_resolution_ck + constraint bt_bug_rev_resolution_ck check (resolution is null or resolution in ('fixed','bydesign','wontfix','postponed','duplicate','norepro','needinfo')), - bug_type varchar(50) not null - constraint bt_bugs_bug_type_ck - check (bug_type in ('bug', 'suggestion','todo')), - severity integer not null - constraint bt_bugs_severity_fk - references bt_severity_codes(severity_id), - priority integer not null - constraint bt_bugs_priority_fk - references bt_priority_codes(priority_id), user_agent varchar(500), - original_estimate_minutes integer, - latest_estimate_minutes integer, - elapsed_time_minutes integer, found_in_version integer - constraint bt_bugs_found_in_version_fk + constraint bt_bug_rev_found_in_version_fk references bt_versions(version_id), fix_for_version integer - constraint bt_bugs_fix_for_version_fk + constraint bt_bug_rev_fix_for_version_fk references bt_versions(version_id), fixed_in_version integer - constraint bt_bugs_fixed_in_version_fk - references bt_versions(version_id), - summary varchar(500) not null, - assignee integer - constraint bt_bug_assignee_fk - references users(user_id), - constraint bt_bugs_bug_number_un - unique (project_id, bug_number) + constraint bt_bug_rev_fixed_in_version_fk + references bt_versions(version_id) ); -create table bt_bug_actions ( - action_id integer not null - constraint bt_bug_actions_pk - primary key, - bug_id integer not null - constraint bt_bug_actions_bug_fk - references bt_bugs(bug_id) - on delete cascade, - action varchar(50) - constraint bt_bug_actions_action_ck - check (action in ('open','edit','comment','reassign','resolve','reopen','close')), - resolution varchar(50) - constraint bt_bugs_actions_resolution_ck - check (resolution is null or - resolution in ('fixed','bydesign','wontfix','postponed','duplicate','norepro','needinfo')), - actor integer not null - constraint bt_bug_actions_actor_fk - references users(user_id), - action_date timestamptz not null - default current_timestamp, - comment text, - comment_format varchar(30) default 'plain' not null - constraint bt_bug_actions_comment_format_ck - check (comment_format in ('html', 'plain', 'pre')) +-- Create the bug revision content type + +select content_type__create_type ( + 'bt_bug_revision', + 'content_revision', + 'Bug Revision', + 'Bug Revisions', + 'btbug_revisions', + 'bug_revision_id', + 'content_revision.revision_name' ); --- Create the bt_bug object type +select define_function_args ('bt_bug__new','bug_id,bug_number,package_id,component_id,found_in_version,summary,user_agent,comment_content,comment_formt,creation_date,creation_user,creation_ip,item_subtype;bt_bug,content_type;bt_bug_revision'); -create function inline_0 () -returns integer as ' -begin - PERFORM acs_object_type__create_type ( - ''bt_bug'', - ''Bug'', - ''Bugs'', - ''acs_object'', - ''bt_bugs'', - ''bug_id'', - null, - ''f'', - null, - ''bt_bug__name'' - ); - - return 0; -end;' language 'plpgsql'; - -select inline_0 (); - -drop function inline_0 (); - - -create function bt_bug__new( +create or replace function bt_bug__new( integer, -- bug_id - integer, -- project_id + integer, -- bug_number + integer, -- package_id integer, -- component_id - varchar, -- bug_type - integer, -- severity - integer, -- priority integer, -- found_in_version varchar, -- summary - text, -- description - varchar, -- desc_format varchar, -- user_agent + text, -- comment_content + varchar, -- comment_format + timestamp, -- creation_date integer, -- creation_user - varchar -- creation_ip + varchar, -- creation_ip + varchar, -- item_subtype + varchar -- content_type ) returns int as ' declare p_bug_id alias for $1; - p_project_id alias for $2; - p_component_id alias for $3; - p_bug_type alias for $4; - p_severity alias for $5; - p_priority alias for $6; - p_found_in_version alias for $7; - p_summary alias for $8; - p_description alias for $9; - p_desc_format alias for $10; - p_user_agent alias for $11; - p_creation_user alias for $12; - p_creation_ip alias for $13; + p_bug_number alias for $2; + p_package_id alias for $3; + p_component_id alias for $4; + p_found_in_version alias for $5; + p_summary alias for $6; + p_user_agent alias for $7; + p_comment_content alias for $8; + p_comment_format alias for $9; + p_creation_date alias for $10; + p_creation_user alias for $11; + p_creation_ip alias for $12; + p_item_subtype alias for $13; + p_content_type alias for $14; + v_bug_id integer; + v_revision_id integer; v_bug_number integer; - v_assignee integer; - v_action_id integer; + v_folder_id integer; begin - v_assignee := bt_component__default_assignee(p_component_id); + -- get the content folder for this instance + select folder_id + into v_folder_id + from bt_projects + where project_id = p_package_id; - v_bug_id := acs_object__new( - p_bug_id, -- object_id - ''bt_bug'', -- object_type - now(), -- creation_date - p_creation_user, -- creation_user - p_creation_ip, -- creation_ip - p_project_id, -- context_id - ''t'' -- security_inherit_p + -- get bug_number + if p_bug_number is null then + select coalesce(max(bug_number),0) + 1 + into v_bug_number + from bt_bugs + where parent_id = v_folder_id; + else + v_bug_number := p_bug_number; + end if; + + -- create the content item + v_bug_id := content_item__new( + v_bug_number, -- name + v_folder_id, -- parent_id + p_bug_id, -- item_id + null, -- locale + p_creation_date, -- creation_date + p_creation_user, -- creation_user + v_folder_id, -- context_id + p_creation_ip, -- creation_ip + p_item_subtype, -- item_subtype + p_content_type, -- content_type + null, -- title + null, -- description + null, -- mime_type + null, -- nls_language + null -- data ); - select coalesce(max(bug_number),0) + 1 - into v_bug_number - from bt_bugs - where project_id = p_project_id; - + -- create the item type row insert into bt_bugs - (bug_id, project_id, component_id, bug_number, bug_type, severity, assignee, - priority, found_in_version, summary, user_agent) + (bug_id, bug_number, comment_content, comment_format, parent_id, project_id, creation_date, creation_user) values - (v_bug_id, p_project_id, p_component_id, v_bug_number, p_bug_type, p_severity, v_assignee, - p_priority, p_found_in_version, p_summary, p_user_agent); + (v_bug_id, v_bug_number, p_comment_content, p_comment_format, v_folder_id, p_package_id, p_creation_date, p_creation_user); - select nextval(''t_acs_object_id_seq'') - into v_action_id; + -- create the initial revision + v_revision_id := bt_bug_revision__new( + null, -- bug_revision_id + v_bug_id, -- bug_id + p_component_id, -- component_id + p_found_in_version, -- found_in_version + null, -- fix_for_version + null, -- fixed_in_version + null, -- resolution + p_user_agent, -- user_agent + p_summary, -- summary + p_creation_date, -- creation_date + p_creation_user, -- creation_user + p_creation_ip -- creation_ip + ); - insert into bt_bug_actions - (action_id, bug_id, action, actor, comment, comment_format) - values - (v_action_id, v_bug_id, ''open'', p_creation_user, p_description, p_desc_format); - - return 0; + return v_bug_id; end; ' language 'plpgsql'; -create function bt_bug__name( +create or replace function bt_bug__delete( integer -- bug_id -) returns varchar +) returns integer as ' declare - name__bug_id alias for $1; - v_name varchar; + p_bug_id alias for $1; + v_case_id integer; + rec record; begin - select summary - into v_name - from bt_bugs - where bug_id = name__bug_id; + -- Every bug is associated with a workflow case + select case_id + into v_case_id + from workflow_cases + where object_id = p_bug_id; - return v_name; -end; -' language 'plpgsql'; + perform workflow_case__delete(v_case_id); + -- Every bug may have notifications attached to it + -- and there is one column in the notificaitons datamodel that doesn''t + -- cascade + for rec in select notification_id from notifications + where response_id = p_bug_id loop -create function bt_bug__delete( - integer -- bug_id -) returns integer -as ' -declare - delete__bug_id alias for $1; -begin - perform acs_object__delete(delete__bug_id); + perform notification__delete (rec.notification_id); + end loop; + -- unset live & latest revision +-- update cr_items +-- set live_revision = null, +-- latest_revision = null +-- where item_id = p_bug_id; + + perform content_item__delete(p_bug_id); + return 0; end; ' language 'plpgsql'; -create function bt_bug__status_sort_order( - varchar -- status -) returns integer -as ' -declare - p_status alias for $1; - v_sort_order integer; -begin - v_sort_order := case p_status - when ''open'' then 1 - when ''resolved'' then 2 - when ''closed'' then 3 - else 4 - end; - - return v_sort_order; -end; -' language 'plpgsql'; -create function bt_bug__bug_type_sort_order( - varchar -- bug_type -) returns integer +create or replace function bt_bug_revision__new( + integer, -- bug_revision_id + integer, -- bug_id + integer, -- component_id + integer, -- found_in_version + integer, -- fix_for_version + integer, -- fixed_in_version + varchar, -- resolution + varchar, -- user_agent + varchar, -- summary + timestamp, -- creation_date + integer, -- creation_user + varchar -- creation_ip +) returns int as ' declare - p_bug_type alias for $1; - v_sort_order integer; + p_bug_revision_id alias for $1; + p_bug_id alias for $2; + p_component_id alias for $3; + p_found_in_version alias for $4; + p_fix_for_version alias for $5; + p_fixed_in_version alias for $6; + p_resolution alias for $7; + p_user_agent alias for $8; + p_summary alias for $9; + p_creation_date alias for $10; + p_creation_user alias for $11; + p_creation_ip alias for $12; + + v_revision_id integer; begin - v_sort_order := case p_bug_type - when ''bug'' then 1 - when ''suggestion'' then 2 - when ''todo'' then 3 - else 4 - end; + -- create the initial revision + v_revision_id := content_revision__new( + p_summary, -- title + null, -- description + now(), -- publish_date + null, -- mime_type + null, -- nls_language + null, -- new_data + p_bug_id, -- item_id + p_bug_revision_id, -- revision_id + p_creation_date, -- creation_date + p_creation_user, -- creation_user + p_creation_ip -- creation_ip + ); - return v_sort_order; -end; -' language 'plpgsql'; + -- insert into the bug-specific revision table + insert into bt_bug_revisions + (bug_revision_id, component_id, resolution, user_agent, found_in_version, fix_for_version, fixed_in_version) + values + (v_revision_id, p_component_id, p_resolution, p_user_agent, p_found_in_version, p_fix_for_version, p_fixed_in_version); + -- make this revision live + PERFORM content_item__set_live_revision(v_revision_id); --- In SDM: sdm_patches --- In SDM, this is a relationship between a general comment and a ticket --- supposedly the patch itself is stored as a special comment --- In BT: Probably something similar, not sure. + -- update the cache + update bt_bugs + set live_revision_id = v_revision_id, + summary = p_summary, + component_id = p_component_id, + resolution = p_resolution, + user_agent = p_user_agent, + found_in_version = p_found_in_version, + fix_for_version = p_fix_for_version, + fixed_in_version = p_fixed_in_version + where bug_id = p_bug_id; --- In SDM: sdm_ticket_ratings --- In BT: We'll leave that out for now, but supposedly we could use a modified --- version of my ratings package from pinds.com + return v_revision_id; +end; +' language 'plpgsql'; --- All of the following should be doable with acs_rels of some sort --- (I'm not too strong in that data model, but I suppose I'll learn over the next few days) --- sdm_ticket_assignments --- sdm_bug_release_maps --- sdm_user_ticket_interest_map --- sdm_user_module_interest_map --- sdm_user_package_interest_map --- sdm_related_tickets_map --- In SDM: sdm_notifications --- This seems to be a table to hold notifications until they're actually sent out in batch --- depending on the user's preferences --- In BT: We'd probably do something similar. - --- In SDM: sdm_notification_prefs --- In BT: create table bt_user_prefs ( user_id integer not null constraint bt_user_prefs_user_id_fk @@ -545,93 +610,79 @@ primary key (user_id, project_id) ); --- For stability, URLs contain patch numbers rather than ACS Object ids. --- This avoids dependence on the ACS kernel and makes upgrades easier. -create sequence t_bt_patch_number_seq; -create view bt_patch_number_seq as -select nextval('t_bt_patch_number_seq') as nextval; create table bt_patches ( - patch_id integer - constraint bt_patches_pk - primary key - constraint bt_patches_pid_fk - references acs_objects(object_id), - patch_number integer not null, - project_id integer - constraint bt_patches_projects_fk - references bt_projects(project_id), - component_id integer - constraint bt_patches_components_fk - references bt_components(component_id), - summary text, - content text, - generated_from_version integer - constraint bt_patches_vid_fk - references bt_versions(version_id), - apply_to_version integer - constraint bt_patchs_apply_to_version_fk - references bt_versions(version_id), - applied_to_version integer - constraint bt_patchs_applied_to_version_fk - references bt_versions(version_id), - status varchar(50) not null - constraint bt_patchs_status_ck - check (status in ('open', 'accepted', 'refused', 'deleted')) - default 'open', - constraint bt_patches_un - unique(patch_number, project_id) + patch_id integer + constraint bt_patches_pk + primary key + constraint bt_patches_pid_fk + references acs_objects(object_id), + patch_number integer not null, + project_id integer + constraint bt_patches_projects_fk + references bt_projects(project_id), + component_id integer + constraint bt_patches_components_fk + references bt_components(component_id), + summary text, + content text, + generated_from_version integer + constraint bt_patches_vid_fk + references bt_versions(version_id), + apply_to_version integer + constraint bt_patchs_apply_to_version_fk + references bt_versions(version_id), + applied_to_version integer + constraint bt_patchs_applied_to_version_fk + references bt_versions(version_id), + status varchar(50) not null + constraint bt_patchs_status_ck + check (status in ('open', 'accepted', 'refused', 'deleted')) + default 'open', + constraint bt_patches_un + unique(patch_number, project_id) ); create table bt_patch_actions ( - action_id integer not null - constraint bt_patch_actions_pk - primary key, - patch_id integer not null - constraint bt_patch_actions_patch_fk - references bt_patches(patch_id) - on delete cascade, - action varchar(50) - constraint bt_patch_actions_action_ck - check (action in ('open', 'edit', 'comment', 'accept', - 'reopen', 'refuse', 'delete')) - default 'open', - actor integer not null - constraint bt_patch_actions_actor_fk - references users(user_id), - action_date timestamptz not null - default current_timestamp, - comment text, - comment_format varchar(30) default 'plain' not null - constraint bt_patch_actions_comment_format_ck - check (comment_format in ('html', 'plain', 'pre')) + action_id integer not null + constraint bt_patch_actions_pk + primary key, + patch_id integer not null + constraint bt_patch_actions_patch_fk + references bt_patches(patch_id) + on delete cascade, + action varchar(50) + constraint bt_patch_actions_action_ck + check (action in ('open', 'edit', 'comment', 'accept', + 'reopen', 'refuse', 'delete')) + default 'open', + actor integer not null + constraint bt_patch_actions_actor_fk + references users(user_id), + action_date timestamp not null + default now(), + comment_text text, + comment_format varchar(30) default 'plain' not null + constraint bt_patch_actions_comment_format_ck + check (comment_format in ('html', 'plain', 'pre')) ); -- Create the bt_patch object type -create function inline_0 () -returns integer as ' -begin - PERFORM acs_object_type__create_type ( - ''bt_patch'', - ''Patch'', - ''Patches'', - ''acs_object'', - ''bt_patches'', - ''patch_id'', - null, - ''f'', - null, - ''bt_patch__name'' - ); +select acs_object_type__create_type ( + 'bt_patch', + 'Patch', + 'Patches', + 'acs_object', + 'bt_patches', + 'patch_id', + null, + 'f', + null, + 'bt_patch__name' +); - return 0; -end;' language 'plpgsql'; -select inline_0 (); - -drop function inline_0 (); - -create function bt_patch__new( +create or replace function bt_patch__new( integer, -- patch_id integer, -- project_id integer, -- component_id @@ -662,8 +713,8 @@ begin v_patch_id := acs_object__new( - p_patch_id, -- object_id - ''bt_patch'', -- object_type + p_patch_id, -- object_id + ''bt_patch'', -- object_type now(), -- creation_date p_creation_user, -- creation_user p_creation_ip, -- creation_ip @@ -697,15 +748,15 @@ into v_action_id; insert into bt_patch_actions - (action_id, patch_id, action, actor, comment, comment_format) + (action_id, patch_id, action, actor, comment_text, comment_format) values (v_action_id, v_patch_id, ''open'', p_creation_user, p_description, p_description_format); - return 0; + return v_patch_id; end; ' language 'plpgsql'; -create function bt_patch__name( +create or replace function bt_patch__name( integer -- patch_id ) returns varchar as ' @@ -722,7 +773,7 @@ end; ' language 'plpgsql'; -create function bt_patch__delete( +create or replace function bt_patch__delete( integer -- patch_id ) returns integer as ' @@ -737,16 +788,18 @@ -- There is a many to many relationship between patches and bugs create table bt_patch_bug_map ( - patch_id integer not null - constraint bt_patch_bug_map_pid_fk - references bt_patches(patch_id) - on delete cascade, - bug_id integer not null - constraint bt_patch_bug_map_bid_fk - references bt_bugs(bug_id) - on delete cascade, - constraint bt_patch_bug_map_un - unique (patch_id, bug_id) + patch_id integer not null + constraint bt_patch_bug_map_pid_fk + references bt_patches(patch_id) + on delete cascade, + bug_id integer not null + constraint bt_patch_bug_map_bid_fk + references cr_items(item_id) + on delete cascade, + constraint bt_patch_bug_map_un + unique (patch_id, bug_id) ); -\i bug-tracker-notifications-init.sql +create index bt_patch_bug_map_patch_id_idx on bt_patch_bug_map(patch_id); +create index bt_patch_bug_map_bug_id_idx on bt_patch_bug_map(bug_id); + Index: openacs-4/packages/bug-tracker/sql/postgresql/bug-tracker-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/sql/postgresql/bug-tracker-drop.sql,v diff -u -r1.3.2.1 -r1.3.2.2 --- openacs-4/packages/bug-tracker/sql/postgresql/bug-tracker-drop.sql 30 Sep 2002 14:55:49 -0000 1.3.2.1 +++ openacs-4/packages/bug-tracker/sql/postgresql/bug-tracker-drop.sql 5 Mar 2003 18:13:18 -0000 1.3.2.2 @@ -1,50 +1,55 @@ -/* Delete all bugs */ -create function inline_0 () -returns integer as ' -declare - v_bug_id integer; -begin - loop - select min(bug_id) into v_bug_id from bt_bugs; - exit when not found or v_bug_id is null; - perform bt_bug__delete(v_bug_id); - end loop; +drop function bt_bug__new( + integer, -- bug_id + integer, -- package_id + integer, -- component_id + integer, -- found_in_version + varchar, -- summary + varchar, -- user_agent + text, -- comment_content + varchar, -- comment_format + timestamp, -- creation_date + integer, -- creation_user + varchar, -- creation_ip + varchar, -- item_subtype + varchar -- content_type +); - return 0; -end;' language 'plpgsql'; +drop function bt_bug__delete (integer); -select inline_0 (); +drop function bt_bug_revision__new( + integer, -- revision_id + integer, -- bug_id + integer, -- component_id + integer, -- found_in_version + integer, -- fix_for_version + integer, -- fixed_in_version + varchar, -- resolution + varchar, -- user_agent + varchar, -- summary + timestamp, -- creation_date + integer, -- creation_user + varchar -- creation_ip +); -drop function inline_0 (); - - -drop function bt_bug__new - (integer, integer, integer, varchar, integer, integer, integer, varchar, text, varchar, varchar, integer, varchar); -drop function bt_bug__name (integer); -drop function bt_bug__delete (integer); -drop function bt_bug__status_sort_order(varchar); -drop function bt_bug__bug_type_sort_order(varchar); drop function bt_version__set_active (integer); -drop function bt_component__default_assignee(integer); drop function bt_project__new(integer); drop function bt_project__delete(integer); drop table bt_user_prefs; -drop table bt_bug_actions; drop table bt_bugs; -drop view bt_bug_number_seq; -drop sequence t_bt_bug_number_seq; -drop table bt_priority_codes; -drop table bt_severity_codes; +select acs_object_type__drop_type('bt_bug', 't'); + +select content_type__drop_type('bt_bug_revision', 't', 'f'); +drop table bt_bug_revisions; + +drop table bt_default_keywords; + drop table bt_components; drop table bt_versions; drop table bt_projects; -delete from acs_objects where object_type = 'bt_bug'; -select acs_object_type__drop_type('bt_bug', 't'); - drop table bt_patch_bug_map; drop function bt_patch__delete(integer); drop function bt_patch__name(integer); @@ -57,5 +62,3 @@ delete from acs_objects where object_type = 'bt_patch'; select acs_object_type__drop_type('bt_patch', 't'); - -\i bug-tracker-notifications-drop.sql Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `openacs-4/packages/bug-tracker/sql/postgresql/bug-tracker-notifications-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1.2.1 refers to a dead (removed) revision in file `openacs-4/packages/bug-tracker/sql/postgresql/bug-tracker-notifications-init.sql'. Fisheye: No comparison available. Pass `N' to diff? Index: openacs-4/packages/bug-tracker/sql/postgresql/upgrade-0.7d5-0.8.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/sql/postgresql/upgrade-0.7d5-0.8.sql,v diff -u -r1.1.2.1 -r1.1.2.2 --- openacs-4/packages/bug-tracker/sql/postgresql/upgrade-0.7d5-0.8.sql 2 Mar 2003 22:39:33 -0000 1.1.2.1 +++ openacs-4/packages/bug-tracker/sql/postgresql/upgrade-0.7d5-0.8.sql 5 Mar 2003 18:13:18 -0000 1.1.2.2 @@ -201,5 +201,3 @@ constraint bt_patch_bug_map_un unique (patch_id, bug_id) ); - -\i bug-tracker-notifications-init.sql Index: openacs-4/packages/bug-tracker/tcl/bug-tracker-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/tcl/bug-tracker-procs.tcl,v diff -u -r1.13.2.6 -r1.13.2.7 --- openacs-4/packages/bug-tracker/tcl/bug-tracker-procs.tcl 21 Feb 2003 14:00:24 -0000 1.13.2.6 +++ openacs-4/packages/bug-tracker/tcl/bug-tracker-procs.tcl 5 Mar 2003 18:13:39 -0000 1.13.2.7 @@ -8,1098 +8,1580 @@ } -namespace eval bug_tracker { +namespace eval bug_tracker {} - ad_proc conn { args } { - - global bt_conn - - set flag [lindex $args 0] - if { [string index $flag 0] != "-" } { - set var $flag - set flag "-get" - } else { - set var [lindex $args 1] +ad_proc bug_tracker::package_key {} { + return "bug-tracker" +} + +ad_proc bug_tracker::conn { args } { + + global bt_conn + + set flag [lindex $args 0] + if { [string index $flag 0] != "-" } { + set var $flag + set flag "-get" + } else { + set var [lindex $args 1] + } + + switch -- $flag { + -set { + set bt_conn($var) [lindex $args 2] } - - switch -- $flag { - -set { - set bt_conn($var) [lindex $args 2] - } - - -get { - if { [info exists bt_conn($var)] } { - return $bt_conn($var) - } else { - switch -- $var { - project_name - project_description - current_version_id - current_version_name { - array set info [get_project_info] + + -get { + if { [info exists bt_conn($var)] } { + return $bt_conn($var) + } else { + switch -- $var { + bug - bugs - Bug - Bugs - + component - components - Component - Components { + 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) } - 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 { - return {} - } - default { - error "Unknown variable $var" - } } + component_id - + filter - filter_human_readable - + filter_where_clauses - + filter_order_by_clause - filter_from_bug_clause { + return {} + } + default { + error "Unknown variable $var" + } } } - - default { - error "bt_conn: unknown flag $flag" - } } - } - ad_proc get_bug_id { - {-bug_number:required} - {-project_id:required} - } { - return [db_string bug_id { select bug_id from bt_bugs where bug_number = :bug_number and project_id = :project_id }] + default { + error "bt_conn: unknown flag $flag" + } } +} + +ad_proc bug_tracker::get_pretty_names { + -array:required +} { + upvar $array row + + set row(bug) [parameter::get -parameter "TicketPrettyName" -default "bug"] + set row(bugs) [parameter::get -parameter "TicketPrettyPlural" -default "bugs"] + set row(Bug) [string totitle $row(bug)] + set row(Bugs) [string totitle $row(bugs)] + + set row(component) [parameter::get -parameter "ComponentPrettyName" -default "component"] + set row(components) [parameter::get -parameter "ComponentPrettyPlural" -default "components"] + set row(Component) [string totitle $row(component)] + set row(Components) [string totitle $row(components)] +} + +ad_proc bug_tracker::get_bug_id { + {-bug_number:required} + {-project_id:required} +} { + return [db_string bug_id {}] +} + +##### +# +# Cached project info procs +# +##### + +ad_proc bug_tracker::get_project_info_internal { + package_id +} { + db_1row project_info {} -column_array result - ##### - # - # Cached project info procs - # - ##### - - ad_proc get_project_info_internal { - package_id - } { - set found_p [db_0or1row project_info { - select pck.instance_name as project_name, - prj.description as project_description, - ver.version_id as current_version_id, - coalesce(ver.version_name, 'None') as current_version_name - from apm_packages pck, - bt_projects prj - left outer join bt_versions ver - on (ver.project_id = prj.project_id and active_version_p = 't') - where pck.package_id = :package_id - and prj.project_id = pck.package_id - } -column_array result] - - if { !$found_p } { - set count [db_string count_project { select count(*) from bt_projects where project_id = :package_id }] - if { $count == 0 } { - db_exec_plsql create_project { - select bt_project__new(:package_id) - } - # we call ourselves again, so we'll get the info this time - return [get_project_info_internal $package_id] - } else { - error "Couldn't find project in database" - } - } else { - return [array get result] - } + return [array get result] +} + +ad_proc bug_tracker::get_project_info { + -package_id +} { + if { ![info exists package_id] } { + set package_id [ad_conn package_id] } + + return [util_memoize [list bug_tracker::get_project_info_internal $package_id]] +} + +ad_proc bug_tracker::get_project_info_flush { + -package_id +} { + if { ![info exists package_id] } { + set package_id [ad_conn package_id] + } + + util_memoize_flush [list bug_tracker::get_project_info_internal $package_id] +} + +ad_proc bug_tracker::set_project_name { + -package_id + project_name +} { + if { ![info exists package_id] } { + set package_id [ad_conn package_id] + } - ad_proc get_project_info { - -package_id - } { - if { ![info exists package_id] } { - set package_id [ad_conn package_id] - } + db_dml project_name_update {} - # temp hack: don't cache - return [get_project_info_internal $package_id] - - # return [util_memoize "bt_get_project_info_internal $package_id"] + # Flush cache + util_memoize_flush [list bug_tracker::get_project_info_internal $package_id]] +} + + + +##### +# +# Stats procs (cache eventually) +# +##### + + +ad_proc -public bug_tracker::bugs_exist_p { + {-package_id {}} +} { + Returns whether any bugs exist in a project +} { + if { ![exists_and_not_null package_id] } { + set package_id [ad_conn package_id] } + + return [util_memoize [list bug_tracker::bugs_exist_p_not_cached -package_id $package_id]] +} - ad_proc set_project_name { - -package_id - project_name - } { - if { ![info exists package_id] } { - set package_id [ad_conn package_id] - } - - db_dml project_name_update { - update apm_packages - set instance_name = :project_name - where package_id = :package_id - } - - # Flush cache - util_memoize_flush "bt_get_project_info_internal $package_id" +ad_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 { ![exists_and_not_null package_id] } { + set package_id [ad_conn package_id] } + + return [util_memoize_seed [list bug_tracker::bugs_exist_p_not_cached -package_id $package_id] 1] +} +ad_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 - # - ##### - - ad_proc get_user_prefs_internal { - package_id - user_id - } { - set found_p [db_0or1row user_info { - select u.first_names as user_first_names, - u.last_name as user_last_name, - u.email as user_email, - ver.version_id as user_version_id, - coalesce(ver.version_name, 'None') as user_version_name - from cc_users u, - bt_user_prefs up - left outer join bt_versions ver - on (ver.version_id = up.user_version) - where u.user_id = :user_id - and up.user_id = u.user_id - and up.project_id = :package_id - } -column_array result] - - if { !$found_p } { - set count [db_string count_user_prefs { select count(*) from bt_user_prefs where project_id = :package_id and user_id = :user_id }] - if { $count == 0 } { - db_dml create_user_prefs { - insert into bt_user_prefs (user_id, project_id) values (:user_id, :package_id) - } - # we call ourselves again, so we'll get the info this time - return [get_user_prefs_internal $package_id $user_id] - } else { - error "Couldn't find user in database" - } +##### +# +# Cached user prefs procs +# +##### + +ad_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 { - return [array get result] + error "Couldn't find user in database" } + } else { + return [array get result] } - - ad_proc get_user_prefs { - -package_id - -user_id - } { - if { ![info exists package_id] } { - set package_id [ad_conn package_id] - } - - if { ![info exists user_id] } { - set user_id [ad_conn user_id] - } - - return [util_memoize "bug_tracker::get_user_prefs_internal $package_id $user_id"] +} + +ad_proc bug_tracker::get_user_prefs { + -package_id + -user_id +} { + if { ![info exists package_id] } { + set package_id [ad_conn package_id] } - ad_proc get_user_prefs_flush { - -package_id - -user_id - } { - if { ![info exists package_id] } { - 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]] +} + +ad_proc bug_tracker::get_user_prefs_flush { + -package_id + -user_id +} { + if { ![info exists package_id] } { + 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] +} - if { ![info exists user_id] } { - set user_id [ad_conn user_id] - } - util_memoize_flush "bug_tracker::get_user_prefs_internal $package_id $user_id" +##### +# +# Bug Types +# +##### + +ad_proc bug_tracker::bug_type_get_options {} { + return { { "Bug" bug } { "Suggestion" suggestion } { "Todo" todo } } +} + +ad_proc bug_tracker::bug_type_pretty { + bug_type +} { + array set bug_types { + bug "Bug" + suggestion "Suggestion" + todo "Todo" } + if { [info exists bug_types($bug_type)] } { + return $bug_types($bug_type) + } else { + return "" + } +} - ##### - # - # Bug Types - # - ##### +##### +# +# Status +# +##### + +ad_proc bug_tracker::status_get_options { + {-package_id ""} +} { + if { [empty_string_p $package_id] } { + 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 +} + +ad_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 - ad_proc bug_type_get_options {} { - return { { "Bug" bug } { "Suggestion" suggestion } { "Todo" todo } } + return $state(pretty_name) +} + +ad_proc bug_tracker::patch_status_get_options {} { + return { { "Open" open } { "Accepted" accepted } { "Refused" refused } { "Deleted" deleted }} +} + +ad_proc bug_tracker::patch_status_pretty { + status +} { + array set status_codes { + open "Open" + accepted "Accepted" + refused "Refused" + deleted "Deleted" } + if { [info exists status_codes($status)] } { + return $status_codes($status) + } else { + return "" + } +} - ad_proc bug_type_pretty { - bug_type - } { - array set bug_types { - bug "Bug" - suggestion "Suggestion" - todo "Todo" - } - if { [info exists bug_types($bug_type)] } { - return $bug_types($bug_type) - } else { - return "" - } +##### +# +# Resolution +# +##### + +ad_proc bug_tracker::resolution_get_options {} { + return { + { "Fixed" fixed } { "By Design" bydesign } { "Won't Fix" wontfix } { "Postponed" postponed } + { "Duplicate" duplicate } { "Not Reproducable" norepro } { "Need Info" needinfo } } +} + +ad_proc bug_tracker::resolution_pretty { + resolution +} { + array set resolution_codes { + fixed "Fixed" + bydesign "By Design" + wontfix "Won't Fix" + postponed "Postponed" + duplicate "Duplicate" + norepro "Not Reproducable" + needinfo "Need Info" + } + if { [info exists resolution_codes($resolution)] } { + return $resolution_codes($resolution) + } else { + return "" + } +} - ##### - # - # Status - # - ##### - ad_proc status_get_options {} { - return { { "Open" open } { "Resolved" resolved } { "Closed" closed } } - } +##### +# +# Severity/Priority codes +# +##### + +ad_proc bug_tracker::severity_codes_get_options { +} { +# XXX FIXME obsolete + set package_id [ad_conn package_id] + return [util_memoize [list bug_tracker::severity_codes_get_options_not_cached $package_id]] +} + +ad_proc bug_tracker::severity_codes_get_options_not_cached { + package_id +} { +# XXX FIXME obsolete + set severity_list [db_list_of_lists severities { + select sort_order || ' - ' || severity_name, severity_id + from bt_severity_codes + where project_id = :package_id + order by sort_order + }] + + return $severity_list +} + +ad_proc bug_tracker::severity_get_default { +} { +# XXX FIXME obsolete + set package_id [ad_conn package_id] + return [util_memoize [list bug_tracker::severity_get_default_not_cached $package_id]] +} + +ad_proc bug_tracker::severity_get_default_not_cached { + package_id +} { +# XXX FIXME obsolete + set default_severity_id [db_string default_severity { + select severity_id + from bt_severity_codes + where project_id = :package_id + and default_p = 't' + order by sort_order + limit 1 + } -default ""] - ad_proc status_pretty { - status - } { - array set status_codes { - open "Open" - resolved "Resolved" - closed "Closed" + return $default_severity_id +} + +ad_proc bug_tracker::priority_codes_get_options { +} { +# XXX FIXME obsolete + set package_id [ad_conn package_id] + return [util_memoize [list bug_tracker::priority_codes_get_options_not_cached $package_id]] +} + +ad_proc bug_tracker::priority_codes_get_options_not_cached { + package_id +} { +# XXX FIXME obsolete + set priority_list [db_list_of_lists priorities { + select sort_order || ' - ' || priority_name, priority_id + from bt_priority_codes + where project_id = :package_id + order by sort_order + }] + + return $priority_list +} + +ad_proc bug_tracker::priority_get_default { +} { +# XXX FIXME obsolete + set package_id [ad_conn package_id] + return [util_memoize [list bug_tracker::priority_get_default_not_cached $package_id]] +} + +ad_proc bug_tracker::priority_get_default_not_cached { + package_id +} { +# XXX FIXME obsolete + set default_priority_id [db_string default_priority { + select priority_id + from bt_priority_codes + where project_id = :package_id + and default_p = 't' + order by sort_order + limit 1 + } -default ""] + + return $default_priority_id +} + + +##### +# +# Categories/Keywords +# +##### + +ad_proc bug_tracker::category_parent_heading { + {-package_id ""} + -keyword_id:required +} { + foreach elm [get_keywords -package_id $package_id] { + set child_id [lindex $elm 0] + set child_heading [lindex $elm 1] + set parent_id [lindex $elm 2] + set parent_heading [lindex $elm 3] + + if { $child_id == $keyword_id } { + return $parent_heading } - if { [info exists status_codes($status)] } { - return $status_codes($status) - } else { - return "" - } } - - ad_proc patch_status_get_options {} { - return { { "Open" open } { "Accepted" accepted } { "Refused" refused } { "Deleted" deleted }} - } +} - ad_proc patch_status_pretty { - status - } { - array set status_codes { - open "Open" - accepted "Accepted" - refused "Refused" - deleted "Deleted" +ad_proc bug_tracker::category_heading { + {-package_id ""} + -keyword_id:required +} { + foreach elm [get_keywords -package_id $package_id] { + set child_id [lindex $elm 0] + set child_heading [lindex $elm 1] + set parent_id [lindex $elm 2] + set parent_heading [lindex $elm 3] + + if { $child_id == $keyword_id } { + return $child_heading } - if { [info exists status_codes($status)] } { - return $status_codes($status) - } else { - return "" - } - } + } +} + +ad_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] - ##### - # - # Resolution - # - ##### - - ad_proc resolution_get_options {} { - return { - { "Fixed" fixed } { "By Design" bydesign } { "Won't Fix" wontfix } { "Postponed" postponed } - { "Duplicate" duplicate } { "Not Reproducable" norepro } { "Need Info" needinfo } + set last_parent_id {} + foreach elm [get_keywords -package_id $package_id] { + set child_id [lindex $elm 0] + set child_heading [lindex $elm 1] + set parent_id [lindex $elm 2] + set parent_heading [lindex $elm 3] + + if { $parent_id != $last_parent_id } { + set heading($parent_id) $parent_heading + lappend parent_ids $parent_id + set last_parent_id $parent_id } } - ad_proc resolution_pretty { - resolution - } { - array set resolution_codes { - fixed "Fixed" - bydesign "By Design" - wontfix "Won't Fix" - postponed "Postponed" - duplicate "Duplicate" - norepro "Not Reproducable" - needinfo "Need Info" + set result [list] + foreach parent_id $parent_ids { + lappend result $parent_id $heading($parent_id) + } + return $result +} + +ad_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] { + set elm_child_id [lindex $elm 0] + set elm_child_heading [lindex $elm 1] + set elm_parent_id [lindex $elm 2] + + if { $elm_parent_id == $parent_id } { + lappend options [list $elm_child_heading $elm_child_id] } - if { [info exists resolution_codes($resolution)] } { - return $resolution_codes($resolution) - } else { - return "" - } } - - - - ##### - # - # Severity/Priority codes - # - ##### - - ad_proc severity_codes_get_options { - } { + return $options +} + + +## Cache maintenance + +ad_proc -private bug_tracker::get_keywords { + {-package_id ""} +} { + if { ![exists_and_not_null package_id] } { set package_id [ad_conn package_id] - - set severity_list [db_list_of_lists severities { - select sort_order || ' - ' || severity_name, severity_id - from bt_severity_codes - where project_id = :package_id - order by sort_order - }] - - return $severity_list } - - ad_proc severity_get_default { - } { + return [util_memoize [list bug_tracker::get_keywords_not_cached -package_id $package_id]] +} + +ad_proc -private bug_tracker::get_keywords_flush { + {-package_id ""} +} { + if { ![exists_and_not_null package_id] } { set package_id [ad_conn package_id] - - set default_severity_id [db_string default_severity { - select severity_id - from bt_severity_codes - where project_id = :package_id - and default_p = 't' - order by sort_order - limit 1 - } -default ""] - - return $default_severity_id } - - ad_proc priority_codes_get_options { - } { + util_memoize_flush [list bug_tracker::get_keywords_not_cached -package_id $package_id] +} + +ad_proc -private bug_tracker::get_keywords_not_cached { + -package_id:required +} { + return [db_list_of_lists select_package_keywords {}] +} + + + + + +ad_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 { ![exists_and_not_null package_id] } { set package_id [ad_conn package_id] - - set priority_list [db_list_of_lists priorities { - select sort_order || ' - ' || priority_name, priority_id - from bt_priority_codes - where project_id = :package_id - order by sort_order - }] - - return $priority_list } - - ad_proc priority_get_default { - } { - set package_id [ad_conn package_id] - - set default_priority_id [db_string default_priority { - select priority_id - from bt_priority_codes - where project_id = :package_id - and default_p = 't' - order by sort_order - limit 1 - } -default ""] - - return $default_priority_id + + # LARS NEW QUERIES + + db_dml delete_existing { + delete + from bt_default_keywords + where project_id = :package_id + and parent_id = :parent_id } - - - ##### - # - # Versions - # - ##### - - ad_proc version_get_options { - -include_unknown:boolean - -include_undecided:boolean - } { + 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 +} + +ad_proc -public bug_tracker::get_default_keyword { + {-package_id ""} + {-parent_id:required} +} { + Get the default keyword for a given type (parent) +} { + if { ![exists_and_not_null package_id] } { set package_id [ad_conn package_id] - - set versions_list [db_list_of_lists versions \ - { select version_name, version_id from bt_versions where project_id = :package_id order by version_name }] - - if { $include_unknown_p } { - set versions_list [concat { { "Unknown" "" } } $versions_list] - } - - if { $include_undecided_p } { - set versions_list [concat { { "Undecided" "" } } $versions_list] - } - - return $versions_list } - - - ##### - # - # Components - # - ##### - - ad_proc components_get_options { - -include_unknown:boolean - } { + + return [util_memoize [list bug_tracker::get_default_keyword_not_cached -package_id $package_id -parent_id $parent_id]] +} + +ad_proc -public bug_tracker::get_default_keyword_flush { + {-package_id ""} + {-parent_id:required} +} { + Flush the cache for +} { + if { ![exists_and_not_null package_id] } { set package_id [ad_conn package_id] - - set components_list [db_list_of_lists components \ - { select component_name, component_id from bt_components where project_id = :package_id order by component_name }] - - if { $include_unknown_p } { - set components_list [concat { { "Unknown" "" } } $components_list] - } - - return $components_list } - - - ##### - # - # Description - # - ##### - - ad_proc bug_convert_comment_to_html { - -comment - -format - } { - switch $format { - html { - return [ad_html_text_convert -from html -to html -- $comment] + + util_memoize_flush [list bug_tracker::get_default_keyword_not_cached -package_id $package_id -parent_id $parent_id] +} + + +ad_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. +} { + # LARS NEW QUERIES + + 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 { + "Bug-Tracker" { + categories { + "Bug Type" { + "*Bug" + "Suggestion" + "Todo" + } + "Priority" { + "1 - High" + "*2 - Normal" + "3 - Low" + } + "Severity" { + "1 - Critical" + "2 - Major" + "*3 - Normal" + "4 - Minor" + "5 - Trivial" + "6 - Enhancement" + } } - pre { - return "

[ad_html_text_convert -from html -to html -- $comment]
" + parameters { + TicketPrettyName "bug" + TicketPrettyPlural "bugs" + ComponentPrettyName "component" + ComponentPrettyPlural "components" + PatchesP "1" + VersionsP "1" } - default { - return [ad_html_text_convert -from text -to html -- $comment] - } } - } - - ad_proc bug_convert_comment_to_text { - -comment - -format - } { - switch $format { - html { - return [ad_html_text_convert -from html -to text -- $comment] + "Ticket-Tracker" { + categories { + "Ticket Type" { + "*Todo" + "Suggestion" + } + "Priority" { + "1 - High" + "*2 - Normal" + "3 - Low" + } } - default { - return [ad_html_text_convert -from text -to text -- $comment] + parameters { + TicketPrettyName "ticket" + TicketPrettyPlural "tickets" + ComponentPrettyName "area" + ComponentPrettyPlural "areas" + PatchesP "0" + VersionsP "0" } } } - - ##### - # - # Actions - # - ##### - - ad_proc bug_action_pretty { - action - {resolution ""} - } { - array set action_codes { - open "Opened" - edit "Edited" - reassign "Reassigned" - comment "Comment" - resolve "Resolved" - reopen "Reopened" - close "Closed" - patched "Patched" - } - if { [info exists action_codes($action)] } { +} - set action_pretty $action_codes($action) +ad_proc -public bug_tracker::delete_all_project_keywords { + {-package_id ""} +} { + Deletes all the keywords in a project +} { + if { ![exists_and_not_null package_id] } { + set package_id [ad_conn package_id] + } + db_exec_plsql keywords_delete {} + bug_tracker::get_keywords_flush -package_id $package_id +} - if { [string equal $action "resolve"] } { - set resolution_pretty [resolution_pretty $resolution] - if { ![empty_string_p $resolution_pretty] } { - append action_pretty " ($resolution_pretty)" - } - } +ad_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] - return $action_pretty - } else { - return "" + foreach { category_type categories } $spec { + set category_type_id [cr::keyword::get_keyword_id \ + -parent_id $root_keyword_id \ + -heading $category_type] + + if { [empty_string_p $category_type_id] } { + set category_type_id [cr::keyword::new \ + -parent_id $root_keyword_id \ + -heading $category_type] } - } - - ad_proc patch_action_pretty { - action - } { + + foreach category $categories { + if { [string equal [string index $category 0] "*"] } { + set default_p 1 + set category [string range $category 1 end] + } else { + set default_p 0 + } + + set category_id [cr::keyword::get_keyword_id \ + -parent_id $category_type_id \ + -heading $category] + + if { [empty_string_p $category_id] } { + set category_id [cr::keyword::new \ + -parent_id $category_type_id \ + -heading $category] + } - array set action_codes { - open "Opened" - edit "Edited" - comment "Comment" - accept "Accepted" - reopen "Reopened" - refuse "Refused" - delete "Deleted" + if { $default_p } { + bug_tracker::set_default_keyword \ + -parent_id $category_type_id \ + -keyword_id $category_id + } } + } + bug_tracker::get_keywords_flush -package_id $package_id +} - if { [info exists action_codes($action)] } { - return $action_codes($action) - } else { - return "" - } +ad_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 } +} - ##### - # - # Users (assignee) - # - ##### - - ad_proc users_get_options { - -package_id - } { - if { ![info exists package_id] } { - 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 distinct q.* - from ( - select u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id - from bt_bugs b, cc_users u - where b.project_id = :package_id - and u.user_id = b.assignee - union - select u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id - from bt_components c, cc_users u - where c.project_id = :package_id - and u.user_id = c.maintainer - union - select u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id - from bt_versions v, cc_users u - where v.project_id = :package_id - and u.user_id = v.maintainer - union - select u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id - from bt_projects p, cc_users u - where p.project_id = :package_id - and u.user_id = p.maintainer - union - select u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id - from cc_users u - where u.user_id = :user_id - ) q - order by name - } +##### +# +# Versions +# +##### - set users_list [db_list_of_lists users $sql] +ad_proc bug_tracker::version_get_options { + -package_id + -include_unknown:boolean + -include_undecided:boolean +} { + if { ![exists_and_not_null package_id] } { + set package_id [ad_conn package_id] + } - set users_list [concat { { "Unassigned" "" } } $users_list] - lappend users_list { "Search..." ":search:"} + set versions_list [util_memoize [list bug_tracker::version_get_options_not_cached $package_id]] - return $users_list + if { $include_unknown_p } { + set versions_list [concat { { "Unknown" "" } } $versions_list] + } + + if { $include_undecided_p } { + set versions_list [concat { { "Undecided" "" } } $versions_list] + } + + return $versions_list +} + + +ad_proc bug_tracker::versions_p { + {-package_id ""} +} { + Is the versions feature turned on? +} { + if { ![exists_and_not_null package_id] } { + set package_id [ad_conn package_id] } + return [parameter::get -package_id [ad_conn 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] +} + +ad_proc bug_tracker::version_get_options_not_cached { + package_id +} { + set versions_list [db_list_of_lists versions {}] - ##### - # - # Notification - # - ##### - - ad_proc bug_notify { - {-bug_id:required} - {-action ""} - {-comment ""} - {-comment_format ""} - {-resolution ""} - {-patch_summary ""} - } { + return $versions_list +} + +ad_proc bug_tracker::version_get_name { + {-package_id ""} + {-version_id:required} +} { + if { [empty_string_p $version_id] } { + return {} + } + foreach elm [version_get_options -package_id $package_id] { + set name [lindex $elm 0] + set id [lindex $elm 1] + if { [string equal $id $version_id] } { + return $name + } + } + error "Version_id $version_id not found" +} + + +##### +# +# Components +# +##### + +ad_proc bug_tracker::components_get_options { + {-package_id ""} + -include_unknown:boolean +} { + if { ![exists_and_not_null package_id] } { set package_id [ad_conn package_id] - - db_1row bug { - select b.bug_id, - b.bug_number, - b.summary, - b.project_id, - o.creation_user as submitter_user_id, - submitter.first_names as submitter_first_names, - submitter.last_name as submitter_last_name, - submitter.email as submitter_email, - b.component_id, - c.component_name, - o.creation_date, - to_char(o.creation_date, 'fmMM/DDfm/YYYY') as creation_date_pretty, - b.severity, - sc.sort_order || ' - ' || sc.severity_name as severity_pretty, - b.priority, - pc.sort_order || ' - ' || pc.priority_name as priority_pretty, - b.status, - b.resolution, - b.bug_type, - b.user_agent, - b.original_estimate_minutes, - b.latest_estimate_minutes, - b.elapsed_time_minutes, - b.found_in_version, - coalesce((select version_name - from bt_versions found_in_v - where found_in_v.version_id = b.found_in_version), 'Unknown') as found_in_version_name, - b.fix_for_version, - coalesce((select version_name - from bt_versions fix_for_v - where fix_for_v.version_id = b.fix_for_version), 'Undecided') as fix_for_version_name, - b.fixed_in_version, - coalesce((select version_name - from bt_versions fixed_in_v - where fixed_in_v.version_id = b.fixed_in_version), 'Unknown') as fixed_in_version_name, - b.assignee as assignee_user_id, - assignee.first_names as assignee_first_names, - assignee.last_name as assignee_last_name, - assignee.email as assignee_email, - to_char(now(), 'fmMon/DDfm/YYYY') as now_pretty - from bt_bugs b left outer join - cc_users assignee on (assignee.user_id = b.assignee), - acs_objects o, - bt_components c, - bt_priority_codes pc, - bt_severity_codes sc, - cc_users submitter - where b.bug_id = :bug_id - and b.project_id = :package_id - and o.object_id = b.bug_id - and c.component_id = b.component_id - and pc.priority_id = b.priority - and sc.severity_id = b.severity - and submitter.user_id = o.creation_user - } -column_array bug + } - set subject "Bug #$bug(bug_number). [ad_html_to_text -- [string_truncate -len 30 -- $bug(summary)]]: [bug_action_pretty $action $resolution] by [conn user_first_names] [conn user_last_name]" + set components_list [util_memoize [list bug_tracker::components_get_options_not_cached $package_id]] - set body "Bug no: #$bug(bug_number) -Summary: $bug(summary) + if { $include_unknown_p } { + set components_list [concat { { "Unknown" "" } } $components_list] + } + + return $components_list +} -Component: $bug(component_name) -Status: [status_pretty $bug(status)] -Severity: $bug(severity_pretty) -Priority: $bug(priority_pretty) -Found in version: $bug(found_in_version_name) +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] +} -Action: [bug_action_pretty $action $resolution] -By user: [conn user_first_names] [conn user_last_name] <[conn user_email]> +ad_proc bug_tracker::components_get_options_not_cached { + package_id +} { + set components_list [db_list_of_lists components {}] -" + return $components_list +} - if { ![string equal $action "patched"] } { - if { ![empty_string_p $comment] } { - append body "Comment:\n\n[bug_convert_comment_to_text -comment $comment -format $comment_format]\n\n" - } +ad_proc bug_tracker::component_get_name { + {-package_id ""} + {-component_id:required} +} { + if { [empty_string_p $component_id] } { + return {} + } + foreach elm [components_get_options -package_id $package_id] { + set id [lindex $elm 1] + if { [string equal $id $component_id] } { + return [lindex $elm 0] + } + } + error "Component_id $component_id not found" +} - } else { - append body "\n\nSummary: $patch_summary\n\n" +ad_proc bug_tracker::component_get_url_name { + {-package_id ""} + {-component_id:required} +} { + if { [empty_string_p $component_id] } { + return {} + } + foreach { id url_name } [components_get_url_names -package_id $package_id] { + if { [string equal $id $component_id] } { + return $url_name } + } + return {} +} - - append body "--\nTo comment on, edit, resolve, close, or reopen this bug, go to:\n[ad_url][ad_conn package_url]bug?[export_vars -url { { bug_number $bug(bug_number) } }]\n" +ad_proc bug_tracker::components_get_url_names { + {-package_id ""} +} { + if { ![exists_and_not_null package_id] } { + set package_id [ad_conn package_id] + } + return [util_memoize [list bug_tracker::components_get_url_names_not_cached -package_id $package_id]] +} - # Use the Notification service to alert (could be immediately, or daily, or weekly) - # people who have signed up for notification on this bug - notification::new \ - -type_id [notification::type::get_type_id -short_name bug_tracker_bug_notif] \ - -object_id $bug(bug_id) \ - -response_id $bug(bug_id) \ - -notif_subject $subject \ - -notif_text $body - - # Use the Notification service to alert people who have signed up for notification - # in this bug tracker package instance - notification::new \ - -type_id [notification::type::get_type_id -short_name bug_tracker_project_notif] \ - -object_id $bug(project_id) \ - -response_id $bug(bug_id) \ - -notif_subject $subject \ - -notif_text $body - } +ad_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 +} - ad_proc add_instant_alert { - {-bug_id:required} - {-user_id:required} - } { - notification::request::new \ - -type_id [notification::type::get_type_id -short_name bug_tracker_bug_notif] \ - -user_id $user_id \ - -object_id $bug_id \ - -interval_id [notification::get_interval_id -name "daily"] \ - -delivery_method_id [notification::get_delivery_method_id -name "email"] - } - ad_proc get_notification_link { - {-type:required} - {-object_id:required} - {-pretty_name:required} - {-url:required} - } { - Returns a list with the url, label, and title for a notifications link (subscribe or unsubscribe). - } { +##### +# +# Description +# +##### - set user_id [ad_conn user_id] +ad_proc bug_tracker::bug_convert_comment_to_html { + {-comment:required} + {-format:required} +} { + ns_log Notice "LARS: Format=$format, comment=$comment, formatted = [ad_html_text_convert -from $format -to text/html -- $comment]" + return [ad_html_text_convert -from $format -to text/html -- $comment] +} - set notification_link [list] - # Only present the link to logged in users. - if { $user_id != 0 } { - set type_id [notification::type::get_type_id -short_name $type] - if { [empty_string_p $type_id] } { - ns_log Error "Can't find notification of type '$type'" - return "" - } +ad_proc bug_tracker::bug_convert_comment_to_text { + {-comment:required} + {-format:required} +} { + return [ad_html_text_convert -from $format -to text/plain -- $comment] +} - set request_id [notification::request::get_request_id -type_id $type_id -object_id $object_id -user_id $user_id] +##### +# +# Actions +# +##### - if { ![empty_string_p $request_id] } { - # The user is already subscribed - lappend notification_link [notification::display::unsubscribe_url -request_id $request_id -url $url] - lappend notification_link "Unsubscribe" - lappend notification_link "Unsubscribe from notifications for this $pretty_name" - } else { - # The user is not subscribed - lappend notification_link [notification::display::subscribe_url \ - -type bug_tracker_project_notif \ - -object_id $object_id \ - -url $url \ - -user_id $user_id \ - -pretty_name "a $pretty_name" - ] - lappend notification_link "Subscribe" - lappend notification_link "Subscribe to notifications for this $pretty_name" +ad_proc bug_tracker::bug_action_pretty { + action + {resolution ""} +} { + array set action_codes { + open "Opened" + edit "Edited" + reassign "Reassigned" + comment "Comment" + resolve "Resolved" + reopen "Reopened" + close "Closed" + patched "Patched" + } + if { [info exists action_codes($action)] } { + + set action_pretty $action_codes($action) + + if { [string equal $action "resolve"] } { + set resolution_pretty [resolution_pretty $resolution] + if { ![empty_string_p $resolution_pretty] } { + append action_pretty " ($resolution_pretty)" } } - return $notification_link + return $action_pretty + } else { + return "" } +} - ad_proc map_patch_to_bug { - {-patch_id:required} - {-bug_id:required} - } { - db_dml map_patch_to_bug { - insert into bt_patch_bug_map (patch_id, bug_id) values (:patch_id, :bug_id) - } +ad_proc bug_tracker::patch_action_pretty { + action +} { + + array set action_codes { + open "Opened" + edit "Edited" + comment "Comment" + accept "Accepted" + reopen "Reopened" + refuse "Refused" + delete "Deleted" } - ad_proc unmap_patch_from_bug { - {-patch_number:required} - {-bug_number:required} - } { + if { [info exists action_codes($action)] } { + return $action_codes($action) + } else { + return "" + } +} + +##### +# +# Maintainers +# +##### + +ad_proc ::bug_tracker::users_get_options { + -package_id +} { + if { ![info exists package_id] } { set package_id [ad_conn package_id] - db_dml unmap_patch_from_bug { - delete from bt_patch_bug_map - where bug_id = (select bug_id from bt_bugs - where bug_number = :bug_number - and project_id = :package_id) - and patch_id = (select patch_id from bt_patches - where patch_number = :patch_number - and project_id = :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 { { "Unassigned" "" } } $users_list] + lappend users_list { "Search..." ":search:"} + + return $users_list +} - ad_proc 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] +ad_proc ::bug_tracker::users_get_searchquery { + -package_id +} { + +} + +ad_proc -private bug_tracker::get_maintainer_role_id { + -package_id +} { + if { ![info exists package_id] } { set package_id [ad_conn package_id] + } + # We're using the assignee widget for a certain role to assign the version maintainer + set workflow_id [bug_tracker::bug::get_instance_workflow_id -package_id [ad_conn package_id]] + set role_ids [workflow::get_roles -workflow_id $workflow_id] + + # LARS HACK: + # We'll use the last role in sort order + return [lindex $role_ids end] +} + - set open_clause [ad_decode $only_open_p "1" "\n and bt_bugs.status = 'open'" ""] +##### +# +# Patches +# +##### - db_foreach get_bugs_for_patch "select bt_bugs.bug_number, - bt_bugs.summary - from bt_bugs, bt_patch_bug_map - where bt_bugs.bug_id = bt_patch_bug_map.bug_id - and bt_patch_bug_map.patch_id = (select patch_id - from bt_patches - where patch_number = :patch_number - and project_id = :package_id - ) - $open_clause" { +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] +} - lappend bug_list [list "$summary" "$bug_number"] - } +ad_proc bug_tracker::map_patch_to_bug { + {-patch_id:required} + {-bug_id:required} +} { + db_dml map_patch_to_bug {} +} - return $bug_list +ad_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 {} +} + +ad_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 "" } - ad_proc 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] + db_foreach get_bugs_for_patch {} { + lappend bug_list [list "[bug_tracker::conn Bug] #$bug_number: $summary" "$bug_number"] + } - if { [llength $bug_list] == "0"} { - return "" - } else { - - foreach bug_item $bug_list { + return $bug_list +} - set bug_number [lindex $bug_item 1] - set bug_summary [lindex $bug_item 0] +ad_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] - set unmap_url "unmap-patch-from-bug?[export_vars -url { patch_number bug_number } ]" - if { $write_or_submitter_p } { - set unmap_link "(unmap)" - } else { - set unmap_link "" - } - lappend bug_link_list "$bug_summary $unmap_link" - } + if { [llength $bug_list] == "0"} { + return "" + } else { + + foreach bug_item $bug_list { - if { [llength $bug_link_list] != 0 } { - set bugs_string [join $bug_link_list ", "] + set bug_number [lindex $bug_item 1] + set bug_summary [lindex $bug_item 0] + + set unmap_url "unmap-patch-from-bug?[export_vars -url { patch_number bug_number } ]" + if { $write_or_submitter_p } { + set unmap_link "(unmap)" } else { - set bugs_string "No bugs." + set unmap_link "" } + lappend bug_link_list "$bug_summary $unmap_link" + } - return $bugs_string + if { [llength $bug_link_list] != 0 } { + set bugs_string [join $bug_link_list "
"] + } else { + set bugs_string "No bugs." } - } - ad_proc get_patch_links { - {-bug_id:required} - {-show_patch_status "open"} - } { - set patch_list [list] + return $bugs_string + } +} - switch -- $show_patch_status { - open { - set status_where_clause "and bt_patches.status = :show_patch_status" - } - all { - set status_where_clause "" - } - } +ad_proc bug_tracker::get_patch_links { + {-bug_id:required} + {-show_patch_status "open"} +} { + set patch_list [list] - db_foreach get_patches_for_bug \ - "select bt_patches.patch_number, - bt_patches.summary, - bt_patches.status - from bt_patch_bug_map, bt_patches - where bt_patch_bug_map.bug_id = :bug_id - and bt_patch_bug_map.patch_id = bt_patches.patch_id - $status_where_clause - " { - - set status_indicator [ad_decode $show_patch_status "all" "($status)" ""] - lappend patch_list "$summary $status_indicator" - } if_no_rows { - set patches_string "No patches." + switch -- $show_patch_status { + open { + set status_where_clause "and bt_patches.status = :show_patch_status" } - - if { [llength $patch_list] != 0 } { - set patches_string [join $patch_list ", "] + all { + set status_where_clause "" } - - return $patches_string } - ad_proc get_patch_submitter { - {-patch_number:required} - } { - set package_id [ad_conn package_id] - return [db_string patch_submitter_id "select acs_objects.creation_user - from bt_patches, acs_objects - where bt_patches.patch_number = :patch_number - and bt_patches.project_id = :package_id - and bt_patches.patch_id = acs_objects.object_id"] + db_foreach get_patches_for_bug "" { + + set status_indicator [ad_decode $show_patch_status "all" "($status)" ""] + lappend patch_list "$summary $status_indicator" + } if_no_rows { + set patches_string "No patches." } - ad_proc update_patch_status { - {-patch_number:required} - {-new_status:required} - } { - set package_id [ad_conn package_id] - db_dml update_patch_status "update bt_patches - set status = :new_status - where bt_patches.project_id = :package_id - and bt_patches.patch_number = :patch_number" + if { [llength $patch_list] != 0 } { + set patches_string [join $patch_list ", "] } - ad_proc get_uploaded_patch_file_content { - - } { - set patch_file [ns_queryget patch_file] - - if { [empty_string_p $patch_file] } { - # No patch file was uploaded - return "" - } + return $patches_string +} - set tmp_file [ns_queryget patch_file.tmpfile] - set tmp_file_channel [open $tmp_file r] - set content [read $tmp_file_channel] +ad_proc bug_tracker::get_patch_submitter { + {-patch_number:required} +} { + set package_id [ad_conn package_id] + return [db_string patch_submitter_id {}] +} - return $content +ad_proc bug_tracker::update_patch_status { + {-patch_number:required} + {-new_status:required} +} { + set package_id [ad_conn package_id] + db_dml update_patch_status "" +} + +ad_proc bug_tracker::get_uploaded_patch_file_content { + +} { + set patch_file [ns_queryget patch_file] + + if { [empty_string_p $patch_file] } { + # No patch file was uploaded + return "" } - ad_proc parse_filters { filter_array_name } { - Parses the array named in 'filter_array_name', setting local - variables for the filter parameters, and constructing a chunk - that can be used in a query, plus a human readable - string. Sets the result in bug_tracker::conn as - 'filter_human_readable', 'filter_where_clauses', and - 'filter_order_by_clause'. - } { - upvar $filter_array_name filter + set tmp_file [ns_queryget patch_file.tmpfile] + set tmp_file_channel [open $tmp_file r] + set content [read $tmp_file_channel] - set where_clauses [list] + return $content +} - set valid_filters { - status - bug_type - fix_for_version:integer - severity:integer - priority:integer - assignee:integer - component_id:integer - actionby:integer - {orderby ""} - } - - foreach name $valid_filters { - if { [llength $name] > 1 } { - set default [lindex $name 1] - set name [lindex $name 0] - } else { - if { [info exists default] } { - unset default - } - } - if { [llength [split $name ":"]] > 1 } { - set filters [split [lindex [split $name ":"] 1] ,] - set name [lindex [split $name ":"] 0] - } else { - set filters [list] - } - if { [info exists filter($name)] } { - upvar __filter_$name var - set var $filter($name) +ad_proc bug_tracker::parse_filters { filter_array_name } { + Parses the array named in 'filter_array_name', setting local + variables for the filter parameters, and constructing a chunk + that can be used in a query, plus a human readable + string. Sets the result in bug_tracker::conn as + 'filter_human_readable', 'filter_where_clauses', 'filter_from_bug_clause', + 'filter_order_by_clause'. +} { + upvar $filter_array_name filter - if { [lsearch -exact $filters "integer"] != -1 && ![empty_string_p $var]} { - validate_integer $name $var - } - } elseif { [info exists default] } { - upvar __filter_$name var - set var $default + set where_clauses [list] + set from_bug_clause "bt_bugs b" + + set workflow_id [bug_tracker::bug::get_instance_workflow_id] + set initial_state_id [workflow::fsm::get_initial_state -workflow_id $workflow_id] + + set valid_filters { + {status $initial_state_id} + {action_id} + fix_for_version:integer + assignee:integer + action_id:integer + component_id:integer + keyword:integer,multiple + {n_days 7} + {orderby ""} + } + + foreach name $valid_filters { + if { [llength $name] > 1 } { + set default [subst [lindex $name 1]] + set name [lindex $name 0] + } else { + if { [info exists default] } { + unset default } - # also upvar it under its real name - upvar __filter_$name __filter_$name } - - - if { ![info exists __filter_status] } { - if { [info exists __filter_actionby] } { - set __filter_status "" - } else { - set __filter_status "open" - } - } - - if { ![empty_string_p $__filter_status] } { - lappend where_clauses "b.status = :__filter_status" - set human_readable_filter "All $__filter_status bugs" + if { [llength [split $name ":"]] > 1 } { + set filters [split [lindex [split $name ":"] 1] ,] + set name [lindex [split $name ":"] 0] } else { - lappend where_clauses "b.status != 'closed'" - set human_readable_filter "All open and resolved bugs" + set filters [list] } - - if { [info exists __filter_bug_type] } { - lappend where_clauses "b.bug_type = :__filter_bug_type" - append human_readable_filter " of type [bug_tracker::bug_type_pretty $__filter_bug_type]" - } - - if { [info exists __filter_assignee] } { - if { [empty_string_p $__filter_assignee] } { - lappend where_clauses "b.assignee is null" - append human_readable_filter " that are unassigned" + + # special case for annoying tcl'ism, whereby if you say + # lappend foo(bar) {}, your foo(bar) entry will be equal to {{}}, + # which we run into, because the page defines filters as + # :array,multiple + if { [info exists filter($name)] && [string equal $filter($name) {{}}] } { + if { [lsearch -exact $filters "multiple"] != -1 } { + unset filter($name) } else { - lappend where_clauses "b.assignee = :__filter_assignee" - if { $__filter_assignee == [ad_conn user_id] } { - append human_readable_filter " assigned to me" + set filter($name) {} + } + } + + if { [info exists filter($name)] } { + upvar filter_$name var + set var $filter($name) + + if { [lsearch -exact $filters "integer"] != -1 && ![empty_string_p $var]} { + if { [lsearch -exact $filters "multiple"] != -1 } { + foreach elm $var { + validate_integer $name $elm + } } else { - append human_readable_filter " assigned to [db_string assignee_name { select first_names || ' ' || last_name from cc_users where user_id = :__filter_assignee }]" + validate_integer $name $var } } + + } elseif { [info exists default] } { + upvar filter_$name var + set var $default } + # also upvar it under its real name + upvar filter_$name filter_$name + } + + if { [info exists filter_status] && ![string equal $filter_status "any"] } { + lappend where_clauses "cfsm.current_state = :filter_status" - if { [info exists __filter_actionby] } { - lappend where_clauses "((b.status = 'open' and b.assignee = :__filter_actionby) or (b.status = 'resolved' and o.creation_user = :__filter_actionby))" - if { $__filter_actionby == [ad_conn user_id] } { - append human_readable_filter " awaiting action by me" + set status_pretty [workflow::state::fsm::get_element \ + -state_id $filter_status \ + -element pretty_name] + + set human_readable_filter "All $status_pretty [bug_tracker::conn bugs]" + } else { + set human_readable_filter "[bug_tracker::conn Bugs] of any status" + } + + if { [info exists filter_bug_type] } { + lappend where_clauses "b.bug_type = :filter_bug_type" + append human_readable_filter " of type [bug_tracker::bug_type_pretty $filter_bug_type]" + } + + if { [info exists filter_assignee] } { + if { [empty_string_p $filter_assignee] } { + lappend where_clauses "assignee.party_id is null" + + append human_readable_filter " that are unassigned" + } else { + + lappend where_clauses "assignee.party_id = :filter_assignee" + + if { $filter_assignee == [ad_conn user_id] } { + append human_readable_filter " assigned to me" } else { - append human_readable_filter " awaiting action by [db_string actionby_name { select first_names || ' ' || last_name from cc_users where user_id = :__filter_actionby }]" + append human_readable_filter " assigned to [db_string assignee_name {}]" } } - - if { [info exists __filter_severity] } { - lappend where_clauses "b.severity = :__filter_severity" - append human_readable_filter " where severity is [db_string severity_name { select severity_name from bt_severity_codes where severity_id = :__filter_severity }]" + } + + if { [info exists filter_keyword] } { + set keyword_human [list] + foreach keyword_id $filter_keyword { + lappend where_clauses [db_map keyword_filter] + set category_name [category_heading -keyword_id $keyword_id] + + # LARS: + # This is a hack to be smart about stripping out the "1 - " or "A - " part + # if people use that naming style + regsub {^[a-zA-Z0-9]\s[-*]*\s} $category_name {} category_name + + lappend keyword_human "[category_parent_heading -keyword_id $keyword_id] is $category_name" } - - if { [info exists __filter_priority] } { - lappend where_clauses "b.priority = :__filter_priority" - append human_readable_filter " with a priority of [db_string priority_name { select priority_name from bt_priority_codes where priority_id = :__filter_priority }]" + append human_readable_filter " where [join $keyword_human " and "]" + } + + if { ![empty_string_p [conn component_id]] } { + set filter_component_id [conn component_id] + } + + if { [info exists filter_component_id] } { + lappend where_clauses "b.component_id = :filter_component_id" + append human_readable_filter " in [component_get_name -component_id $filter_component_id]" + conn -set component_id $filter_component_id + } + + if { [info exists filter_fix_for_version] } { + if { [empty_string_p $filter_fix_for_version] } { + lappend where_clauses "b.fix_for_version is null" + append human_readable_filter " where fix for version is undecided" + } else { + lappend where_clauses "b.fix_for_version = :filter_fix_for_version" + append human_readable_filter " to be fixed in version [db_string version_name {}]" } - - if { ![empty_string_p [conn component_id]] } { - set __filter_component_id [conn component_id] + } + + if { [empty_string_p $filter_orderby] } { + set order_by_clause "b.bug_number desc" + } else { + append from_bug_clause [db_map orderby_filter_from_bug] + lappend where_clauses [db_map orderby_filter_where] + set order_by_clause "kw_order.heading, bug_number desc " + } + + if { ![empty_string_p $filter_n_days] } { + if { ![string equal $filter_n_days "all"] } { + lappend where_clauses [db_map n_days_filter] + append human_readable_filter " opened in the last $filter_n_days days" } + } - if { [info exists __filter_component_id] } { - lappend where_clauses "b.component_id = :__filter_component_id" - append human_readable_filter " in [db_string component_name { select component_name from bt_components where component_id = :__filter_component_id }]" - conn -set component_id $__filter_component_id + conn -set filter [array get filter] + conn -set filter_human_readable $human_readable_filter + conn -set filter_where_clauses $where_clauses + conn -set filter_order_by_clause $order_by_clause + conn -set filter_from_bug_clause $from_bug_clause +} + +ad_proc bug_tracker::filter_url_vars { + {-array:required} + {-override:required} +} { + Returns query args for the URL string, overriding the existing filters with the new one given by name and value. + Existing orderby and n_days filters are kept, however, unless that's the one you're replacing + @param array the name of the array in the caller's scope holding the current filter values + @param override an array list of new values to set instead +} { + upvar $array cur_filters + + array set filter [list] + + foreach keeper { orderby n_days } { + if { [info exists cur_filters($keeper)] } { + set filter($keeper) $cur_filters($keeper) } - - if { [info exists __filter_fix_for_version] } { - if { [empty_string_p $__filter_fix_for_version] } { - lappend where_clauses "b.fix_for_version is null" - append human_readable_filter " where fix for version is undecided" - } else { - lappend where_clauses "b.fix_for_version = :__filter_fix_for_version" - append human_readable_filter " to be fixed in version [db_string version_name { select version_name from bt_versions where version_id = :__filter_fix_for_version }]" - } + } + + array set filter $override + return [export_vars { filter:array }] +} + +ad_proc bug_tracker::context_bar { args } { + Context bar that takes the component information into account +} { + set component_id [conn component_id] + if { ![empty_string_p $component_id] } { + set component_name [bug_tracker::component_get_name -component_id $component_id] + set url_name [bug_tracker::component_get_url_name -component_id $component_id] + if { [llength $args] == 0 } { + return [eval ad_context_bar [list $component_name]] + } else { + return [eval ad_context_bar [list [list "[ad_conn package_url]com/$url_name/" $component_name]] $args] } - - switch -exact -- $__filter_orderby { - severity { - set order_by_clause "sc.sort_order, b.bug_number desc" - append human_readable_filter ", most severe bugs first" - } - priority { - set order_by_clause "pc.sort_order, b.bug_number desc" - append human_readable_filter ", highest priority bugs first" - } - default { - set order_by_clause "b.bug_number desc" - } - } + } else { + return [eval ad_context_bar $args] + } +} - conn -set filter [array get filter] - conn -set filter_human_readable $human_readable_filter - conn -set filter_where_clauses $where_clauses - conn -set filter_order_by_clause $order_by_clause +ad_proc bug_tracker::security_violation { + -user_id:required + -bug_id:required + -action:required +} { + ns_log Notice "$user_id doesn't have permission to '$action' on bug $bug_id" + ad_return_forbidden \ + "Security Violation" \ + "
+ You don't have permission to '$action' on this bug. +
+ This incident has been logged. +
" + ad_script_abort +} +ad_proc bug_tracker::bug_delete { bug_id } { + Delete a Bug Tracker bug. + This should only ever be run when un-instantiating a project! + + @author Mark Aufflick +} { + set case_id [db_string get_case_id {}] + db_exec_plsql delete_bug_case {} + set notifications [db_list get_notifications {}] + foreach notification_id $notifications { + db_exec_plsql delete_notification {} } + db_dml unset_revisions {} + db_exec_plsql delete_cr_item {} +} - ad_proc context_bar { args } { - Context bar that takes the component information into account - } { - set component_id [conn component_id] - if { ![empty_string_p $component_id] } { - db_1row component_name { - select component_name, url_name from bt_components where component_id = :component_id - } - if { [llength $args] == 0 } { - return [eval ad_context_bar [list $component_name]] - } else { - return [eval ad_context_bar [list [list "[ad_conn package_url]com/$url_name/" $component_name]] $args] - } - } else { - return [eval ad_context_bar $args] +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 wierd integrity constraints + while { [set bug_id [db_string min_bug_id {}]] > 0 } { + 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 +} { + db_exec_plsql create_project {} +} + +ad_proc bug_tracker::bug_notify { + {-bug_id:required} + {-action ""} + {-comment ""} + {-comment_format ""} + {-resolution ""} + {-patch_summary ""} +} { + set package_id [ad_conn package_id] + + db_1row bug {} -column_array bug + set bug(found_in_version_name) [version_get_name -version_id $bug(found_in_version)] + set bug(fix_for_version_name) [version_get_name -version_id $bug(fix_for_version)] + set bug(fixed_in_version_name) [version_get_name -version_id $bug(fixed_in_version)] + + get_pretty_names -array pretty_names + + set subject "$pretty_names(Bug) #$bug(bug_number). [ad_html_to_text -- [string_truncate -len 30 $bug(summary)]]: [bug_action_pretty $action $resolution] by [conn user_first_names] [conn user_last_name]" + + set body "$pretty_names(Bug) no: #$bug(bug_number) +Summary: $bug(summary) + +$pretty_names(Component): $bug(component_name) +Status: $bug(status) +" + +foreach {category_id category_name} [bug_tracker::category_types] { + append body "$category_name: [cr::keyword::item_get_assigned -item_id $bug(bug_id) -parent_id $category_id] +" +} + +append body "Found in version: $bug(found_in_version_name) + +Action: [bug_action_pretty $action $resolution] +By user: [conn user_first_names] [conn user_last_name] <[conn user_email]> + +" + + if { ![string equal $action "patched"] } { + if { ![empty_string_p $comment] } { + append body "Comment:\n\n[bug_convert_comment_to_text -comment $comment -format $comment_format]\n\n" } + + } else { + append body "\n\nSummary: $patch_summary\n\n" } + + append body "--\nTo comment on, edit, resolve, close, or reopen this bug, go to:\n[ad_url][ad_conn package_url]bug?[export_vars -url { { bug_number $bug(bug_number) } }]\n" + + # Use the Notification service to alert (could be immediately, or daily, or weekly) + # people who have signed up for notification on this bug + notification::new \ + -type_id [notification::type::get_type_id -short_name bug_tracker_bug_notif] \ + -object_id $bug(bug_id) \ + -response_id $bug(bug_id) \ + -notif_subject $subject \ + -notif_text $body + + # Use the Notification service to alert people who have signed up for notification + # in this bug tracker package instance + notification::new \ + -type_id [notification::type::get_type_id -short_name bug_tracker_project_notif] \ + -object_id $bug(project_id) \ + -response_id $bug(bug_id) \ + -notif_subject $subject \ + -notif_text $body } Index: openacs-4/packages/bug-tracker/www/bug-add.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/bug-add.adp,v diff -u -r1.3 -r1.3.2.1 --- openacs-4/packages/bug-tracker/www/bug-add.adp 20 Sep 2002 15:08:57 -0000 1.3 +++ openacs-4/packages/bug-tracker/www/bug-add.adp 5 Mar 2003 18:13:52 -0000 1.3.2.1 @@ -13,3 +13,4 @@ + Index: openacs-4/packages/bug-tracker/www/bug-add.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/bug-add.tcl,v diff -u -r1.7 -r1.7.2.1 --- openacs-4/packages/bug-tracker/www/bug-add.tcl 13 Sep 2002 08:30:32 -0000 1.7 +++ openacs-4/packages/bug-tracker/www/bug-add.tcl 5 Mar 2003 18:13:52 -0000 1.7.2.1 @@ -5,20 +5,13 @@ @creation-date 2002-03-25 @cvs-id $Id$ } { - cancel:optional {return_url ""} } if { [empty_string_p $return_url] } { set return_url "." } -# If the user hit cancel, ignore everything else -if { [exists_and_not_null cancel] } { - ad_returnredirect $return_url - ad_script_abort -} - ad_require_permission [ad_conn package_id] create # User needs to be logged in here @@ -29,135 +22,81 @@ set package_id [ad_conn package_id] set package_key [ad_conn package_key] -set page_title "New Bug" +set page_title "New [bug_tracker::conn Bug]" set context_bar [bug_tracker::context_bar $page_title] set user_id [ad_conn user_id] +# Is this project using multiple versions? +set versions_p [bug_tracker::versions_p] # Create the form +ad_form -name bug -cancel_url $return_url -form { + bug_id:key(acs_object_id_seq) -form create bug + {component_id:text(select) + {label "[bug_tracker::conn Component]"} + {options {[bug_tracker::components_get_options]}} + {value {[bug_tracker::conn component_id]}} + } + {summary:text + {label "Summary"} + {html {size 50}} + } + {found_in_version:text(select) + {label "Version"} + {options {[bug_tracker::version_get_options -include_unknown]}} + {value {[bug_tracker::conn user_version_id]}} + optional + } -element create bug bug_id \ - -datatype integer \ - -widget hidden + {return_url:text(hidden) {value $return_url}} +} +foreach {category_id category_name} [bug_tracker::category_types] { + ad_form -extend -name bug -form [list \ + [list "${category_id}:integer(select)" \ + [list label $category_name] \ + [list options [bug_tracker::category_get_options -parent_id $category_id]] \ + [list value [bug_tracker::get_default_keyword -parent_id $category_id]] \ + ] \ + ] +} -element create bug component_id \ - -datatype integer \ - -widget select \ - -label "Component" \ - -options [bug_tracker::components_get_options] - -element create bug bug_type \ - -datatype text \ - -widget select \ - -label "Type of bug" \ - -options [bug_tracker::bug_type_get_options] \ - -optional - -element create bug summary \ - -datatype text \ - -label "Summary" \ - -html { size 50 } - -element create bug severity \ - -datatype integer \ - -widget select \ - -label "Severity" \ - -options [bug_tracker::severity_codes_get_options] \ - -optional - -element create bug priority \ - -datatype integer \ - -widget select \ - -label "Priority" \ - -options [bug_tracker::priority_codes_get_options] \ - -optional - -element create bug found_in_version \ - -datatype integer \ - -widget select \ - -label "Version" \ - -options [bug_tracker::version_get_options -include_unknown] \ - -optional - -element create bug description \ - -datatype text \ - -widget textarea \ - -label "Description" \ - -html { cols 50 rows 10 } \ - -optional - -element create bug desc_format \ - -datatype text \ - -widget select \ - -label "Description format" \ - -options { { "Plain" plain } { "HTML" html } { "Preformatted" pre } } - -element create bug return_url \ - -datatype text \ - -widget hidden \ - -value $return_url - - -if { [form is_request bug] } { - - element set_properties bug bug_id -value [db_nextval "acs_object_id_seq"] - - element set_properties bug found_in_version \ - -value [bug_tracker::conn user_version_id] - - element set_properties bug severity -value [bug_tracker::severity_get_default] - element set_properties bug priority -value [bug_tracker::priority_get_default] - - if { ![empty_string_p [bug_tracker::conn component_id]] } { - element set_properties bug component_id -value [bug_tracker::conn component_id] +ad_form -extend -name bug -form { + {description:richtext(richtext) + {label "Description"} + {html {cols 60 rows 13}} + optional } - element set_properties bug desc_format -value "plain" +} -} +ad_form -extend -name bug -new_data { + bug_tracker::bug::new \ + -bug_id $bug_id \ + -package_id $package_id \ + -component_id $component_id \ + -found_in_version $found_in_version \ + -summary $summary \ + -description [template::util::richtext::get_property contents $description] \ + -desc_format [template::util::richtext::get_property format $description] - -if { [form is_valid bug] } { - - db_transaction { - - form get_values bug bug_id component_id bug_type severity priority found_in_version summary description desc_format + foreach {category_id category_name} [bug_tracker::category_types] { + # -singular not required here since it's a new bug + cr::keyword::item_assign -item_id $bug_id -keyword_id [element get_value bug $category_id] + } - set ip_address [ns_conn peeraddr] - set user_agent [ns_set get [ns_conn headers] "User-Agent"] +} -after_submit { + bug_tracker::bugs_exist_p_set_true - db_exec_plsql new_bug { - select bt_bug__new( - :bug_id, - :package_id, - :component_id, - :bug_type, - :severity, - :priority, - :found_in_version, - :summary, - :description, - :desc_format, - :user_agent, - :user_id, - :ip_address - ) - } - - } - - bug_tracker::bug_notify -bug_id $bug_id -action "open" -comment $description -comment_format $desc_format - - # Sign up the submitter of the bug for instant alerts. We do this after calling - # the alert procedure so that the submitter isn't alerted about his own submittal of the bug - bug_tracker::add_instant_alert -bug_id $bug_id -user_id $user_id - ad_returnredirect $return_url ad_script_abort } + +if { !$versions_p } { + element set_properties bug found_in_version -widget hidden +} + ad_return_template Index: openacs-4/packages/bug-tracker/www/bug.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/bug.adp,v diff -u -r1.3 -r1.3.2.1 --- openacs-4/packages/bug-tracker/www/bug.adp 11 Sep 2002 14:03:25 -0000 1.3 +++ openacs-4/packages/bug-tracker/www/bug.adp 5 Mar 2003 18:13:52 -0000 1.3.2.1 @@ -1,9 +1,9 @@ @page_title@ @context_bar@ -@notification_link@ +@notification_link@ - +
@@ -17,22 +17,17 @@
- -

+ +

- -
-
- @button_form_export_vars@ - - - -
-
+ +

+ You're not logged in. For more options, log in now. +

- +
(show user agent) @@ -43,4 +38,3 @@
-

Index: openacs-4/packages/bug-tracker/www/bug.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/bug.tcl,v diff -u -r1.12.2.6 -r1.12.2.7 --- openacs-4/packages/bug-tracker/www/bug.tcl 20 Jan 2003 13:33:46 -0000 1.12.2.6 +++ openacs-4/packages/bug-tracker/www/bug.tcl 5 Mar 2003 18:13:52 -0000 1.12.2.7 @@ -5,621 +5,411 @@ @creation-date 2002-03-20 @cvs-id $Id$ } { - mode:optional bug_number:integer,notnull - edit:optional - comment:optional - reassign:optional - resolve:optional - reopen:optional - cancel:optional - close:optional {user_agent_p:boolean 0} - {show_patch_status "all"} + {show_patch_status "open"} filter:array,optional } +##### +# +# Setup +# +##### + set return_url "[ad_conn url]?[export_vars -url { bug_number filter:array }]" -# If the user hit cancel, ignore everything else -if { [exists_and_not_null cancel] } { - ad_returnredirect $return_url - ad_script_abort -} - -ad_require_permission [ad_conn package_id] read - -if { ![info exists mode] } { - if { [exists_and_not_null edit] } { - set mode "edit" - } elseif { [exists_and_not_null comment] } { - set mode "comment" - } elseif { [exists_and_not_null reassign] } { - set mode "reassign" - } elseif { [exists_and_not_null resolve] } { - set mode "resolve" - } elseif { [exists_and_not_null reopen] } { - set mode "reopen" - } elseif { [exists_and_not_null close] } { - set mode "close" - } else { - set mode "view" - } -} - -switch -- $mode { - edit { - set edit_fields { component_id bug_type summary severity priority found_in_version assignee fix_for_version resolution fixed_in_version } - } - comment { - set edit_fields {} - } - reassign { - set edit_fields { assignee } - } - resolve { - set edit_fields { resolution fixed_in_version } - } - default { - set edit_fields {} - } -} -foreach field $edit_fields { - set field_editable_p($field) 1 -} - -if { ![string equal $mode "view"] } { - ad_maybe_redirect_for_registration -} - set project_name [bug_tracker::conn project_name] set package_id [ad_conn package_id] set package_key [ad_conn package_key] set user_id [ad_conn user_id] -set write_p [ad_permission_p $package_id write] +permission::require_permission -object_id $package_id -privilege read +set page_title "[bug_tracker::conn Bug] #$bug_number" +set context_bar [bug_tracker::context_bar $page_title] + +# Is this project using multiple versions? +set versions_p [bug_tracker::versions_p] + +# Paches enabled for this project? +set patches_p [bug_tracker::patches_p] + + +##### # -# Filter management +# Get basic info # +##### -set filter_parsed [bug_tracker::parse_filters filter] +# Get the bug_id +db_1row permission_info {} -column_array bug -if { [string equal $mode view] } { +set case_id [workflow::case::get_id \ + -object_id $bug(bug_id) \ + -workflow_short_name [bug_tracker::bug::workflow_short_name]] - set human_readable_filter [bug_tracker::conn filter_human_readable] - set where_clauses [bug_tracker::conn filter_where_clauses] - set order_by_clause [bug_tracker::conn filter_order_by_clause] - - lappend where_clauses "b.project_id = :package_id" +set workflow_id [bug_tracker::bug::get_instance_workflow_id] - set filter_bug_numbers [db_list filter_bug_numbers " - select bug_number - from bt_bugs b join - acs_objects o on (object_id = bug_id) join - bt_priority_codes pc on (pc.priority_id = b.priority) join - bt_severity_codes sc on (sc.severity_id = b.severity) - where [join $where_clauses " and "] - order by $order_by_clause - "] +set role_ids [workflow::get_roles -workflow_id $workflow_id] - set filter_bug_index [lsearch -exact $filter_bug_numbers $bug_number] - multirow create navlinks url label - - if { $filter_bug_index != -1 } { - - if { $filter_bug_index > 0 } { - multirow append navlinks "bug?[export_vars { { bug_number {[lindex $filter_bug_numbers [expr $filter_bug_index -1]]} } filter:array }]" "<" - } else { - multirow append navlinks "" "<" - } - - multirow append navlinks "" "[expr $filter_bug_index+1] of [llength $filter_bug_numbers]" - - if { $filter_bug_index < [expr [llength $filter_bug_numbers]-1] } { - multirow append navlinks "bug?[export_vars { { bug_number {[lindex $filter_bug_numbers [expr $filter_bug_index +1]]} } filter:array }]" ">" - } else { - multirow append navlinks "" ">" - } - } -} +##### +# +# Action +# +##### +set action_id [form get_action bug] -# Create the form +if { ![empty_string_p $action_id] } { + set action_short_name [workflow::action::get_element -action_id $action_id -element short_name] +} else { + set action_short_name {} +} -switch -- $mode { - view { - form create bug -has_submit 1 - } - default { - form create bug - } +# Registration required for all actions +if { ![empty_string_p $action_id] } { + ad_maybe_redirect_for_registration } -element create bug bug_number \ - -datatype integer \ - -widget hidden +# Check permissions +if { ![workflow::case::action::available_p -case_id $case_id -action_id $action_id] } { + bug_tracker::security_violation -user_id $user_id -bug_id $bug(bug_id) -action $action_id +} -element create bug bug_number_i \ - -datatype integer \ - -widget inform \ - -label "Bug #" -element create bug component_id \ - -datatype integer \ - -widget [ad_decode [info exists field_editable_p(component_id)] 1 select inform] \ - -label "Component" \ - -options [bug_tracker::components_get_options] +# Buttons +set actions [list] +if { [empty_string_p $action_id] } { + foreach available_action_id [workflow::case::get_available_actions -case_id $case_id] { + workflow::action::get -action_id $available_action_id -array available_action + lappend actions [list " $available_action(pretty_name) " $available_action(action_id)] + } +} -element create bug bug_type \ - -datatype text \ - -widget [ad_decode [info exists field_editable_p(bug_type)] 1 select inform] \ - -label "Type of bug" \ - -options [bug_tracker::bug_type_get_options] \ - -optional -element create bug summary \ - -datatype text \ - -widget [ad_decode [info exists field_editable_p(summary)] 1 text inform] \ - -label "Summary" \ - -html { size 50 } +##### +# +# Create the form +# +##### -element create bug submitter \ - -datatype text \ - -widget inform \ - -label "Submitted by" +# Set the variable that we need for the elements below -element create bug status \ - -widget [ad_decode [info exists field_editable_p(status)] 1 select inform] \ - -datatype text \ - -options [bug_tracker::status_get_options] \ - -label "Status" -element create bug resolution \ - -widget [ad_decode [info exists field_editable_p(resolution)] 1 select inform] \ - -datatype text \ - -label "Resolution" \ - -options [ad_decode $mode resolve [bug_tracker::resolution_get_options] [concat {{"" ""}} [bug_tracker::resolution_get_options]]] \ - -optional +# set patch label +set patch_label [ad_decode $show_patch_status "open" "Open Patches (show all)" "all" "All Patches (show only open)" "Patches"] -element create bug severity \ - -datatype integer \ - -widget [ad_decode [info exists field_editable_p(severity)] 1 select inform] \ - -label "Severity" \ - -options [bug_tracker::severity_codes_get_options] \ - -optional +ad_form -name bug -cancel_url $return_url -mode display -has_edit 1 -actions $actions -form { + {bug_number_display:integer(inform) + {label "[bug_tracker::conn Bug] \#"} + {mode display} + } + {component_id:integer(select) + {label "[bug_tracker::conn Component]"} + {options {[bug_tracker::components_get_options]}} + {mode display} + optional + } + {summary:text(text) + {label "Summary"} + {after_html ""} + {before_html ""} + {mode display} + {html {size 50}} + } +} -element create bug priority \ - -datatype integer \ - -widget [ad_decode [info exists field_editable_p(priority)] 1 select inform] \ - -label "Priority" \ - -options [bug_tracker::priority_codes_get_options] \ - -optional -element create bug found_in_version \ - -datatype text \ - -widget [ad_decode [info exists field_editable_p(found_in_version)] 1 select inform] \ - -label "Found in Version" \ - -options [bug_tracker::version_get_options -include_unknown] \ - -optional +ad_form -extend -name bug -form { + {pretty_state:text(inform) + {label "Status"} + {before_html ""} + {after_html ""} + {mode display} + } + {resolution:text(select) + {label "Resolution"} + {options {[bug_tracker::resolution_get_options]}} + {mode display} + optional + } +} -element create bug patches \ - -datatype text \ - -widget inform \ - -label [ad_decode $show_patch_status "open" "Open Patches (show all)" "all" "All Patches (show only open)" "Patches"] - -if { $user_agent_p } { - element create bug user_agent \ - -datatype text \ - -widget inform \ - -label "User Agent" +foreach {category_id category_name} [bug_tracker::category_types] { + ad_form -extend -name bug -form [list \ + [list "${category_id}:integer(select)" \ + [list label $category_name] \ + [list options [bug_tracker::category_get_options -parent_id $category_id]] \ + [list mode display] \ + ] \ + ] } -element create bug assignee \ - -widget [ad_decode [info exists field_editable_p(assignee)] 1 search inform] \ - -datatype search \ - -result_datatype integer \ - -label {Assigned to} \ - -options [bug_tracker::users_get_options] \ - -optional \ - -search_query { - select distinct u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id - from cc_users u - where upper(coalesce(u.first_names || ' ', '') || coalesce(u.last_name || ' ', '') || u.email || ' ' || coalesce(u.screen_name, '')) like upper('%'||:value||'%') - order by name -} -element create bug fix_for_version \ - -datatype text \ - -widget [ad_decode [info exists field_editable_p(fix_for_version)] 1 select inform] \ - -label "Fix for Version" \ - -options [bug_tracker::version_get_options -include_undecided] \ - -optional +ad_form -extend -name bug -form { + {found_in_version:text(select) + {label "Found in Version"} + {options {[bug_tracker::version_get_options -include_unknown]}} + {mode display} + optional + } +} -element create bug fixed_in_version \ - -datatype text \ - -widget [ad_decode [info exists field_editable_p(fixed_in_version)] 1 select inform] \ - -label "Fixed in Version" \ - -options [bug_tracker::version_get_options -include_undecided] \ - -optional +workflow::case::role::add_assignee_widgets -case_id $case_id -form_name bug -switch -- $mode { - edit - comment - reassign - resolve - reopen - close { - element create bug description \ - -datatype text \ - -widget comment \ - -label "Description" \ - -html { cols 60 rows 13 } \ - -optional - - element create bug desc_format \ - -datatype text \ - -widget select \ - -label "Description format" \ - -options { { "Plain" plain } { "HTML" html } { "Preformatted" pre } } - +# More fixed form elements +ad_form -extend -name bug -form { + {patches:text(inform) + {label $patch_label} + {mode display} } - default { - element create bug description \ - -datatype text \ - -widget inform \ - -label "Description" + {user_agent:text(inform) + {label "User Agent"} + {mode display} } + {fix_for_version:text(select) + {label "Fix for Version"} + {options {[bug_tracker::version_get_options -include_undecided]}} + {mode display} + optional + } + {fixed_in_version:text(select) + {label "Fixed in Version"} + {options {[bug_tracker::version_get_options -include_undecided]}} + {mode display} + optional + } + {description:richtext(richtext) + {label "Description"} + {html {cols 60 rows 13}} + optional + } + {return_url:text(hidden) + {value $return_url} + } + {bug_number:key} + {entry_id:integer(hidden) + optional + } } - -element create bug return_url \ - -datatype text \ - -widget hidden \ - -value $return_url - -element create bug mode \ - -datatype text \ - -widget hidden \ - -value $mode - -foreach name [array names filter] { - element create bug filter.$name -datatype text -widget hidden -value $filter($name) +# Export filters +if { [llength [array names filter]] > 0 } { + set filters [list] + foreach name [array names filter] { + lappend filters [list "filter.${name}:text(hidden)" [list value $filter($name)]] + } + ad_form -extend -name bug -form $filters } -# If nothing else ... -set page_title "Bug #$bug_number" +# Set editable fields +if { ![empty_string_p $action_id] } { + foreach field [workflow::action::get_element -action_id $action_id -element edit_fields] { + element set_properties bug $field -mode edit + } + if {[string compare $action_short_name "edit"] == 0} { + foreach {category_id category_name} [bug_tracker::category_types] { + element set_properties bug $category_id -mode edit + } + } +} + -set show_user_agent_url "bug?[export_vars { bug_number { user_agent_p 1 }}]" -set hide_user_agent_url "bug?[export_vars { bug_number }]" +# on_submit block +ad_form -extend -name bug -on_submit { -if { ![form is_valid bug] } { - db_1row bug { - select b.bug_id, - b.bug_number, - b.summary, - o.creation_user as submitter_user_id, - submitter.first_names as submitter_first_names, - submitter.last_name as submitter_last_name, - submitter.email as submitter_email, - b.component_id, - c.component_name, - o.creation_date, - to_char(o.creation_date, 'fmMM/DDfm/YYYY') as creation_date_pretty, - b.severity, - sc.sort_order || ' - ' || sc.severity_name as severity_pretty, - b.priority, - pc.sort_order || ' - ' || pc.priority_name as priority_pretty, - b.status, - b.resolution, - b.bug_type, - b.user_agent, - b.original_estimate_minutes, - b.latest_estimate_minutes, - b.elapsed_time_minutes, - b.found_in_version, - coalesce((select version_name - from bt_versions found_in_v - where found_in_v.version_id = b.found_in_version), 'Unknown') as found_in_version_name, - b.fix_for_version, - coalesce((select version_name - from bt_versions fix_for_v - where fix_for_v.version_id = b.fix_for_version), 'Undecided') as fix_for_version_name, - b.fixed_in_version, - coalesce((select version_name - from bt_versions fixed_in_v - where fixed_in_v.version_id = b.fixed_in_version), 'Unknown') as fixed_in_version_name, - b.assignee, - asgnu.first_names as assignee_first_names, - asgnu.last_name as assignee_last_name, - asgnu.email as assignee_email, - to_char(now(), 'fmMM/DDfm/YYYY') as now_pretty - from bt_bugs b left outer join - cc_users asgnu on (asgnu.user_id = b.assignee), - acs_objects o, - bt_components c, - bt_priority_codes pc, - bt_severity_codes sc, - cc_users submitter - where b.bug_number = :bug_number - and b.project_id = :package_id - and o.object_id = b.bug_id - and c.component_id = b.component_id - and pc.priority_id = b.priority - and sc.severity_id = b.severity - and submitter.user_id = o.creation_user - } -column_array bug - - switch -- $mode { - resolve { - set bug(status) "resolved" - } - reopen { - set bug(status) "open" + array set row [list] + + if { ![empty_string_p $action_id] } { + foreach field [workflow::action::get_element -action_id $action_id -element edit_fields] { + set row($field) [element get_value bug $field] } - close { - set bug(status) "closed" + foreach {category_id category_name} [bug_tracker::category_types] { + set row($category_id) [element get_value bug $category_id] } } - set pretty(bug_number) "#$bug(bug_number)" - set pretty(component_id) $bug(component_name) - set pretty(bug_type) [bug_tracker::bug_type_pretty $bug(bug_type)] - set pretty(summary) "$bug(summary)" - set pretty(submitter) "[acs_community_member_link -user_id $bug(submitter_user_id) \ - -label "$bug(submitter_first_names) $bug(submitter_last_name)" \ - ] ($bug(submitter_email))" - set pretty(status) [bug_tracker::status_pretty $bug(status)] - set pretty(resolution) [bug_tracker::resolution_pretty $bug(resolution)] - set pretty(severity) $bug(severity_pretty) - set pretty(priority) $bug(priority_pretty) - set pretty(found_in_version) $bug(found_in_version_name) - set pretty(patches) "[bug_tracker::get_patch_links -bug_id $bug(bug_id) -show_patch_status $show_patch_status]   \[ Upload a patch \]" - set pretty(user_agent) $bug(user_agent) - set pretty(fix_for_version) $bug(fix_for_version_name) - set pretty(fixed_in_version) $bug(fixed_in_version_name) - set pretty(assignee) [ad_decode $bug(assignee) "" "Unassigned" " - [acs_community_member_link -user_id $bug(assignee) \ - -label "$bug(assignee_first_names) $bug(assignee_last_name)"] - ($bug(assignee_email))"] + set description [element get_value bug description] + + bug_tracker::bug::edit \ + -bug_id $bug(bug_id) \ + -action_id $action_id \ + -description [template::util::richtext::get_property contents $description] \ + -desc_format [template::util::richtext::get_property format $description] \ + -array row \ + -entry_id [element get_value bug entry_id] - element set_properties bug bug_number -value $bug(bug_number) + ad_returnredirect $return_url + ad_script_abort - # Description/Actions/History +} -edit_request { + # Dummy + # If we don't have this, ad_form complains + # Unfortunately, ad_form doesn't let us do what we want, namely have a block that executes + # whenever the form is displayed, whether initially or because of a validation error. +} - set bug_id $bug(bug_id) +# Not-valid block (request, error) +if { ![form is_valid bug] } { - set action_html "" + # Get the bug data + bug_tracker::bug::get -bug_id $bug(bug_id) -array bug -action_id $action_id - db_foreach actions { - select ba.action_id, - ba.action, - ba.resolution, - ba.actor as actor_user_id, - actor.first_names as actor_first_names, - actor.last_name as actor_last_name, - actor.email as actor_email, - ba.action_date, - to_char(ba.action_date, 'fmMM/DDfm/YYYY') as action_date_pretty, - ba.comment, - ba.comment_format - from bt_bug_actions ba, - cc_users actor - where ba.bug_id = :bug_id - and actor.user_id = ba.actor - order by action_date - } { - append action_html "$action_date_pretty [bug_tracker::bug_action_pretty $action $resolution] by $actor_first_names $actor_last_name -

[bug_tracker::bug_convert_comment_to_html -comment $comment -format $comment_format]
" + + # Make list of form fields + set element_names { + bug_number component_id summary pretty_state resolution + found_in_version user_agent fix_for_version fixed_in_version + bug_number_display entry_id } - if { [string equal $mode "view"] } { - element set_properties bug description -value $action_html - } else { - element set_properties bug description \ - -history $action_html \ - -header "$bug(now_pretty) [bug_tracker::bug_action_pretty $mode] by [bug_tracker::conn user_first_names] [bug_tracker::conn user_last_name]" \ - -value "" + # update the element_name list and bug array with category stuff + foreach {category_id category_name} [bug_tracker::category_types] { + lappend element_names $category_id + set bug($category_id) [cr::keyword::item_get_assigned -item_id $bug(bug_id) -parent_id $category_id] + if {[string compare $bug($category_id) ""] == 0} { + set bug($category_id) [bug_tracker::get_default_keyword -parent_id $category_id] + } } + + # Display value for patches + set bug(patches_display) "[bug_tracker::get_patch_links -bug_id $bug(bug_id) -show_patch_status $show_patch_status]   \[ Upload a patch \]" - set page_title "Bug #$bug_number: $bug(summary)" + # Hide elements that should be hidden depending on the bug status + foreach element $bug(hide_fields) { + element set_properties bug $element -widget hidden + } -} + if { !$versions_p } { + foreach element { found_in_version fix_for_version fixed_in_version } { + if { [info exists bug:$element] } { + element set_properties bug $element -widget hidden + } + } + } -if { [form is_request bug] } { - # If the user has submitted the bug he gets full write access on the bug - set write_p [expr $write_p || ($bug(submitter_user_id) == [ad_conn user_id])] - if { !$write_p && [info exists bug(assignee)] && $bug(assignee) == [ad_conn user_id] } { - set write_p 1 + if { !$patches_p } { + foreach element { patches } { + if { [info exists bug:$element] } { + element set_properties bug $element -widget hidden + } + } } - if { [string equal $mode "view"] } { - set button_form_export_vars [export_vars -form { bug_number filter:array }] - multirow create button name label + # Optionally hide user agent + if { !$user_agent_p } { + element set_properties bug user_agent -widget hidden + } - multirow append button "comment" "Comment" - if { $write_p } { - multirow append button "edit" "Edit" + # Set regular element values + foreach element $element_names { - switch -- $bug(status) { - open { - multirow append button "reassign" "Reassign" - multirow append button "resolve" "Resolve" - } - resolved { - multirow append button "resolve" "Resolve" - multirow append button "reopen" "Reopen" - multirow append button "close" "Close" - } - closed { - multirow append button "reopen" "Reopen" - } + # check that the element exists + if { [info exists bug:$element] && [info exists bug($element)] } { + if { [form is_request bug] || [string equal [element get_property bug $element mode] "display"] } { + element set_value bug $element $bug($element) } } } - if { ![string equal $mode "view"] && ![string equal $mode "comment"] && !$write_p } { - ns_log notice "[ad_conn user_id] doesn't have write on object $bug(bug_id)" - ad_return_forbidden "Security Violation" "
- You don't have permission to edit this bug. -
- This incident has been logged. -
" - ad_script_abort + # Add empty option to resolution code + if { ![empty_string_p $action_id] } { + if { [lsearch [workflow::action::get_element -action_id $action_id -element edit_fields] "resolution"] == -1 } { + element set_properties bug resolution -options [concat {{{} {}}} [element get_property bug resolution options]] + } + } else { + element set_properties bug resolution -widget hidden } -} -if { ![form is_valid bug] } { - # set the values of all the inform widgets - - element set_properties bug bug_number_i -value $pretty(bug_number) + # Get values for the role assignment widgets + workflow::case::role::set_assignee_values -case_id $case_id -form_name bug + # Set values for elements with separate display value foreach element { - component_id bug_type summary submitter status resolution severity - priority found_in_version patches user_agent fix_for_version fixed_in_version assignee + patches } { # check that the element exists if { [info exists bug:$element] } { - if { [info exists field_editable_p($element)] } { - if { [form is_request bug] } { - element set_value bug $element $bug($element) - } - } else { - element set_value bug $element $pretty($element) - } + element set_properties bug $element -display_value $bug(${element}_display) } - } - - if { [string equal $bug(status) "open"] && ![string equal $mode "resolve"] || [string equal $mode "reopen"] } { - element set_properties bug resolution -widget hidden - element set_properties bug fixed_in_version -widget hidden } -} + # Set values for description field + element set_properties bug description \ + -before_html "[workflow::case::get_activity_html -case_id $case_id][ad_decode $action_id "" "" "

$bug(now_pretty) [bug_tracker::bug_action_pretty $action_short_name] by [bug_tracker::conn user_first_names] [bug_tracker::conn user_last_name]

"]" + # Set page title + set page_title "[bug_tracker::conn Bug] #$bug_number: $bug(summary)" - -# Notifications for a project. Provide a link for logged in users in view mode -if { [string equal $mode "view"] } { - set notification_link [bug_tracker::get_notification_link \ - -type bug_tracker_project_notif \ - -object_id $bug(bug_id) \ - -url $return_url \ - -pretty_name "bug"] -} else { - set notification_link "" -} - - -if { [info exists filter] } { - if { [array names filter] == [list "actionby"] && $filter(actionby) == [ad_conn user_id] } { - set context_bar [bug_tracker::context_bar [list ".?[export_vars { filter:array }]" "My bugs"] $page_title] + # Context bar + if { [info exists filter] } { + if { [array names filter] == [list "actionby"] && $filter(actionby) == $user_id } { + set context_bar [bug_tracker::context_bar [list ".?[export_vars { filter:array }]" "My bugs"] $page_title] + } else { + set context_bar [bug_tracker::context_bar [list ".?[export_vars { filter:array }]" "Filtered bug list"] $page_title] + } } else { - set context_bar [bug_tracker::context_bar [list ".?[export_vars { filter:array }]" "Filtered bug list"] $page_title] + set context_bar [bug_tracker::context_bar $page_title] } -} else { - set context_bar [bug_tracker::context_bar $page_title] -} + + # User agent show/hide URLs + set show_user_agent_url "bug?[export_vars { bug_number { user_agent_p 1 }}]" + set hide_user_agent_url "bug?[export_vars { bug_number }]" + + # Login + set login_url "/register/?[export_vars { return_url }]" + + # Single-bug notifications + if { [empty_string_p $action_id] } { + set notification_link [bug_tracker::bug::get_watch_link -bug_id $bug(bug_id)] + } -if { [form is_valid bug] } { - # Find out whether the user has permission to modify - - if { !$write_p } { - # No write permission, is this the submitter? - db_1row submitter { - select o.creation_user as submitter_user_id, - b.bug_id, - b.assignee - from bt_bugs b, - acs_objects o - where o.object_id = b.bug_id - and b.bug_number = :bug_number - and b.project_id = :package_id - } -column_array bug + # Filter management + set filter_parsed [bug_tracker::parse_filters filter] - # If the user has submitted the bug he gets full write access on the bug - if { [info exists bug(submitter_user_id)] && ($bug(submitter_user_id) == [ad_conn user_id]) } { - set write_p 1 - } + if { [empty_string_p $action_id] } { + + set human_readable_filter [bug_tracker::conn filter_human_readable] + set where_clauses [bug_tracker::conn filter_where_clauses] + set from_bug_clause [bug_tracker::conn filter_from_bug_clause] + set order_by_clause [bug_tracker::conn filter_order_by_clause] - if { [info exists bug(assignee)] && ($bug(assignee) == [ad_conn user_id]) } { - set write_p 1 - } - } + lappend where_clauses "b.project_id = :package_id" - if { !$write_p && ![string equal $mode "comment"] } { - ns_log notice "$bug(submitter_user_id) doesn't have write on object $bug(bug_id)" - ad_return_forbidden \ - "Security Violation" \ - "
- You don't have permission to edit this bug. -
- This incident has been logged. -
" - ad_script_abort - } + set workflow_id [bug_tracker::bug::get_instance_workflow_id] + set initial_state [workflow::fsm::get_initial_state -workflow_id $workflow_id] - set update_exprs [list] - - foreach column $edit_fields { - set $column [element get_value bug $column] - lappend update_exprs "$column = :$column" - } - - switch -- $mode { - resolve { - set status "resolved" - lappend update_exprs "status = :status" + set action_role [db_string select_resolve_role {}] + + set filter_bug_numbers [db_list filter_bug_numbers {}] + + set filter_bug_index [lsearch -exact $filter_bug_numbers $bug_number] + + multirow create navlinks url label + + if { $filter_bug_index != -1 } { + + if { $filter_bug_index > 0 } { + multirow append navlinks "bug?[export_vars { { bug_number {[lindex $filter_bug_numbers [expr $filter_bug_index -1]]} } filter:array }]" "<" + } else { + multirow append navlinks "" "<" + } + + multirow append navlinks "" "[expr $filter_bug_index+1] of [llength $filter_bug_numbers]" + + if { $filter_bug_index < [expr [llength $filter_bug_numbers]-1] } { + multirow append navlinks "bug?[export_vars { { bug_number {[lindex $filter_bug_numbers [expr $filter_bug_index +1]]} } filter:array }]" ">" + } else { + multirow append navlinks "" ">" + } } - reopen { - set status "open" - lappend update_exprs "status = :status" - } - close { - set status "closed" - lappend update_exprs "status = :status" - } - } - - if { ![info exists resolution] || ![string equal $mode "resolve"] } { - set resolution {} - } - - db_transaction { - set bug_id [bug_tracker::get_bug_id -bug_number $bug_number -project_id $package_id] - - if { [llength $update_exprs] > 0 } { - db_dml update_bug "update bt_bugs \n set [join $update_exprs ",\n "] \n where bug_id = :bug_id" - } - - set action_id [db_nextval "acs_object_id_seq"] - set user_id [ad_conn user_id] - - foreach column { description desc_format } { - set $column [element get_value bug $column] - } - - db_dml bug_action { - insert into bt_bug_actions - (action_id, bug_id, action, resolution, actor, comment, comment_format) - values - (:action_id, :bug_id, :mode, :resolution, :user_id, :description, :desc_format) - } - - # Setup any assignee for alerts on the bug - if { [info exists assignee] && ![empty_string_p $assignee] } { - bug_tracker::add_instant_alert -bug_id $bug_id -user_id $assignee - } - } - - bug_tracker::bug_notify -bug_id $bug_id \ - -action $mode \ - -comment $description \ - -comment_format $desc_format \ - -resolution $resolution - - ad_returnredirect $return_url - ad_script_abort + } } ad_return_template Index: openacs-4/packages/bug-tracker/www/index.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/index.adp,v diff -u -r1.2 -r1.2.2.1 --- openacs-4/packages/bug-tracker/www/index.adp 11 Sep 2002 14:03:25 -0000 1.2 +++ openacs-4/packages/bug-tracker/www/index.adp 5 Mar 2003 18:13:52 -0000 1.2.2.1 @@ -1,63 +1,60 @@ @project_name@ @context_bar@ -@notification_link@ - -
-
- - @by_status.num_bugs@ @by_status.name@
-
-

Open bugs summary:

-
+ - - - - - - - - - - -
- @stats.stat_name@ -
- @stats.name@ - - @stats.num_bugs@ -
-

- -

  - - - - - - - - - @displaymode_form_export_vars@ - - + + - - - - - + + + Opened in the last: [ + + | + @options_n_days.label@ + @options_n_days.label@ + + ] days + + + + + + + - - - + + + +

- - - + No @pretty_names.bugs@ match these criteria. -
- + +

@stats.header@

+
+ +

+

- + + + + + + + + + + +
- Showing: @human_readable_filter@ - (none1 bug@bugs:rowcount@ bugs) - (clear filters) + + @stats.stat_name@
+ @stats.name@ + + @stats.num_bugs@ +
-
-
-
+

+ + + +
  + +
+ Showing: @human_readable_filter@ + (none1 bug@bugs_count@ @pretty_names.bug@@pretty_names.bugs@) + (show default listing) +
+ + + @displaymode_form_export_vars@ + +
+ +
+ Order by: -
-
-
- - #@bugs.bug_number@. @bugs.summary@
- - @bugs.description_short@
- Component: @bugs.component_name@ - - Opened @bugs.creation_date_pretty@ - By @bugs.submitter_first_names@ @bugs.submitter_last_name@
- Priority: @bugs.priority_pretty@ - - Severity: @bugs.severity_pretty@ - - Type: @bugs.bug_type_pretty@ -
- Assigned to: - - @bugs.assignee_first_names@ @bugs.assignee_last_name@ +

+ + + #@bugs.bug_number@. + @bugs.summary@
+
+ + @bugs.comment_short@
+ @pretty_names.Component@: @bugs.component_name@ + - Opened @bugs.creation_date_pretty@ + By @bugs.submitter_first_names@ @bugs.submitter_last_name@
+ + + @bugs.category_name@: @bugs.category_value@ + - + +
+
+ Assigned to: + + @bugs.assignee_name@ + + + Unassigned + +
+ + Status: + @bugs.pretty_state@ + + (fix for version @bugs.fix_for_version_name@) + + + - @bugs.resolution_pretty@ + + in version @bugs.fixed_in_version_name@ - - Unassigned - -
- Status: - @bugs.status_pretty@ - - - (fix for version @bugs.fix_for_version_name@) - - - - - @bugs.resolution_pretty@ - - in version @bugs.fixed_in_version_name@ - - - - Est: @bugs.latest_estimate_minutes@
- -
-

-

 

- No bugs match these criteria. -

+
Index: openacs-4/packages/bug-tracker/www/index.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/index.tcl,v diff -u -r1.11.2.2 -r1.11.2.3 --- openacs-4/packages/bug-tracker/www/index.tcl 21 Feb 2003 14:01:10 -0000 1.11.2.2 +++ openacs-4/packages/bug-tracker/www/index.tcl 5 Mar 2003 18:13:52 -0000 1.11.2.3 @@ -5,7 +5,7 @@ @creation-date 2002-03-20 @cvs-id $Id$ } { - filter:optional,array + filter:optional,array,multiple } ad_require_permission [ad_conn package_id] read @@ -14,11 +14,18 @@ set package_id [ad_conn package_id] set package_key [ad_conn package_key] +bug_tracker::get_pretty_names -array pretty_names + +set project_root_keyword_id [bug_tracker::conn project_root_keyword_id] + +# Is this project using multiple versions? +set versions_p [bug_tracker::versions_p] + if { [info exists filter] } { if { [array names filter] == [list "actionby"] && $filter(actionby) == [ad_conn user_id] } { - set context_bar [bug_tracker::context_bar "My bugs"] + set context_bar [bug_tracker::context_bar "My [bug_tracker::conn bugs]"] } else { - set context_bar [bug_tracker::context_bar "Filtered bug list"] + set context_bar [bug_tracker::context_bar "Filtered [bug_tracker::conn bug] list"] } } else { set context_bar [bug_tracker::context_bar] @@ -28,48 +35,43 @@ set return_url "[ad_conn url][ad_decode [ad_conn query] "" "" "?[ad_conn query]"]" -set num_components [db_string num_components { select count(component_id) from bt_components where project_id = :package_id }] +set num_components [db_string num_components {}] if { $num_components == 0 } { ad_return_template "no-components" return } -set num_bugs [db_string num_bugs { select count(bug_id) from bt_bugs where project_id = :package_id }] - -set user_id [ad_conn user_id] - -# Notifications for a project. Provide a link for logged in users -set notification_link [bug_tracker::get_notification_link \ - -type bug_tracker_project_notif \ - -object_id $package_id \ - -url $return_url \ - -pretty_name "project"] - -if { $num_bugs == 0 } { +if { ![bug_tracker::bugs_exist_p] } { ad_return_template "no-bugs" return } + +##### # # Filter management # +##### set filter_parsed [bug_tracker::parse_filters filter] set human_readable_filter [bug_tracker::conn filter_human_readable] set where_clauses [bug_tracker::conn filter_where_clauses] +set from_bug_clause [bug_tracker::conn filter_from_bug_clause] set order_by_clause [bug_tracker::conn filter_order_by_clause] lappend where_clauses "b.project_id = :package_id" -if { [llength [array names filter]] > 0 } { +if { [llength [array names filter]] > 0 && [array names filter] != "orderby" } { set clear_url [ad_conn package_url] } +##### # # Order by # +##### if { [info exists filter(orderby)] } { set save_orderby $filter(orderby) @@ -82,223 +84,176 @@ } multirow create orderby value label selected_p -foreach value { "" severity priority } label { "Bug number" "Severity" "Priority" } { - if { [info exists filter(orderby)] && [string equal $filter(orderby) $value] } { - set selected_p 1 - } else { - set selected_p 0 - } - multirow append orderby $value $label $selected_p + +multirow append orderby {} "[bug_tracker::conn Bug] number" [exists_and_equal filter(orderby) {}] + + +foreach { category_type_id label } [bug_tracker::category_types] { + multirow append orderby \ + $category_type_id \ + $label \ + [exists_and_equal filter(orderby) $category_type_id] } + +##### # +# Last n days filter +# +##### + +multirow create options_n_days url label selected_p + +foreach n_days { 1 3 7 30 90 365 all } { + multirow append options_n_days ".?[bug_tracker::filter_url_vars -array filter -override [list n_days $n_days]]" $n_days [exists_and_equal filter_n_days $n_days] + +} + + +##### +# # Get bug list # +##### set truncate_len [ad_parameter "TruncateDescriptionLength" -default 200] -db_multirow -extend { description_short submitter_url status_pretty resolution_pretty bug_type_pretty original_esimate_pretty latest_estimate_pretty elapsed_time_pretty assignee_url bug_url } bugs bugs " - select b.bug_id, - b.bug_number, - b.summary, - bact.comment as description, - bact.comment_format as desc_format, - b.component_id, - c.component_name, - o.creation_date, - to_char(o.creation_date, 'fmMM/DDfm/YYYY') as creation_date_pretty, - o.creation_user as submitter_user_id, - submitter.first_names as submitter_first_names, - submitter.last_name as submitter_last_name, - submitter.email as submitter_email, - pc.sort_order || ' - ' || pc.priority_name as priority_pretty, - sc.sort_order || ' - ' || sc.severity_name as severity_pretty, - b.status, - b.resolution, - b.bug_type, - b.original_estimate_minutes, - b.latest_estimate_minutes, - b.elapsed_time_minutes, - b.found_in_version, - coalesce((select version_name - from bt_versions found_in_v - where found_in_v.version_id = b.found_in_version), 'Unknown') as found_in_version_name, - b.fix_for_version, - coalesce((select version_name - from bt_versions fix_for_v - where fix_for_v.version_id = b.fix_for_version), 'Undecided') as fix_for_version_name, - b.fixed_in_version, - coalesce((select version_name - from bt_versions fixed_in_v - where fixed_in_v.version_id = b.fixed_in_version), 'Unknown') as fixed_in_version_name, - b.assignee as assignee_user_id, - assignee.first_names as assignee_first_names, - assignee.last_name as assignee_last_name, - assignee.email as assignee_email - from bt_bugs b left outer join - cc_users assignee on (assignee.user_id = b.assignee), - bt_bug_actions bact, - bt_components c, - acs_objects o, - bt_priority_codes pc, - bt_severity_codes sc, - cc_users submitter - where c.component_id = b.component_id - and bact.bug_id = b.bug_id - and bact.action = 'open' - and o.object_id = b.bug_id - and pc.priority_id = b.priority - and sc.severity_id = b.severity - and submitter.user_id = o.creation_user - and [join $where_clauses " and "] - order by $order_by_clause -" { - set description_short [string_truncate -len $truncate_len -format $desc_format -- $description] +set workflow_id [bug_tracker::bug::get_instance_workflow_id] +set initial_state_id [workflow::fsm::get_initial_state -workflow_id $workflow_id] + +# Role will be assignee or submitter +set action_role [db_string select_resolve_role {}] + +set initial_action_id [workflow::get_element -workflow_id $workflow_id -element initial_action_id] + +set bugs_count 0 +set last_bug_id {} + +db_multirow -extend { + comment_short + submitter_url + status_pretty + resolution_pretty + assignee_url + bug_url + component_name + found_in_version_name + fix_for_version_name + fixed_in_version_name + category_name + category_value +} bugs bugs {} { + + if { ![string equal $bug_id $last_bug_id] } { + incr bugs_count + set last_bug_id $bug_id + } + + set component_name [bug_tracker::component_get_name -component_id $component_id] + set found_in_version_name [bug_tracker::version_get_name -version_id $found_in_version] + set fix_for_version_name [bug_tracker::version_get_name -version_id $fix_for_version] + set fixed_in_version_name [bug_tracker::version_get_name -version_id $fixed_in_version] + set comment_short [string_truncate -len $truncate_len -format $comment_format $comment_content] set summary [ad_quotehtml $summary] set submitter_url [acs_community_member_url -user_id $submitter_user_id] - set status_pretty [bug_tracker::status_pretty $status] set resolution_pretty [bug_tracker::resolution_pretty $resolution] - set bug_type_pretty [bug_tracker::bug_type_pretty $bug_type] - set original_estimate_pretty [ad_decode $original_estimate_minutes "" "" 0 "" "$original_estimate_minutes minutes"] - set latest_estimate_pretty [ad_decode $latest_estimate_minutes "" "" 0 "" "$latest_estimate_minutes minutes"] - set elapsed_time_pretty [ad_decode $elapsed_time_minutes "" "" 0 "" "$elapsed_time_minutes minutes"] - set assignee_url [acs_community_member_url -user_id $assignee_user_id] + set assignee_url {} + if { ![empty_string_p $assignee_party_id] } { + set assignee_url [acs_community_member_url -user_id $assignee_party_id] + } set bug_url "bug?[export_vars { bug_number filter:array }]" + set category_name [bug_tracker::category_parent_heading -keyword_id $keyword_id] + set category_value [bug_tracker::category_heading -keyword_id $keyword_id] + + # Hide fields in this state + foreach element $hide_fields { + set $element {} + } } + +##### # # Get stats # +##### -db_multirow -extend { name name_url } by_status by_status { - select b.status as unique_id, - count(b.bug_id) as num_bugs - from bt_bugs b - where b.project_id = :package_id - group by unique_id - order by bt_bug__status_sort_order(b.status) -} { - set name "[bug_tracker::status_pretty $unique_id] Bugs" - set name_url "?[export_vars { { filter.status $unique_id } }]" -} +# Stat: Status -db_multirow -extend { name name_url stat_name } stats stats_by_bug_type { - select b.bug_type as unique_id, - count(b.bug_id) as num_bugs - from bt_bugs b - where b.project_id = :package_id - and b.status = 'open' - group by unique_id - order by bt_bug__bug_type_sort_order(b.bug_type) -} { - set stat_name "Type of bug" - set name [bug_tracker::bug_type_pretty $unique_id] - set name_url "?[export_vars { { filter.bug_type $unique_id } }]" +db_multirow -extend { name_url stat_name header selected_p } stats by_status {} { + set header "All [bug_tracker::conn bugs] by status:" + set stat_name "Status" + set name_url "?[bug_tracker::filter_url_vars -array filter -override [list status $unique_id]]" + set selected_p [expr { [info exists filter(status)] && [string equal $filter(status) $unique_id] }] } -db_multirow -extend { name_url stat_name } -append stats stats_by_fix_for_version { - select b.fix_for_version as unique_id, - v.version_name as name, - count(b.bug_id) as num_bugs - from bt_bugs b left outer join - bt_versions v on (v.version_id = b.fix_for_version) - where b.project_id = :package_id - and b.status = 'open' - group by unique_id, v.anticipated_freeze_date, name - order by v.anticipated_freeze_date, name -} { - set stat_name "Fix For" - if { [empty_string_p $unique_id] } { - set name "Undecided" +set open_bugs_header "Open [bug_tracker::conn bugs] summary:" + +# Stat: By Category + +foreach { parent_id parent_heading } [bug_tracker::category_types] { + db_multirow -extend { header selected_p stat_name name name_url } -append stats stats_by_category {} { + set header $open_bugs_header + set stat_name "By $parent_heading" + set name [bug_tracker::category_heading -keyword_id $unique_id] + set name_url "?[bug_tracker::filter_url_vars -array filter -override [list keyword $unique_id]]" + set selected_p [expr { [info exists filter(keyword)] && [lsearch -exact $filter(keyword) $unique_id] != -1 }] } - set name_url "?[export_vars { { filter.fix_for_version $unique_id } }]" } -set stat_name_val "Severity" +# Stat: Fix for version -db_multirow -extend { name_url stat_name } -append stats stats_by_severity { - select b.severity as unique_id, - p.sort_order || ' - ' || p.severity_name as name, - count(b.bug_id) as num_bugs - from bt_bugs b left join - bt_severity_codes p on (p.severity_id = b.severity) - where b.project_id = :package_id - and b.status = 'open' - group by unique_id, name - order by name -} { - set stat_name $stat_name_val - set name_url "?[export_vars { { filter.severity $unique_id } }]" +if { $versions_p } { + db_multirow -extend { name_url stat_name header selected_p } -append stats stats_by_fix_for_version {} { + set header $open_bugs_header + set stat_name "Fix For" + if { [empty_string_p $unique_id] } { + set name "Undecided" + } + set name_url "?[bug_tracker::filter_url_vars -array filter -override [list fix_for_version $unique_id]]" + set selected_p [expr { [info exists filter(fix_for_version)] && [string equal $filter(fix_for_version) $unique_id] }] + } } -set stat_name_val "Priority" -db_multirow -extend { name_url stat_name } -append stats stats_by_priority { - select b.priority as unique_id, - p.sort_order || ' - ' || p.priority_name as name, - count(b.bug_id) as num_bugs - from bt_bugs b left join - bt_priority_codes p on (p.priority_id = b.priority) - where b.project_id = :package_id - and b.status = 'open' - group by unique_id, name - order by name -} { - set stat_name $stat_name_val - set name_url "?[export_vars { { filter.priority $unique_id } }]" -} +# Stat: Assigned action -db_multirow -extend { name_url stat_name } -append stats stats_by_assignee { - select b.assignee as unique_id, - assignee.first_names || ' ' || assignee.last_name as name, - count(b.bug_id) as num_bugs - from bt_bugs b left outer join - cc_users assignee on (assignee.user_id = b.assignee) - where b.project_id = :package_id - and b.status = 'open' - group by unique_id, name - order by name -} { - set stat_name "Assigned To" - if { [empty_string_p $unique_id] } { - set name "Unassigned" - } - set name_url "?[export_vars -url { { filter.assignee $unique_id } }]" +db_multirow -extend { name_url header selected_p } -append stats stats_by_assigned_action {} { + set header $open_bugs_header + + regexp {^([0-9]+)\.([0-9]+)\.([0-9]+)$} $unique_id match action_id state_id assignee_id + + set name_url "?[bug_tracker::filter_url_vars -array filter -override [list assignee $assignee_id status $state_id]]" + set selected_p [expr { [exists_and_equal filter(assignee) $assignee_id] && \ + [exists_and_equal filter(status) $state_id] } ] } -db_multirow -extend { name_url stat_name } -append stats stats_by_actionby { - select o.creation_user as unique_id, - submitter.first_names || ' ' || submitter.last_name as name, - count(b.bug_id) as num_bugs - from bt_bugs b join - acs_objects o on (object_id = bug_id) join - cc_users submitter on (submitter.user_id = o.creation_user) - where b.project_id = :package_id - and b.status = 'resolved' - group by unique_id, name - order by name -} { - set stat_name "To Be Verified By" - set name_url "?[export_vars -url { { filter.status resolved } { filter.actionby $unique_id } }]" +# Stat: Unassigned action + +db_multirow -extend { unique_id name stat_name name_url header selected_p } -append stats stats_by_unassigned_action {} { + set header $open_bugs_header + + set name "Unassigned" + set stat_name "Resolve" + + set unique_id "." + set action_id "" + set assignee_id "" + + set name_url "?[bug_tracker::filter_url_vars -array filter -override [list assignee $assignee_id status $initial_state_id]]" + set selected_p [expr { [exists_and_equal filter(assignee) $assignee_id] && \ + [exists_and_equal filter(status) $initial_state_id] } ] } -db_multirow -extend { name_url stat_name } -append stats stats_by_component { - select coalesce('com/'||c.url_name||'/', trim(to_char(c.component_id,'99999999'))) as unique_id, - c.component_name as name, - count(b.bug_id) as num_bugs - from bt_bugs b left join - bt_components c on (c.component_id = b.component_id) - where b.project_id = :package_id - and b.status = 'open' - group by unique_id, name - order by name -} { - set stat_name "Components" +# Stat: By Component + +db_multirow -extend { name_url stat_name header selected_p } -append stats stats_by_component {} { + set header $open_bugs_header + set stat_name "[bug_tracker::conn Components]" if { [string match "com/*" $unique_id] } { set name_url "[ad_conn package_url]$unique_id" } else { - set name_url "[ad_conn package_url]?[export_vars -url { { filter.component_id $unique_id } }]" + set name_url "[ad_conn package_url]?[bug_tracker::filter_url_vars -array filter -override [list component_id $unique_id]]" } + set selected_p [expr { [exists_and_equal filter(component_id) $unique_id] || [string equal [ad_conn extra_url] $unique_id] }] } - -ad_return_template Index: openacs-4/packages/bug-tracker/www/map-patch-to-bugs.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/map-patch-to-bugs.adp,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/bug-tracker/www/map-patch-to-bugs.adp 11 Sep 2002 14:03:25 -0000 1.1 +++ openacs-4/packages/bug-tracker/www/map-patch-to-bugs.adp 5 Mar 2003 18:13:52 -0000 1.1.2.1 @@ -3,7 +3,7 @@ @context_bar@ -Select one or more of the following bugs for patch "@patch_summary@" (you may select more bugs later): +Select one or more of the following @pretty_names.bugs@ for patch "@patch_summary@" (you may select more @pretty_names.bugs@ later):

@@ -15,7 +15,7 @@

- +

@@ -43,7 +43,7 @@ - There are no open bugs to map the patch to. Try changing the component filter above. + There are no open @pretty_names.bugs@ to map the patch to. Try changing the component filter above.

@@ -54,7 +54,7 @@

-     +    

Index: openacs-4/packages/bug-tracker/www/map-patch-to-bugs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/map-patch-to-bugs.tcl,v diff -u -r1.2 -r1.2.2.1 --- openacs-4/packages/bug-tracker/www/map-patch-to-bugs.tcl 13 Sep 2002 10:43:58 -0000 1.2 +++ openacs-4/packages/bug-tracker/www/map-patch-to-bugs.tcl 5 Mar 2003 18:13:52 -0000 1.2.2.1 @@ -20,6 +20,8 @@ set user_id [ad_conn user_id] set redirect_url [ad_decode $return_url "" "patch?patch_number=$patch_number" $return_url] +bug_tracker::get_pretty_names -array pretty_names + if { [exists_and_not_null cancel] } { # The user chose to abort the mapping so redirect without further processing ad_returnredirect $redirect_url @@ -38,8 +40,8 @@ if { [exists_and_not_null bug_number] } { # Do the mapping foreach one_bug_number $bug_number { - set bug_id [db_string get_bug_id_for_number "select bug_id from bt_bugs where bug_number = :one_bug_number and project_id = :package_id"] - set patch_id [db_string get_patch_id_for_number "select patch_id from bt_patches where patch_number = :patch_number and project_id = :package_id"] + set bug_id [db_string get_bug_id_for_number {}] + set patch_id [db_string get_patch_id_for_number {}] bug_tracker::map_patch_to_bug -patch_id $patch_id -bug_id $bug_id } @@ -48,18 +50,18 @@ ad_script_abort } -set patch_summary [db_string get_patch_summary "select summary from bt_patches where patch_number = :patch_number and project_id = :package_id"] +set patch_summary [db_string get_patch_summary {}] set page_title "Mapping Patch #$patch_number \"$patch_summary\" to a Bug" set context_bar [ad_context_bar "$page_title"] # Build the component filter if { ![exists_and_not_null component_id] } { - set component_id [db_string component_id_for_patch "select component_id from bt_patches where patch_number = :patch_number and project_id = :package_id"] + set component_id [db_string component_id_for_patch {}] } set component_where_clause "" set component_filter "" if { ![empty_string_p $component_id] } { - set component_name [db_string component_name "select component_name from bt_components where component_id = :component_id"] + set component_name [bug_tracker::component_get_name -component_id $component_id] set component_filter_url "map-patch-to-bugs?[export_vars -url {patch_number component_id return_url offset show_only_open_p interval_size}]" if { $show_all_components_p } { set component_filter "\[ Only Component \"$component_name\" | All Components \]" @@ -71,18 +73,23 @@ } # Build the bug status filter +set workflow_id [bug_tracker::bug::get_instance_workflow_id] +set initial_state_id [workflow::fsm::get_initial_state -workflow_id $workflow_id] + set open_filter_url "map-patch-to-bugs?[export_vars -url {patch_number component_id return_url offset show_all_components_p interval_size}]" set only_open_label "Only Open Bugs" set any_status_label "Bugs of any Status" if { $show_only_open_p } { - set open_where_clause "and bt_bugs.status = 'open'" + set open_where_clause "and cfsm.current_state = :initial_state_id" set open_filter "$only_open_label | $any_status_label" } else { set open_where_clause "" set open_filter "$only_open_label | $any_status_label" } set sql_where_clause "bt_bugs.project_id = :package_id + and bt_bugs.bug_id = cas.object_id + and cas.case_id = cfsm.case_id $open_where_clause $component_where_clause and bt_bugs.bug_id not in (select bug_id @@ -95,20 +102,9 @@ )" # Build the pagination filter -set bug_count [db_string bug_count_for_mapping \ - "select count(*) - from bt_bugs - where $sql_where_clause"] +set bug_count [db_string bug_count_for_mapping {}] set pagination_export_var_set [ad_tcl_vars_to_ns_set patch_number component_id return_url show_all_components_p show_only_open_p] -db_multirow open_bugs select_open_bugs \ - "select bt_bugs.bug_number, - bt_bugs.summary, - to_char(acs_objects.creation_date, 'fmMM/DDfm/YYYY') as creation_date_pretty - from bt_bugs, acs_objects - where bt_bugs.bug_id = acs_objects.object_id - and $sql_where_clause - order by acs_objects.creation_date desc - limit $interval_size offset $offset" +db_multirow open_bugs select_open_bugs {} ad_return_template Index: openacs-4/packages/bug-tracker/www/no-bugs.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/no-bugs.adp,v diff -u -r1.1.2.1 -r1.1.2.2 --- openacs-4/packages/bug-tracker/www/no-bugs.adp 4 Dec 2002 20:27:59 -0000 1.1.2.1 +++ openacs-4/packages/bug-tracker/www/no-bugs.adp 5 Mar 2003 18:13:52 -0000 1.1.2.2 @@ -3,9 +3,17 @@ @context_bar@ @notification_link@ -No bugs in this bug-tracker. -

+ This project is empty. +

-Submit a new bug report + +

+ » Project administration +

+
+

+ » Submit a new @pretty_names.bug@ +

+ Index: openacs-4/packages/bug-tracker/www/patch-add.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/patch-add.tcl,v diff -u -r1.2.2.1 -r1.2.2.2 --- openacs-4/packages/bug-tracker/www/patch-add.tcl 30 Sep 2002 14:55:53 -0000 1.2.2.1 +++ openacs-4/packages/bug-tracker/www/patch-add.tcl 5 Mar 2003 18:13:52 -0000 1.2.2.2 @@ -9,20 +9,20 @@ @cvs-id $Id$ } { bug_number:integer,optional - cancel:optional component_id:optional - {return_url ""} + {return_url ""} } -# If the user hit cancel, ignore everything else -if { [exists_and_not_null cancel] } { - set bug_view_url "bug?[export_vars { bug_number }]" - ad_returnredirect $bug_view_url - ad_script_abort -} - ad_require_permission [ad_conn package_id] create +if { [empty_string_p $return_url] } { + if { [exists_and_not_null bug_number] } { + set return_url "bug?[export_vars { bug_number }]" + } else { + set return_url "patch-list" + } +} + # User needs to be logged in here ad_maybe_redirect_for_registration @@ -34,8 +34,11 @@ set context_bar [ad_context_bar $page_title] set user_id [ad_conn user_id] +# Is this project using multiple versions? +set versions_p [bug_tracker::versions_p] + # Create the form -form create patch -html { enctype multipart/form-data } +form create patch -html { enctype multipart/form-data } -cancel_url $return_url element create patch patch_id \ -datatype integer \ @@ -108,6 +111,10 @@ element set_properties patch version_id \ -value [bug_tracker::conn user_version_id] + if { !$versions_p } { + element set_properties patch version_id -widget hidden + } + if { [info exists component_id] } { element set_properties patch component_id -value $component_id } @@ -124,28 +131,13 @@ set content [bug_tracker::get_uploaded_patch_file_content] set ip_address [ns_conn peeraddr] + + db_exec_plsql new_patch {} - db_exec_plsql new_patch { - select bt_patch__new( - :patch_id, - :package_id, - :component_id, - :summary, - :description, - :description_format, - :content, - :version_id, - :user_id, - :ip_address - ) - } + set patch_number [db_string patch_number_for_id {}] # Redirect to the view page for the created patch by default if { [empty_string_p $return_url] } { - set patch_number [db_string patch_number_for_id "select patch_number - from bt_patches - where patch_id = :patch_id"] - set redirect_url "patch?[export_vars { patch_number }]" } else { set redirect_url $return_url Index: openacs-4/packages/bug-tracker/www/patch.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/patch.tcl,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/bug-tracker/www/patch.tcl 11 Sep 2002 14:03:25 -0000 1.1 +++ openacs-4/packages/bug-tracker/www/patch.tcl 5 Mar 2003 18:13:52 -0000 1.1.2.1 @@ -25,13 +25,19 @@ set user_id [ad_conn user_id] # Does the user have write privilege on the project? set write_p [ad_permission_p $package_id write] -set user_is_submitter_p [expr $user_id == [bug_tracker::get_patch_submitter -patch_number $patch_number]] + +set submitter_id [bug_tracker::get_patch_submitter -patch_number $patch_number] + +set user_is_submitter_p [expr { ![empty_string_p $submitter_id] && $user_id == $submitter_id }] set write_or_submitter_p [expr $write_p || $user_is_submitter_p] set project_name [bug_tracker::conn project_name] set package_key [ad_conn package_key] set view_patch_url "[ad_conn url]?[export_vars -url { patch_number }]" -set patch_status [db_string patch_status "select status from bt_patches where patch_number = :patch_number and project_id = :package_id"] +set patch_status [db_string patch_status {}] +# Is this project using multiple versions? +set versions_p [bug_tracker::versions_p] + # Abort editing and return to view mode if the user hit cancel on the edit form if { [exists_and_not_null cancel_edit] } { ad_returnredirect $view_patch_url @@ -41,7 +47,7 @@ # If the download link was clicked - return the text content of the patch if { [exists_and_not_null download] } { - set patch_content [db_string get_patch_content "select content from bt_patches where patch_number = :patch_number and project_id = :package_id"] + set patch_content [db_string get_patch_content {}] doc_return 200 "text/plain" $patch_content ad_script_abort @@ -125,13 +131,15 @@ ad_maybe_redirect_for_registration } +# XXX FIXME TODO editing a patch invokes filename::validate, which is too paranoid... + # Create the form switch -- $mode { view { - form create patch -has_submit 1 + form create patch -has_submit 1 -cancel_url "[ad_conn url]?[export_vars -url { patch_number }]" } default { - form create patch -html { enctype multipart/form-data } + form create patch -html { enctype multipart/form-data } -cancel_url "[ad_conn url]?[export_vars -url { patch_number }]" } } @@ -252,47 +260,12 @@ if { [form is_request patch] } { # The form was requested - db_1row patch { - select bt_patches.patch_id, - bt_patches.patch_number, - bt_patches.project_id, - bt_patches.component_id, - bt_patches.summary, - bt_patches.content, - bt_patches.generated_from_version, - bt_patches.apply_to_version, - bt_patches.applied_to_version, - bt_patches.status, - bt_components.component_name, - acs_objects.creation_user as submitter_user_id, - submitter.first_names as submitter_first_names, - submitter.last_name as submitter_last_name, - submitter.email as submitter_email, - acs_objects.creation_date, - to_char(acs_objects.creation_date, 'fmMM/DDfm/YYYY') as creation_date_pretty, - coalesce((select version_name - from bt_versions - where bt_versions.version_id = bt_patches.generated_from_version), 'Unknown') as generated_from_version_name, - coalesce((select version_name - from bt_versions - where bt_versions.version_id = bt_patches.apply_to_version), 'Unknown') as apply_to_version_name, - coalesce((select version_name - from bt_versions - where bt_versions.version_id = bt_patches.applied_to_version), 'Unknown') as applied_to_version_name, - to_char(now(), 'fmMM/DDfm/YYYY') as now_pretty - from bt_patches, - acs_objects, - cc_users submitter, - bt_components - - where bt_patches.patch_number = :patch_number - and bt_patches.project_id = :package_id - and bt_patches.patch_id = acs_objects.object_id - and bt_patches.component_id = bt_components.component_id - and submitter.user_id = acs_objects.creation_user - - } -column_array patch + db_1row patch {} -column_array patch + set patch(generated_from_version_name) [ad_decode $patch(generated_from_version) "" "Unknown" [bug_tracker::version_get_name -version_id $patch(generated_from_version)]] + set patch(apply_to_version_name) [ad_decode $patch(apply_to_version) "" "Undecided" [bug_tracker::version_get_name -version_id $patch(apply_to_version)]] + set patch(applied_to_version_name) [bug_tracker::version_get_name -version_id $patch(applied_to_version)] + # When the user is taking an action that should change the status of the patch # - update the status (the new status will show up in the form) switch -- $mode { @@ -319,7 +292,7 @@ if { [string equal $mode "view"] } { set map_new_bug_link [ad_decode $write_or_submitter_p "1" "\[ Map to bugs \]" ""] element set_properties patch fixes_bugs \ - -value "[bug_tracker::get_bug_links -patch_id $patch(patch_id) -patch_number $patch(patch_number) -write_or_submitter_p $write_or_submitter_p] $map_new_bug_link" + -value "[bug_tracker::get_bug_links -patch_id $patch(patch_id) -patch_number $patch(patch_number) -write_or_submitter_p $write_or_submitter_p]
$map_new_bug_link" } element set_properties patch summary \ -value [ad_decode [info exists field_editable_p(summary)] 1 $patch(summary) "$patch(summary)"] @@ -331,7 +304,6 @@ element set_properties patch status \ -value [ad_decode [info exists field_editable_p(status)] 1 $patch(status) [bug_tracker::patch_status_pretty $patch(status)]] - element set_properties patch generated_from_version \ -value [ad_decode [info exists field_editable_p(generated_from_version)] 1 $patch(generated_from_version) $patch(generated_from_version_name)] element set_properties patch apply_to_version \ @@ -346,23 +318,8 @@ # Description/Actions/History set patch_id $patch(patch_id) set action_html "" - db_foreach actions { - select bt_patch_actions.action_id, - bt_patch_actions.action, - bt_patch_actions.actor as actor_user_id, - actor.first_names as actor_first_names, - actor.last_name as actor_last_name, - actor.email as actor_email, - bt_patch_actions.action_date, - to_char(bt_patch_actions.action_date, 'fmMM/DDfm/YYYY') as action_date_pretty, - bt_patch_actions.comment, - bt_patch_actions.comment_format - from bt_patch_actions, - cc_users actor - where bt_patch_actions.patch_id = :patch_id - and actor.user_id = bt_patch_actions.actor - order by action_date - } { + db_foreach actions {} { + set comment $comment_text append action_html "$action_date_pretty [bug_tracker::patch_action_pretty $action] by $actor_first_names $actor_last_name
[bug_tracker::bug_convert_comment_to_html -comment $comment -format $comment_format]
" } @@ -431,6 +388,10 @@
" ad_script_abort } + + if { !$versions_p } { + element set_properties patch generated_from_version -widget hidden + } } if { [form is_valid patch] } { @@ -473,10 +434,10 @@ } db_transaction { - set patch_id [db_string patch_id "select patch_id from bt_patches where patch_number = :patch_number and project_id = :package_id"] + set patch_id [db_string patch_id {}] if { [llength $update_exprs] > 0 } { - db_dml update_patch "update bt_patches \n set [join $update_exprs ",\n "] \n where patch_id = :patch_id" + db_dml update_patch {} } set action_id [db_nextval "acs_object_id_seq"] @@ -485,39 +446,27 @@ set $column [element get_value patch $column] } - db_dml patch_action { - insert into bt_patch_actions - (action_id, patch_id, action, actor, comment, comment_format) - values - (:action_id, :patch_id, :mode, :user_id, :description, :desc_format) - } + set action $mode + db_dml patch_action {} if { [string equal $mode "accept"] } { # Resolve any bugs that the user selected set resolve_bugs [element get_values patch resolve_bugs] foreach bug_number $resolve_bugs { - db_transaction { - set bug_id [bug_tracker::get_bug_id -bug_number $bug_number -project_id $package_id] - - db_dml resolve_bug { - update bt_bugs - set status = 'resolved' - where bug_id = :bug_id - } - - set bug_action_id [db_nextval "acs_object_id_seq"] - - set resolve_description "Fixed by patch #$patch_number" - - db_dml bug_action_resolve { - insert into bt_bug_actions - (action_id, bug_id, action, resolution, actor, comment, comment_format) - values - (:bug_action_id, :bug_id, 'resolve', 'fixed', :user_id, :resolve_description, 'html') - } - } + set resolve_description "Fixed by patch #$patch_number" + + set workflow_id [bug_tracker::bug::get_instance_workflow_id] + set bug_id [bug_tracker::get_bug_id -bug_number $bug_number -project_id $package_id] + set action_id [workflow::action::get_id -workflow_id $workflow_id -short_name "resolve"] + + bug_tracker::bug::edit \ + -bug_id $bug_id \ + -action_id $action_id \ + -description $resolve_description \ + -desc_format "text/html" \ + -array bug_row } } } Index: openacs-4/packages/bug-tracker/www/prefs.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/prefs.adp,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/bug-tracker/www/prefs.adp 3 May 2002 16:29:59 -0000 1.1 +++ openacs-4/packages/bug-tracker/www/prefs.adp 5 Mar 2003 18:13:52 -0000 1.1.2.1 @@ -1,7 +1,6 @@ @page_title@ @context_bar@ -component.name +prefs.user_version - - + Index: openacs-4/packages/bug-tracker/www/prefs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/prefs.tcl,v diff -u -r1.3.2.1 -r1.3.2.2 --- openacs-4/packages/bug-tracker/www/prefs.tcl 30 Sep 2002 14:55:53 -0000 1.3.2.1 +++ openacs-4/packages/bug-tracker/www/prefs.tcl 5 Mar 2003 18:13:52 -0000 1.3.2.2 @@ -6,16 +6,9 @@ @creation-date March 28, 2002 @cvs-id $Id$ } { - cancel:optional - {return_url ""} + {return_url "."} } -# If the user hit cancel, ignore everything else -if { [exists_and_not_null cancel] } { - ad_returnredirect $return_url - ad_script_abort -} - # User needs to be logged in here ad_maybe_redirect_for_registration @@ -32,38 +25,22 @@ set user_id [ad_conn user_id] - - -template::form create bt_user_prefs - -template::element create bt_user_prefs user_version \ - -label "Your version" \ - -widget select \ - -datatype integer \ - -options [concat { { "None" "" } } \ - [db_list_of_lists versions { select version_name, version_id from bt_versions where project_id = :package_id order by anticipated_freeze_date, version_name }]] \ - -optional - -template::element create bt_user_prefs return_url \ - -datatype text \ - -widget hidden \ - -value $return_url - -if { [template::form is_request bt_user_prefs] } { - db_1row get_current_values { - select user_version - from bt_user_prefs - where user_id = :user_id - and project_id = :package_id +ad_form -name prefs -cancel_url $return_url -form { + {user_version:integer(select) + {label "Your version"} + {options {[bug_tracker::version_get_options -include_unknown]}} + optional } - template::element set_properties bt_user_prefs user_version -value $user_version -} - -if { [template::form is_valid bt_user_prefs] } { - # valid form submission - - set user_version [template::element::get_value bt_user_prefs user_version] - + {return_url:text(hidden) + {value $return_url} + } +} -select_query { + select user_version + from prefs + where user_id = :user_id + and project_id = :package_id +} -after_submit { + set user_version [element get_value prefs user_version] db_dml update_row { update bt_user_prefs set user_version = :user_version Index: openacs-4/packages/bug-tracker/www/admin/component-ae.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/component-ae.adp,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/bug-tracker/www/admin/component-ae.adp 3 May 2002 16:29:59 -0000 1.1 +++ openacs-4/packages/bug-tracker/www/admin/component-ae.adp 5 Mar 2003 18:14:15 -0000 1.1.2.1 @@ -1,7 +1,8 @@ @page_title@ -@context_bar@ +@context@ component.name + Index: openacs-4/packages/bug-tracker/www/admin/component-ae.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/component-ae.tcl,v diff -u -r1.5.2.1 -r1.5.2.2 --- openacs-4/packages/bug-tracker/www/admin/component-ae.tcl 6 Dec 2002 15:01:45 -0000 1.5.2.1 +++ openacs-4/packages/bug-tracker/www/admin/component-ae.tcl 5 Mar 2003 18:14:15 -0000 1.5.2.2 @@ -3,111 +3,59 @@ @creation-date 2002-03-26 @cvs-id $Id$ } { - cancel:optional component_id:integer,optional - {return_url ""} + {return_url "."} } -if { [exists_and_not_null cancel] } { - ad_returnredirect $return_url - ad_script_abort -} - -set project_name [bug_tracker::conn project_name] set package_id [ad_conn package_id] -set package_key [ad_conn package_key] if { [info exists component_id] } { - set page_title "Edit Component" + set page_title "Edit [bug_tracker::conn Component]" } else { - set page_title "Add Component" + set page_title "Add [bug_tracker::conn Component]" } -set context_bar [ad_context_bar $page_title] +set context [list $page_title] -form create component +# LARS: +# I've hidden the description, because we don't use it anywhere -element create component return_url -datatype text -widget hidden -value $return_url - -element create component name \ - -datatype text \ - -html { size 50 } \ - -label "Component Name" - -element create component description \ - -datatype text \ - -widget textarea \ - -label "Description" \ - -optional \ - -html { cols 50 rows 8 } - -element create component url_name \ - -datatype text \ - -html { size 50 } \ - -label "Name in shortcut URL" \ - -optional - -element create component maintainer \ - -widget search \ - -datatype search \ - -result_datatype integer \ - -label "Maintainer" \ - -options [bug_tracker::users_get_options] \ - -optional \ - -search_query { - select distinct u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id - from cc_users u - where upper(coalesce(u.first_names || ' ', '') || coalesce(u.last_name || ' ', '') || u.email || ' ' || coalesce(u.screen_name, '')) like upper('%'||:value||'%') - order by name -} - - - -element create component component_id \ - -datatype integer \ - -widget hidden - -if { [form is_request component] } { - if { ![info exists component_id] } { - element set_properties component component_id -value [db_nextval "acs_object_id_seq"] - } else { - db_1row component_info { - select component_id, - component_name as name, - description, - maintainer, - url_name - from bt_components - where component_id = :component_id - } -column_array component_info - form set_values component component_info +ad_form -name component -cancel_url $return_url -form { + {component_id:key(acs_object_id_seq)} + {return_url:text(hidden) {value $return_url}} + {name:text {html { size 50 }} {label "[bug_tracker::conn Component] Name"}} + {description:text(hidden) {label {Description}} optional {html { cols 50 rows 8 }}} + {url_name:text {html { size 50 }} {label {Name in shortcut URL}} optional + {help_text "You can filter by this [bug_tracker::conn component] by viisting [ad_conn package_url]com/this-name/"} } -} - -if { [form is_valid component] } { - form get_values component name description maintainer url_name - - set count [db_0or1row num_components { select 1 from bt_components where component_id = :component_id }] - - if { $count == 0 } { - db_dml component_create { - insert into bt_components - (component_id, project_id, component_name, description, url_name, maintainer) - values - (:component_id, :package_id, :name, :description, :url_name, :maintainer) + {maintainer:search + {result_datatype integer} + {label "Maintainer"} + {options [bug_tracker::users_get_options]} + optional + {search_query + { + select distinct u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id + from cc_users u + where upper(coalesce(u.first_names || ' ', '') || coalesce(u.last_name || ' ', '') || u.email || ' ' || coalesce(u.screen_name, '')) like upper('%'||:value||'%') + order by name + } } - } else { - db_dml component_update { - update bt_components - set component_name = :name, - description = :description, - maintainer = :maintainer, - url_name = :url_name - where component_id = :component_id - } } +} -select_query { + select component_id, + component_name as name, + description, + maintainer, + url_name + from bt_components + where component_id = :component_id +} -new_data { + db_dml component_create {} +} -edit_data { + db_dml component_update {} +} -after_submit { + bug_tracker::components_flush ad_returnredirect $return_url ad_script_abort } - -ad_return_template \ No newline at end of file Index: openacs-4/packages/bug-tracker/www/admin/index.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/index.adp,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/bug-tracker/www/admin/index.adp 3 May 2002 16:29:59 -0000 1.1 +++ openacs-4/packages/bug-tracker/www/admin/index.adp 5 Mar 2003 18:14:15 -0000 1.1.2.1 @@ -1,20 +1,33 @@ -@project_name@ Project Admin +@page_title@ @context_bar@ +
+ + +
+

+ This is a new project. +

+

+ » Initial project configuration +

+
+
+ - - - + + + + + + + + + + - - + + + + + - @@ -108,27 +150,29 @@ @components.maintainer_first_names@ @components.maintainer_last_name@ - No maintainer of this component + No maintainer + - + - +
+ + Edit - - + + Delete - +
+ @project_name@ @@ -26,7 +39,7 @@
- Maintainer: + Maintainer: @project.maintainer_first_names@ @project.maintainer_last_name@ @@ -35,26 +48,44 @@ +   + Edit  
+ Versions + + Edit + +   +
- Project versions + + Categories - Edit + Edit  
- Project permissions + + Permissions Edit @@ -63,11 +94,22 @@  
+ Parameters + + Edit + +   +
- Components + + @pretty_names.Components@
+ @components.num_bugs@ @pretty_names.bug@@pretty_names.bugs@ + Edit - + Delete
No componentsNo components
Create New Component» Create new @pretty_names.component@
+
-

- Index: openacs-4/packages/bug-tracker/www/admin/index.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/index.tcl,v diff -u -r1.3 -r1.3.2.1 --- openacs-4/packages/bug-tracker/www/admin/index.tcl 10 Sep 2002 22:22:28 -0000 1.3 +++ openacs-4/packages/bug-tracker/www/admin/index.tcl 5 Mar 2003 18:14:15 -0000 1.3.2.1 @@ -10,66 +10,44 @@ set project_name [bug_tracker::conn project_name] set package_id [ad_conn package_id] set package_key [ad_conn package_key] +set page_title "Administration" +set bugs_exist_p [bug_tracker::bugs_exist_p] + +bug_tracker::get_pretty_names -array pretty_names + +set versions_p [bug_tracker::versions_p] + set context_bar [ad_context_bar] -db_1row project_info { - select p.maintainer, - u.first_names as maintainer_first_names, - u.last_name as maintainer_last_name, - u.email as maintainer_email - from bt_projects p left outer join - cc_users u on (u.user_id = p.maintainer) - where p.project_id = :package_id -} -column_array project +db_1row project_info { } -column_array project + set project(maintainer_url) [acs_community_member_url -user_id $project(maintainer)] set project_edit_url "project-edit" -set project_maintainer_edit_url "project-maintainer-edit" +set project_maintainer_edit_url "project-edit" set versions_edit_url "versions" -set permissions_edit_url "/permissions/one?[export_vars -url { { object_id {[ad_conn package_id]} } }]" +set categories_edit_url "categories" +set permissions_edit_url "/permissions/one?[export_vars { { object_id {[ad_conn package_id]} } }]" +set parameters_edit_url "/admin/site-map/parameter-set?[export_vars { { package_id {[ad_conn package_id]} } }]" set severity_codes_edit_url "severity-codes" set priority_codes_edit_url "priority-codes" -db_multirow -extend { edit_url delete_url maintainer_url } components components { - select c.component_id, - c.component_name, - c.description, - c.maintainer, - u.first_names as maintainer_first_names, - u.last_name as maintainer_last_name, - u.email as maintainer_email - from bt_components c left outer join - cc_users u on (u.user_id = c.maintainer) - where c.project_id = :package_id - order by component_name -} { - set edit_url "component-ae?[export_vars -url { component_id }]" - set delete_url "component-delete?[export_vars -url { component_id }]" +db_multirow -extend { edit_url delete_url maintainer_url view_bugs_url } components components {} { + set edit_url "component-ae?[export_vars { component_id }]" + if { $num_bugs == 0 } { + set delete_url "component-delete?[export_vars { component_id }]" + set view_bugs_url {} + } else { + set view_bugs_url "../?[export_vars { { filter.component_id $component_id } { filter.status any } }]" + set delete_url {} + } set maintainer_url [acs_community_member_url -user_id $maintainer] } set component_add_url "component-ae" -db_multirow versions versions { - select v.version_id, - v.version_name, - v.description, - v.anticipated_freeze_date, - v.actual_freeze_date, - v.anticipated_release_date, - v.actual_release_date, - v.maintainer, - u.first_names as maintainer_first_names, - u.last_name as maintainer_last_name, - u.email as maintainer_email, - v.supported_platforms, - v.active_version_p, - v.assignable_p - from bt_versions v left outer join - cc_users u on (u.user_id = v.maintainer) - where v.project_id = :package_id -} +db_multirow versions versions {} ad_return_template Index: openacs-4/packages/bug-tracker/www/admin/project-edit.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/project-edit.adp,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/bug-tracker/www/admin/project-edit.adp 3 May 2002 16:29:59 -0000 1.1 +++ openacs-4/packages/bug-tracker/www/admin/project-edit.adp 5 Mar 2003 18:14:15 -0000 1.1.2.1 @@ -1,7 +1,8 @@ @page_title@ -@context_bar@ -project_info.name +@context@ +project.name - + + Index: openacs-4/packages/bug-tracker/www/admin/project-edit.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/project-edit.tcl,v diff -u -r1.5 -r1.5.2.1 --- openacs-4/packages/bug-tracker/www/admin/project-edit.tcl 10 Sep 2002 22:22:28 -0000 1.5 +++ openacs-4/packages/bug-tracker/www/admin/project-edit.tcl 5 Mar 2003 18:14:15 -0000 1.5.2.1 @@ -5,73 +5,44 @@ @creation-date 2002-03-26 @cvs-id $Id$ } { - cancel:optional - {return_url ""} + {return_url "."} } -if { [exists_and_not_null cancel] } { - ad_returnredirect $return_url - ad_script_abort -} - set project_name [bug_tracker::conn project_name] set package_id [ad_conn package_id] -set package_key [ad_conn package_key] set page_title "Edit Project" -set context_bar [ad_context_bar $page_title] +set context [list $page_title] -form create project_info - -element create project_info return_url -datatype text -widget hidden -value $return_url - -element create project_info name \ - -datatype text \ - -html { size 50 } \ - -label "Project Name" - -element create project_info description \ - -datatype text \ - -widget textarea \ - -label "Description" \ - -optional \ - -html { cols 50 rows 8 } - -element create project_info email_subject_name \ - -datatype text \ - -html { size 50 } \ - -label "Email subject tag" - -if { [form is_request project_info] } { - db_1row project_info { - select description, email_subject_name - from bt_projects - where project_id = :package_id - } -column_array project_info - - form set_values project_info project_info - - element set_properties project_info name \ - -value [bug_tracker::conn project_name] - -} - -if { [form is_valid project_info] } { - form get_values project_info description email_subject_name name - +ad_form -name project -cancel_url $return_url -form { + package_id:key + {return_url:text(hidden) {value $return_url}} + {name:text {html { size 50 }} {label "Project Name"} + {help_text {This is also the name of this package in the site map}} + } + {description:text(hidden) {label "Description"} optional {html { cols 50 rows 8 }} + {help_text {This isn't actually used anywhere at this point. Sorry.}} + } + {email_subject_name:text {html { size 50 }} {label "Notification tag"} optional + {help_text {This text will be included in square brackets at the beginning of all notifications, for example \[OpenACS Bugs\]}} + } + {maintainer:search + {result_datatype integer} + {label {Project Maintainer}} + {options [bug_tracker::users_get_options]} + optional + {search_query_name project_search} + } +} -select_query_name project_select -edit_data { db_transaction { - db_dml project_info_update { - update bt_projects - set description = :description, - email_subject_name = :email_subject_name - where project_id = :package_id - } + db_dml project_info_update {} bug_tracker::set_project_name $name } - + site_nodes_sync + bug_tracker::get_project_info_flush +} -after_submit { ad_returnredirect $return_url ad_script_abort } -ad_return_template Index: openacs-4/packages/bug-tracker/www/admin/project-maintainer-edit.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/project-maintainer-edit.adp,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/bug-tracker/www/admin/project-maintainer-edit.adp 3 May 2002 16:29:59 -0000 1.1 +++ openacs-4/packages/bug-tracker/www/admin/project-maintainer-edit.adp 5 Mar 2003 18:14:15 -0000 1.1.2.1 @@ -1,7 +1,8 @@ @page_title@ -@context_bar@ +@context@ project_maintainer.maintainer + Index: openacs-4/packages/bug-tracker/www/admin/project-maintainer-edit.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/project-maintainer-edit.tcl,v diff -u -r1.4.2.2 -r1.4.2.3 --- openacs-4/packages/bug-tracker/www/admin/project-maintainer-edit.tcl 13 Jan 2003 18:25:43 -0000 1.4.2.2 +++ openacs-4/packages/bug-tracker/www/admin/project-maintainer-edit.tcl 5 Mar 2003 18:14:15 -0000 1.4.2.3 @@ -5,49 +5,34 @@ @creation-date 2002-03-26 @cvs-id $Id$ } { - cancel:optional - {return_url ""} + {return_url "."} } -if { [exists_and_not_null cancel] } { - ad_returnredirect $return_url - ad_script_abort -} - -set project_name [bug_tracker::conn project_name] set package_id [ad_conn package_id] -set package_key [ad_conn package_key] set page_title "Edit Project Maintainer" -set context_bar [ad_context_bar $page_title] +set context [list $page_title] -form create project_maintainer - -element create project_maintainer return_url -datatype text -widget hidden -value $return_url - -element create project_maintainer maintainer \ - -datatype search \ - -widget search \ - -result_datatype integer \ - -label "Project Maintainer" \ - -options [bug_tracker::users_get_options] \ - -optional \ - -search_query { - select distinct u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id - from cc_users u - where upper(coalesce(u.first_names || ' ', '') || coalesce(u.last_name || ' ', '') || u.email || ' ' || coalesce(u.screen_name, '')) like upper('%'||:value||'%') - order by name -} - -if { [form is_request project_maintainer] } { - element set_properties project_maintainer maintainer \ - -value [db_string maintainer { select maintainer from bt_projects where project_id = :package_id }] -} - -if { [form is_valid project_maintainer] } { - form get_values project_maintainer maintainer - +ad_form -name project_maintainer -cancel_url $return_url -form { + {return_url:text(hidden) {value $return_url}} + {maintainer:search + {result_datatype integer} + {label {Project Maintainer}} + {options [bug_tracker::users_get_options]} + optional + {search_query + { + select distinct u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id + from cc_users u + where upper(coalesce(u.first_names || ' ', '') || coalesce(u.last_name || ' ', '') || u.email || ' ' || coalesce(u.screen_name, '')) like upper('%'||:value||'%') + order by name + } + } + } +} -select_query { + select maintainer from bt_projects where project_id = :package_id +} -on_submit { db_dml project_maintainer_update { update bt_projects set maintainer = :maintainer @@ -57,5 +42,3 @@ ad_returnredirect $return_url ad_script_abort } - -ad_return_template \ No newline at end of file Index: openacs-4/packages/bug-tracker/www/admin/version-ae.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/version-ae.adp,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/bug-tracker/www/admin/version-ae.adp 3 May 2002 16:29:59 -0000 1.1 +++ openacs-4/packages/bug-tracker/www/admin/version-ae.adp 5 Mar 2003 18:14:15 -0000 1.1.2.1 @@ -1,7 +1,8 @@ @page_title@ -@context_bar@ +@context@ version.version_name + Index: openacs-4/packages/bug-tracker/www/admin/version-ae.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/version-ae.tcl,v diff -u -r1.3.2.1 -r1.3.2.2 --- openacs-4/packages/bug-tracker/www/admin/version-ae.tcl 6 Dec 2002 15:01:45 -0000 1.3.2.1 +++ openacs-4/packages/bug-tracker/www/admin/version-ae.tcl 5 Mar 2003 18:14:15 -0000 1.3.2.2 @@ -4,134 +4,59 @@ @creation-date March 26, 2002 @cvs-id $Id$ } { - {version_id ""} - {return_url ""} - cancel:optional + version_id:integer,optional + {return_url "."} } -if { [exists_and_not_null cancel] } { - ad_returnredirect $return_url - ad_script_abort -} - -set project_name [bug_tracker::conn project_name] set package_id [ad_conn package_id] -set package_key [ad_conn package_key] -if { [info exists component_id] } { +if { [info exists version_id] } { set page_title "Edit Version" } else { set page_title "Add Version" } -set context_bar [ad_context_bar [list $return_url "Versions"] $page_title] +set context [list [list $return_url "Versions"] $page_title] - -# TODO: check that the handling of the primary key is okay. If there is -# no primary key and you're only inserting, you can just ignore it. -# Add handling for any other incoming URL variables that should become part of the form. - -form create version - -element create version version_id -widget hidden -element create version return_url -datatype text -widget hidden -value $return_url - -element create version version_name -label "Version name" -widget text -datatype text -html { size 50 } -element create version description -label "Description" -widget textarea -datatype text -optional -html { cols 50 rows 8 } -element create version supported_platforms -label "Supported platforms" -widget text -datatype text \ - -html { size 50 } -optional - -element create version maintainer \ - -widget search \ - -datatype search \ - -result_datatype integer \ - -label "Maintainer" \ - -options [bug_tracker::users_get_options] \ - -optional \ - -search_query { - select distinct u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id - from cc_users u - where upper(coalesce(u.first_names || ' ', '') || coalesce(u.last_name || ' ', '') || u.email || ' ' || coalesce(u.screen_name, '')) like upper('%'||:value||'%') - order by name -} - - -element create version anticipated_freeze_date -label "Anticipated freeze date" -widget date -datatype date -optional -format "MONTH DD, YYYY" -element create version anticipated_release_date -label "Anticipated release date" -widget date -datatype date -optional -format "MONTH DD, YYYY" -element create version assignable_p -label "Assignable?" -widget select -datatype text -optional -options {{Yes t} {No f}} - -element create version insert_or_update -widget hidden -datatype text - -if { [form is_request version] } { - if {[empty_string_p $version_id]} { - set insert_or_update insert - element set_properties version insert_or_update -value insert - set version_id [db_nextval "acs_object_id_seq"] - element set_properties version version_id -value $version_id - } else { - set insert_or_update update - element set_properties version insert_or_update -value update - db_1row get_current_values " - select version_id, version_name, description, to_char(anticipated_freeze_date, 'YYYY MM DD HH24 MI') as anticipated_freeze_date, to_char(anticipated_release_date, 'YYYY MM DD HH24 MI') as anticipated_release_date, maintainer, supported_platforms, assignable_p - from bt_versions - where version_id = :version_id - " - element set_properties version version_id -value $version_id - element set_properties version version_name -value $version_name - element set_properties version description -value $description - element set_properties version anticipated_freeze_date -value $anticipated_freeze_date - element set_properties version anticipated_release_date -value $anticipated_release_date - element set_properties version maintainer -value $maintainer - element set_properties version supported_platforms -value $supported_platforms - element set_properties version assignable_p -value $assignable_p - - +ad_form -name version -cancel_url $return_url -form { + {version_id:key(acs_object_id_seq)} + {version_name:text {label "Version name"} {html { size 50 }}} + {description:text(textarea) {label "Description"} optional {html { cols 50 rows 8 }}} + {supported_platforms:text {label "Supported platforms"} {html { size 50 }} optional} + {maintainer:search + {result_datatype integer} + {label "Maintainer"} + {options {[bug_tracker::users_get_options]}} + optional + {search_query_name version_search} } -} - -set insert_or_update [element::get_value version insert_or_update] - -if { [form is_valid version] } { - # valid form submission - set version_id [element::get_value version version_id] - set project_id [ad_conn package_id] - set version_name [element::get_value version version_name] - set description [element::get_value version description] - set anticipated_freeze_date [element::get_value version anticipated_freeze_date] - if {![empty_string_p $anticipated_freeze_date]} { - set anticipated_freeze_date [util::date::get_property sql_date $anticipated_freeze_date] - } else { - set anticipated_freeze_date NULL + {anticipated_freeze_date:date,to_sql(sql_date),to_html(sql_date),optional + {label "Anticipated freeze"} optional } - set anticipated_release_date [element::get_value version anticipated_release_date] - if {![empty_string_p $anticipated_release_date]} { - set anticipated_release_date [util::date::get_property sql_date $anticipated_release_date] - } else { - set anticipated_release_date NULL + {actual_freeze_date:date,to_sql(sql_date),to_html(sql_date),optional + {label "Actual freeze"} optional } - set maintainer [element::get_value version maintainer] - set supported_platforms [element::get_value version supported_platforms] - set assignable_p [element::get_value version assignable_p] - - if {$insert_or_update == "insert"} { - if {[db_0or1row check_exists " - select 1 from bt_versions where version_id = :version_id - "]} { - # detected a double form submission - you can return - # an error if you want, but it's not really necessary - } else { - db_dml insert_row " - insert into bt_versions (version_id, project_id, version_name, description, anticipated_freeze_date, anticipated_release_date, maintainer, supported_platforms, assignable_p) - values (:version_id, :project_id, :version_name, :description, $anticipated_freeze_date, $anticipated_release_date, :maintainer, :supported_platforms, :assignable_p) - " - } + {anticipated_release_date:date,to_sql(sql_date),to_html(sql_date) ,optional + {label "Anticipated release"} optional + } + {actual_release_date:date,to_sql(sql_date),to_html(sql_date),optional + {label "Actual release"} optional + } + {assignable_p:text(radio) {label "Assignable?"} optional {options {{Yes t} {No f}}}} + {return_url:text(hidden) {value $return_url}} +} -select_query_name version_select -new_request { + set assignable_p "t" +} -new_data { + if { [db_0or1row check_exists {}] } { + # detected a double form submission - you can return + # an error if you want, but it's not really necessary } else { - db_dml update_row " - update bt_versions - set version_id=:version_id, project_id=:project_id, version_name=:version_name, description=:description, anticipated_freeze_date=$anticipated_freeze_date, anticipated_release_date=$anticipated_release_date, maintainer=:maintainer, supported_platforms=:supported_platforms, assignable_p=:assignable_p - where version_id = :version_id - " + db_dml insert_row "" } - +} -edit_data { + db_dml update_row "" +} -after_submit { + bug_tracker::versions_flush + ad_returnredirect $return_url ad_script_abort } Index: openacs-4/packages/bug-tracker/www/admin/version-set-active.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/version-set-active.tcl,v diff -u -r1.2 -r1.2.2.1 --- openacs-4/packages/bug-tracker/www/admin/version-set-active.tcl 10 Sep 2002 22:22:28 -0000 1.2 +++ openacs-4/packages/bug-tracker/www/admin/version-set-active.tcl 5 Mar 2003 18:14:15 -0000 1.2.2.1 @@ -9,8 +9,6 @@ { return_url "" } } -db_exec_plsql set_active_version { - select bt_version__set_active(:version_id) -} +db_exec_plsql set_active_version {} ad_returnredirect $return_url Index: openacs-4/packages/bug-tracker/www/admin/versions.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/versions.adp,v diff -u -r1.1 -r1.1.2.1 --- openacs-4/packages/bug-tracker/www/admin/versions.adp 3 May 2002 16:29:59 -0000 1.1 +++ openacs-4/packages/bug-tracker/www/admin/versions.adp 5 Mar 2003 18:14:15 -0000 1.1.2.1 @@ -1,77 +1,125 @@ -@project_name@ Versions +@ Versions @context_bar@ -

Current Version (The one currently being developed)

+

Current Version

None - - - +
Edit
+ - - + + + + - - - - - - + + + + + + + + - - + + + +
Version Planned Freeze Planned Release MaintainerSupported PlatformsAssignable?AssignEditDeleteRelease
Edit@current_version.version_name@@current_version.anticipated_freeze_date@@current_version.anticipated_release_date@ + +
+ @current_version.version_name@ + + @current_version.anticipated_freeze_date@ + + @current_version.anticipated_release_date@ + @current_version.maintainer_first_names@ @current_version.maintainer_last_name@ None @current_version.supported_platforms@@current_version.assignable_p_pretty@ + @current_version.assignable_p_pretty@ + + Edit + + + Delete + + + Release this version +
+

+ The current version is the currently being developed on. +

+

Future Versions

None - - - - +
EditMake Active
+ - - + + + + - - - - - - - + + + + + + + + - - + + + +
Version Planned Freeze Planned Release MaintainerSupported PlatformsAssignable?AssignEditDeleteCurrent
EditMake Active@future_version.version_name@@future_version.anticipated_freeze_date@@future_version.anticipated_release_date@ + +
+ @future_version.version_name@ + + @future_version.anticipated_freeze_date@ + + @future_version.anticipated_release_date@ + @future_version.maintainer_first_names@ @future_version.maintainer_last_name@ None @future_version.supported_platforms@@future_version.assignable_p_pretty@ + @future_version.assignable_p_pretty@ + + Edit + + + @bug-tracker.Delete# + + + Set to current +
@@ -87,28 +135,46 @@ None
- - - +
Edit
+ - + - + + + - - - - - - + + + + + + + + - + +
VersionActual FreezePlanned Release Actual ReleaseSupported PlatformsMaintainerEditDelete
Edit@past_version.version_name@@past_version.actual_freeze_date@@past_version.actual_release_date@ + +
+ @past_version.version_name@ + + @past_version.anticipated_release_date@ + + @past_version.actual_release_date@ + @past_version.maintainer_first_names@ @past_version.maintainer_last_name@ None @past_version.supported_platforms@ + Edit + + + @bug-tracker.Delete# + +
Index: openacs-4/packages/bug-tracker/www/admin/versions.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/bug-tracker/www/admin/versions.tcl,v diff -u -r1.3 -r1.3.2.1 --- openacs-4/packages/bug-tracker/www/admin/versions.tcl 10 Sep 2002 22:22:28 -0000 1.3 +++ openacs-4/packages/bug-tracker/www/admin/versions.tcl 5 Mar 2003 18:14:15 -0000 1.3.2.1 @@ -17,83 +17,38 @@ set return_url "versions" -db_multirow -extend { actual_release_date maintainer_url edit_url delete_url } current_version current_version { - select v.version_id, - v.version_name, - v.description, - v.anticipated_freeze_date, - v.actual_freeze_date, - v.anticipated_release_date, - v.maintainer, - u.first_names as maintainer_first_names, - u.last_name as maintainer_last_name, - u.email as maintainer_email, - v.supported_platforms, - v.active_version_p, - v.assignable_p, - case when v.assignable_p = 't' then 'Yes' else 'No' end as assignable_p_pretty - from bt_versions v left outer join - cc_users u on (u.user_id = v.maintainer) - where v.project_id = :package_id - and v.active_version_p = 't' +db_multirow -extend { maintainer_url edit_url delete_url release_url } current_version current_version { } { set edit_url "version-ae?[export_vars -url { version_id return_url }]" - set delete_url "version-delete?[export_vars -url { version_id return_url }]" + if { $num_bugs == 0 } { + set delete_url "version-delete?[export_vars -url { version_id }]" + } else { + set delete_url {} + } + set release_url "version-release?[export_vars { version_id }]" set maintainer_url [acs_community_member_url -user_id $maintainer] } -db_multirow -extend { actual_release_date maintainer_url edit_url delete_url set_active_url } future_version future_versions { - select v.version_id, - v.version_name, - v.description, - v.anticipated_freeze_date, - v.actual_freeze_date, - v.anticipated_release_date, - v.maintainer, - u.first_names as maintainer_first_names, - u.last_name as maintainer_last_name, - u.email as maintainer_email, - v.supported_platforms, - v.active_version_p, - v.assignable_p, - case when v.assignable_p = 't' then 'Yes' else 'No' end as assignable_p_pretty - from bt_versions v left outer join - cc_users u on (u.user_id = v.maintainer) - where v.project_id = :package_id - and v.actual_release_date is null - and v.active_version_p = 'f' - order by v.anticipated_release_date, version_name +db_multirow -extend { maintainer_url edit_url delete_url set_active_url } future_version future_versions { } { set edit_url "version-ae?[export_vars -url { version_id return_url }]" - set delete_url "version-delete?[export_vars -url { version_id return_url }]" + if { $num_bugs == 0 } { + set delete_url "version-delete?[export_vars -url { version_id }]" + } else { + set delete_url {} + } set maintainer_url [acs_community_member_url -user_id $maintainer] set set_active_url "version-set-active?[export_vars -url { version_id return_url }]" } db_multirow -extend { maintainer_url edit_url delete_url } past_version past_versions { - select v.version_id, - v.version_name, - v.description, - v.anticipated_freeze_date, - v.actual_freeze_date, - v.anticipated_release_date, - v.actual_release_date, - v.maintainer, - u.first_names as maintainer_first_names, - u.last_name as maintainer_last_name, - u.email as maintainer_email, - v.supported_platforms, - v.active_version_p, - v.assignable_p, - case when v.assignable_p = 't' then 'Yes' else 'No' end as assignable_p_pretty - from bt_versions v left outer join - cc_users u on (u.user_id = v.maintainer) - where v.project_id = :package_id - and v.actual_release_date is not null - order by v.actual_release_date, version_name } { set edit_url "version-ae?[export_vars -url { version_id return_url }]" - set delete_url "version-delete?[export_vars -url { version_id return_url }]" + if { $num_bugs == 0 } { + set delete_url "version-delete?[export_vars -url { version_id }]" + } else { + set delete_url {} + } set maintainer_url [acs_community_member_url -user_id $maintainer] }