summaryrefslogtreecommitdiffstats
path: root/extensions/MyDashboard/Extension.pm
diff options
context:
space:
mode:
authorDave Lawrence <dlawrence@mozilla.com>2012-08-10 01:06:02 +0200
committerDave Lawrence <dlawrence@mozilla.com>2012-08-10 01:06:02 +0200
commitb0f7006e467249d5cbff2b84febe0b658744b559 (patch)
treec0fac29a3f79e686a27a5feca4803ef3c98aeb39 /extensions/MyDashboard/Extension.pm
parent5c72835ba89910d7586a1f6b18e6e1cd0a897090 (diff)
downloadbugzilla-b0f7006e467249d5cbff2b84febe0b658744b559.tar.gz
bugzilla-b0f7006e467249d5cbff2b84febe0b658744b559.tar.xz
Initial import of MyDashboard extension
Diffstat (limited to 'extensions/MyDashboard/Extension.pm')
-rw-r--r--extensions/MyDashboard/Extension.pm379
1 files changed, 379 insertions, 0 deletions
diff --git a/extensions/MyDashboard/Extension.pm b/extensions/MyDashboard/Extension.pm
new file mode 100644
index 000000000..869d3c81e
--- /dev/null
+++ b/extensions/MyDashboard/Extension.pm
@@ -0,0 +1,379 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Extension::MyDashboard;
+
+use strict;
+
+use base qw(Bugzilla::Extension);
+
+use Bugzilla;
+use Bugzilla::Constants;
+use Bugzilla::Search;
+use Bugzilla::Util;
+use Bugzilla::Status;
+use Bugzilla::Field;
+use Bugzilla::Search::Saved;
+
+use Bugzilla::Extension::MyDashboard::TimeAgo qw(time_ago);
+
+use DateTime;
+
+our $VERSION = BUGZILLA_VERSION;
+
+sub QUERY_DEFS {
+ my $user = Bugzilla->user;
+
+ my @query_defs = (
+ {
+ name => 'assignedbugs',
+ heading => 'Assigned to You',
+ description => 'The bug has been assigned to you and it is not resolved or closed yet.',
+ params => {
+ 'bug_status' => ['__open__'],
+ 'emailassigned_to1' => 1,
+ 'emailtype1' => 'exact',
+ 'email1' => $user->login
+ }
+ },
+ {
+ name => 'newbugs',
+ heading => 'New Reported by You',
+ description => 'You reported the bug but nobody has accepted it yet.',
+ params => {
+ 'bug_status' => ['NEW'],
+ 'emailreporter1' => 1,
+ 'emailtype1' => 'exact',
+ 'email1' => $user->login
+ }
+ },
+ {
+ name => 'inprogressbugs',
+ heading => "In Progress Reported by You",
+ description => 'You reported the bug, the developer accepted the bug and is hopefully working on it.',
+ params => {
+ 'bug_status' => [ map { $_->name } grep($_->name ne 'NEW' && $_->name ne 'MODIFIED', _open_states()) ],
+ 'emailreporter1' => 1,
+ 'emailtype1' => 'exact',
+ 'email1' => $user->login
+ }
+ },
+ {
+ name => 'openccbugs',
+ heading => "You Are CC'd On",
+ description => 'You are in the CC list of the bug, so you are watching it.',
+ params => {
+ 'bug_status' => ['__open__'],
+ 'emailcc1' => 1,
+ 'emailtype1' => 'exact',
+ 'email1' => $user->login
+ }
+ },
+ );
+
+ if (Bugzilla->params->{'useqacontact'}) {
+ push(@query_defs, {
+ name => 'qacontactbugs',
+ heading => 'You Are QA Contact',
+ description => 'You are the qa contact on this bug and it is not resolved or closed yet.',
+ params => {
+ 'bug_status' => ['__open__'],
+ 'emailqa_contact1' => 1,
+ 'emailtype1' => 'exact',
+ 'email1' => $user->login
+ }
+ });
+ }
+
+ return @query_defs;
+}
+
+################
+# Installation #
+################
+
+sub db_schema_abstract_schema {
+ my ($self, $args) = @_;
+
+ my $schema = $args->{schema};
+
+ $schema->{'mydashboard'} = {
+ FIELDS => [
+ namedquery_id => {TYPE => 'INT3', NOTNULL => 1,
+ REFERENCES => {TABLE => 'namedqueries',
+ COLUMN => 'id',
+ DELETE => 'CASCADE'}},
+ user_id => {TYPE => 'INT3', NOTNULL => 1,
+ REFERENCES => {TABLE => 'profiles',
+ COLUMN => 'userid',
+ DELETE => 'CASCADE'}},
+ ],
+ INDEXES => [
+ mydashboard_namedquery_id_idx => {FIELDS => [qw(namedquery_id user_id)],
+ TYPE => 'UNIQUE'},
+ mydashboard_user_id_idx => ['user_id'],
+ ],
+ };
+}
+
+###########
+# Objects #
+###########
+
+BEGIN {
+ *Bugzilla::Search::Saved::in_mydashboard = \&_in_mydashboard;
+}
+
+sub _in_mydashboard {
+ my ($self) = @_;
+ my $dbh = Bugzilla->dbh;
+ return $self->{'in_mydashboard'} if exists $self->{'in_mydashboard'};
+ $self->{'in_mydashboard'} = $dbh->selectrow_array("
+ SELECT 1 FROM mydashboard WHERE namedquery_id = ? AND user_id = ?",
+ undef, $self->id, $self->user->id);
+ return $self->{'in_mydashboard'};
+}
+
+#############
+# Templates #
+#############
+
+sub page_before_template {
+ my ($self, $args) = @_;
+ my $page = $args->{'page_id'};
+ my $vars = $args->{'vars'};
+
+ return if $page ne 'mydashboard.html';
+
+ # If we're using bug groups to restrict bug entry, we need to know who the
+ # user is right from the start.
+ my $user = Bugzilla->login(LOGIN_REQUIRED);
+
+ # Switch to shadow db since we are just reading information
+ Bugzilla->switch_to_shadow_db();
+
+ _active_product_counts($vars);
+ _standard_saved_queries($vars);
+ _flags_requested($vars);
+
+ $vars->{'severities'} = get_legal_field_values('bug_severity');
+}
+
+our $_open_states;
+sub _open_states {
+ $_open_states ||= Bugzilla::Status->match({ is_open => 1, isactive => 1 });
+ return wantarray ? @$_open_states : $_open_states;
+}
+
+our $_quoted_open_states;
+sub _quoted_open_states {
+ my $dbh = Bugzilla->dbh;
+ $_quoted_open_states ||= [ map { $dbh->quote($_->name) } _open_states() ];
+ return wantarray ? @$_quoted_open_states : $_quoted_open_states;
+}
+
+sub _active_product_counts {
+ my ($vars) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+
+ my @enterable_products = @{$user->get_enterable_products()};
+ $vars->{'products'}
+ = $dbh->selectall_arrayref("SELECT products.name AS product, count(*) AS count
+ FROM bugs,products
+ WHERE bugs.product_id=products.id
+ AND products.isactive = 1
+ AND bugs.bug_status IN (" . join(',', _quoted_open_states()) . ")
+ AND products.id IN (" . join(',', map { $_->id } @enterable_products) . ")
+ GROUP BY products.name ORDER BY count DESC", { Slice => {} });
+
+ $vars->{'products_buffer'} = "&" . join('&', map { "bug_status=" . $_->name } _open_states());
+}
+
+sub _standard_saved_queries {
+ my ($vars) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+
+ # Default sort order
+ my $order = ["bug_id"];
+
+ # List of columns that we will be selecting. In the future this should be configurable
+ # Share with buglist.cgi?
+ my @select_columns = ('bug_id','product','bug_status','bug_severity','version', 'component','short_desc', 'changeddate');
+
+ # Define the columns that can be selected in a query
+ my $columns = Bugzilla::Search::COLUMNS;
+
+ # Weed out columns that don't actually exist and detaint along the way.
+ @select_columns = grep($columns->{$_} && trick_taint($_), @select_columns);
+
+ ### Standard query definitions
+ my @query_defs = QUERY_DEFS;
+
+ ### Saved query definitions
+ ### These are enabled through the userprefs.cgi UI
+ foreach my $q (@{$user->queries}) {
+ next if !$q->in_mydashboard;
+ push(@query_defs, { name => $q->name,
+ heading => $q->name,
+ saved => 1,
+ params => $q->url });
+ }
+
+ my $date_now = DateTime->now(time_zone => Bugzilla->local_timezone);
+
+ ### Collect the query results for display in the template
+
+ my @results;
+ foreach my $qdef (@query_defs) {
+ my $params = new Bugzilla::CGI($qdef->{params});
+
+ my $search = new Bugzilla::Search( fields => \@select_columns,
+ params => $params,
+ order => $order );
+ my $query = $search->sql();
+
+ my $sth = $dbh->prepare($query);
+ $sth->execute();
+
+ my $rows = $sth->fetchall_arrayref();
+
+ my @bugs;
+ foreach my $row (@$rows) {
+ my $bug = {};
+ foreach my $column (@select_columns) {
+ $bug->{$column} = shift @$row;
+ if ($column eq 'changeddate') {
+ my $date_then = datetime_from($bug->{$column});
+ $bug->{'updated'} = time_ago($date_then, $date_now);
+ }
+ }
+ push(@bugs, $bug);
+ }
+
+ $qdef->{bugs} = \@bugs;
+ $qdef->{buffer} = $params->canonicalise_query();
+
+ push(@results, $qdef);
+ }
+
+ $vars->{'results'} = \@results;
+}
+
+sub _flags_requested {
+ my ($vars) = @_;
+ my $user = Bugzilla->user;
+ my $dbh = Bugzilla->dbh;
+
+ my $attach_join_clause = "flags.attach_id = attachments.attach_id";
+ if (Bugzilla->params->{insidergroup} && !$user->in_group(Bugzilla->params->{insidergroup})) {
+ $attach_join_clause .= " AND attachments.isprivate < 1";
+ }
+
+ my $query =
+ # Select columns describing each flag, the bug/attachment on which
+ # it has been set, who set it, and of whom they are requesting it.
+ " SELECT flags.id AS id,
+ flagtypes.name AS type,
+ flags.status AS status,
+ flags.bug_id AS bug_id,
+ bugs.short_desc AS bug_summary,
+ flags.attach_id AS attach_id,
+ attachments.description AS attach_summary,
+ requesters.realname AS requester,
+ requestees.realname AS requestee,
+ " . $dbh->sql_date_format('flags.creation_date', '%Y.%m.%d %H:%i') . " AS created
+ FROM flags
+ LEFT JOIN attachments
+ ON ($attach_join_clause)
+ INNER JOIN flagtypes
+ ON flags.type_id = flagtypes.id
+ INNER JOIN bugs
+ ON flags.bug_id = bugs.bug_id
+ LEFT JOIN profiles AS requesters
+ ON flags.setter_id = requesters.userid
+ LEFT JOIN profiles AS requestees
+ ON flags.requestee_id = requestees.userid
+ LEFT JOIN bug_group_map AS bgmap
+ ON bgmap.bug_id = bugs.bug_id
+ LEFT JOIN cc AS ccmap
+ ON ccmap.who = " . $user->id . "
+ AND ccmap.bug_id = bugs.bug_id ";
+
+ # Limit query to pending requests and open bugs only
+ $query .= " WHERE bugs.bug_status IN (" . join(',', _quoted_open_states()) . ")
+ AND flags.status = '?' ";
+
+ # Weed out bug the user does not have access to
+ $query .= " AND ((bgmap.group_id IS NULL)
+ OR bgmap.group_id IN (" . $user->groups_as_string . ")
+ OR (ccmap.who IS NOT NULL AND cclist_accessible = 1)
+ OR (bugs.reporter = " . $user->id . " AND bugs.reporter_accessible = 1)
+ OR (bugs.assigned_to = " . $user->id .") ";
+ if (Bugzilla->params->{useqacontact}) {
+ $query .= " OR (bugs.qa_contact = " . $user->id . ") ";
+ }
+ $query .= ") ";
+
+ # Order the records (within each group).
+ my $group_order_by = " GROUP BY flags.bug_id ORDER BY flagtypes.name, flags.creation_date";
+
+ my $requestee_list = $dbh->selectall_arrayref($query .
+ " AND requestees.login_name = ? " .
+ $group_order_by,
+ { Slice => {} }, $user->login);
+ $vars->{'requestee_list'} = $requestee_list;
+ my $requester_list = $dbh->selectall_arrayref($query .
+ " AND requesters.login_name = ? " .
+ $group_order_by,
+ { Slice => {} }, $user->login);
+ $vars->{'requester_list'} = $requester_list;
+}
+
+#########
+# Hooks #
+#########
+
+sub user_preferences {
+ my ($self, $args) = @_;
+ my $tab = $args->{'current_tab'};
+ return unless $tab eq 'saved-searches';
+
+ my $save = $args->{'save_changes'};
+ my $handled = $args->{'handled'};
+ my $vars = $args->{'vars'};
+
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+ my $params = Bugzilla->input_params;
+
+ if ($save) {
+ my $sth_insert_fp = $dbh->prepare('INSERT INTO mydashboard
+ (namedquery_id, user_id)
+ VALUES (?, ?)');
+ my $sth_delete_fp = $dbh->prepare('DELETE FROM mydashboard
+ WHERE namedquery_id = ?
+ AND user_id = ?');
+ foreach my $q (@{$user->queries}, @{$user->queries_available}) {
+ if (defined $params->{'in_mydashboard_' . $q->id}) {
+ $sth_insert_fp->execute($q->id, $q->user->id) if !$q->in_mydashboard;
+ }
+ else {
+ $sth_delete_fp->execute($q->id, $q->user->id) if $q->in_mydashboard;
+ }
+ }
+ }
+}
+
+sub webservice {
+ my ($self, $args) = @_;
+ my $dispatch = $args->{dispatch};
+ $dispatch->{MyDashboard} = "Bugzilla::Extension::MyDashboard::WebService";
+}
+
+__PACKAGE__->NAME;