blob: 9e193df02156fa0728a343a358b1daa06428f605 [file] [log] [blame]
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +00001#!/usr/bin/perl -T
2# This Source Code Form is subject to the terms of the Mozilla Public
3# License, v. 2.0. If a copy of the MPL was not distributed with this
4# file, You can obtain one at http://mozilla.org/MPL/2.0/.
timothy@apple.comf42518d2008-02-06 20:19:16 +00005#
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +00006# This Source Code Form is "Incompatible With Secondary Licenses", as
7# defined by the Mozilla Public License, v. 2.0.
timothy@apple.comf42518d2008-02-06 20:19:16 +00008
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +00009use 5.10.1;
timothy@apple.comf42518d2008-02-06 20:19:16 +000010use strict;
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +000011use warnings;
timothy@apple.comf42518d2008-02-06 20:19:16 +000012
ddkilzer@apple.com097da082009-07-03 02:14:25 +000013use lib qw(. lib);
timothy@apple.comf42518d2008-02-06 20:19:16 +000014
ddkilzer@apple.comf3615fc2009-07-03 02:13:41 +000015use Bugzilla;
16use Bugzilla::Error;
17use Bugzilla::Bug;
timothy@apple.comf42518d2008-02-06 20:19:16 +000018
ddkilzer@apple.comf3615fc2009-07-03 02:13:41 +000019use List::Util qw(max);
20
21my $user = Bugzilla->login();
timothy@apple.comf42518d2008-02-06 20:19:16 +000022
23my $cgi = Bugzilla->cgi;
ddkilzer@apple.comf3615fc2009-07-03 02:13:41 +000024my $template = Bugzilla->template;
25my $vars = {};
timothy@apple.comf42518d2008-02-06 20:19:16 +000026# Connect to the shadow database if this installation is using one to improve
27# performance.
ddkilzer@apple.comf3615fc2009-07-03 02:13:41 +000028my $dbh = Bugzilla->switch_to_shadow_db();
timothy@apple.comf42518d2008-02-06 20:19:16 +000029
30################################################################################
31# Data/Security Validation #
32################################################################################
33
34# Make sure the bug ID is a positive integer representing an existing
35# bug that the user is authorized to access.
ddkilzer@apple.com57772842014-10-16 16:00:58 +000036my $bug = Bugzilla::Bug->check(scalar $cgi->param('id'));
37my $id = $bug->id;
timothy@apple.comf42518d2008-02-06 20:19:16 +000038
ddkilzer@apple.comf3615fc2009-07-03 02:13:41 +000039local our $hide_resolved = $cgi->param('hide_resolved') ? 1 : 0;
ddkilzer@apple.comf3615fc2009-07-03 02:13:41 +000040local our $maxdepth = $cgi->param('maxdepth') || 0;
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +000041if ($maxdepth !~ /^\d+$/) {
42 $maxdepth = 0;
43}
timothy@apple.comf42518d2008-02-06 20:19:16 +000044
45################################################################################
46# Main Section #
47################################################################################
48
ddkilzer@apple.comf3615fc2009-07-03 02:13:41 +000049# Stores the greatest depth to which either tree goes.
50local our $realdepth = 0;
timothy@apple.comf42518d2008-02-06 20:19:16 +000051
52# Generate the tree of bugs that this bug depends on and a list of IDs
53# appearing in the tree.
ddkilzer@apple.com57772842014-10-16 16:00:58 +000054my $dependson_tree = { $id => $bug };
timothy@apple.comf42518d2008-02-06 20:19:16 +000055my $dependson_ids = {};
56GenerateTree($id, "dependson", 1, $dependson_tree, $dependson_ids);
57$vars->{'dependson_tree'} = $dependson_tree;
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +000058$vars->{'dependson_ids'} = [keys(%$dependson_ids)];
timothy@apple.comf42518d2008-02-06 20:19:16 +000059
60# Generate the tree of bugs that this bug blocks and a list of IDs
61# appearing in the tree.
ddkilzer@apple.com57772842014-10-16 16:00:58 +000062my $blocked_tree = { $id => $bug };
timothy@apple.comf42518d2008-02-06 20:19:16 +000063my $blocked_ids = {};
64GenerateTree($id, "blocked", 1, $blocked_tree, $blocked_ids);
65$vars->{'blocked_tree'} = $blocked_tree;
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +000066$vars->{'blocked_ids'} = [keys(%$blocked_ids)];
timothy@apple.comf42518d2008-02-06 20:19:16 +000067
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +000068$vars->{'bugid'} = $id;
69$vars->{'realdepth'} = $realdepth;
70$vars->{'maxdepth'} = $maxdepth;
71$vars->{'hide_resolved'} = $hide_resolved;
timothy@apple.comf42518d2008-02-06 20:19:16 +000072
73print $cgi->header();
74$template->process("bug/dependency-tree.html.tmpl", $vars)
75 || ThrowTemplateError($template->error());
76
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +000077# Tree Generation Functions
timothy@apple.comf42518d2008-02-06 20:19:16 +000078
79sub GenerateTree {
timothy@apple.comf42518d2008-02-06 20:19:16 +000080 my ($bug_id, $relationship, $depth, $bugs, $ids) = @_;
ddkilzer@apple.comf3615fc2009-07-03 02:13:41 +000081
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +000082 # determine just the list of bug ids
83 _generate_bug_ids($bug_id, $relationship, $depth, $ids);
84 my $bug_ids = [ keys %$ids ];
85 return unless @$bug_ids;
86
87 # load all the bugs at once
88 foreach my $bug (@{ Bugzilla::Bug->new_from_list($bug_ids) }) {
89 if (!$bug->{error}) {
90 $bugs->{$bug->id} = $bug;
91 }
ddkilzer@apple.comf3615fc2009-07-03 02:13:41 +000092 }
93
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +000094 # preload bug visibility
95 Bugzilla->user->visible_bugs($bug_ids);
ddkilzer@apple.comf3615fc2009-07-03 02:13:41 +000096
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +000097 # and generate the tree
98 _generate_tree($bug_id, $relationship, $depth, $bugs, $ids);
99}
100
101sub _generate_bug_ids {
102 my ($bug_id, $relationship, $depth, $ids) = @_;
103
104 # Record this depth in the global $realdepth variable if it's farther
timothy@apple.comf42518d2008-02-06 20:19:16 +0000105 # than we've gone before.
106 $realdepth = max($realdepth, $depth);
107
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +0000108 my $dependencies = _get_dependencies($bug_id, $relationship);
109 foreach my $dep_id (@$dependencies) {
110 if (!$maxdepth || $depth <= $maxdepth) {
timothy@apple.comf42518d2008-02-06 20:19:16 +0000111 $ids->{$dep_id} = 1;
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +0000112 _generate_bug_ids($dep_id, $relationship, $depth + 1, $ids);
timothy@apple.comf42518d2008-02-06 20:19:16 +0000113 }
114 }
115}
ddkilzer@apple.com8040bb02017-03-21 16:27:49 +0000116
117sub _generate_tree {
118 my ($bug_id, $relationship, $depth, $bugs, $ids) = @_;
119
120 my $dependencies = _get_dependencies($bug_id, $relationship);
121
122 foreach my $dep_id (@$dependencies) {
123 # recurse
124 if (!$maxdepth || $depth < $maxdepth) {
125 _generate_tree($dep_id, $relationship, $depth + 1, $bugs, $ids);
126 }
127
128 # remove bugs according to visiblity
129 if (!Bugzilla->user->can_see_bug($dep_id)) {
130 delete $ids->{$dep_id};
131 }
132 elsif (!grep { $_ == $dep_id } @{ $bugs->{dependencies}->{$bug_id} }) {
133 push @{ $bugs->{dependencies}->{$bug_id} }, $dep_id;
134 }
135 }
136}
137
138sub _get_dependencies {
139 my ($bug_id, $relationship) = @_;
140 my $cache = Bugzilla->request_cache->{dependency_cache} ||= {};
141 return $cache->{$bug_id}->{$relationship} ||=
142 $relationship eq 'dependson'
143 ? Bugzilla::Bug::EmitDependList('blocked', 'dependson', $bug_id, $hide_resolved)
144 : Bugzilla::Bug::EmitDependList('dependson', 'blocked', $bug_id, $hide_resolved);
145}
146