blob: b11c44949c17f4ba57c6860bba0f40a431a017f8 [file] [log] [blame]
#!/usr/bin/perl -T
# 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.
################################################################################
# Script Initialization
################################################################################
use 5.10.1;
use strict;
use warnings;
use lib qw(. lib);
use Bugzilla;
use Bugzilla::Constants;
use Bugzilla::Util;
use Bugzilla::Error;
use Bugzilla::User;
use Bugzilla::Group;
use Bugzilla::Token;
use Bugzilla::Whine::Schedule;
use Bugzilla::Whine::Query;
use Bugzilla::Whine;
use DateTime;
# require the user to have logged in
my $user = Bugzilla->login(LOGIN_REQUIRED);
###############################################################################
# Main Body Execution
###############################################################################
my $cgi = Bugzilla->cgi;
my $template = Bugzilla->template;
my $vars = {};
my $dbh = Bugzilla->dbh;
my $userid = $user->id;
my $token = $cgi->param('token');
my $sth; # database statement handle
# $events is a hash ref of Bugzilla::Whine objects keyed by event id,
# that stores the active user's events.
#
# Eventually, it winds up with:
# 'queries' - array ref containing hashes of:
# 'name' - the name of the saved query
# 'title' - The title line for the search results table
# 'sort' - Numeric sort ID
# 'id' - row ID for the query entry
# 'onemailperbug' - whether a single message must be sent for each
# result.
# 'schedule' - array ref containing hashes of:
# 'day' - Day or range of days this schedule will be run
# 'time' - time or interval to run
# 'mailto_type' - MAILTO_USER or MAILTO_GROUP
# 'mailto' - person/group who will receive the results
# 'id' - row ID for the schedule
my $events = get_events($userid);
# First see if this user may use whines
$user->in_group('bz_canusewhines')
|| ThrowUserError("auth_failure", {group => "bz_canusewhines",
action => "schedule",
object => "reports"});
# May this user send mail to other users?
my $can_mail_others = $user->in_group('bz_canusewhineatothers');
# If the form was submitted, we need to look for what needs to be added or
# removed, then what was altered.
if ($cgi->param('update')) {
check_token_data($token, 'edit_whine');
if ($cgi->param("add_event")) {
# we create a new event
$sth = $dbh->prepare("INSERT INTO whine_events " .
"(owner_userid) " .
"VALUES (?)");
$sth->execute($userid);
}
else {
for my $eventid (keys %{$events}) {
# delete an entire event
if ($cgi->param("remove_event_$eventid")) {
# We need to make sure these belong to the same user,
# otherwise we could simply delete whatever matched that ID.
#
# schedules
my $schedules = Bugzilla::Whine::Schedule->match({ eventid => $eventid });
$sth = $dbh->prepare("DELETE FROM whine_schedules "
. "WHERE id=?");
foreach my $schedule (@$schedules) {
$sth->execute($schedule->id);
}
# queries
$sth = $dbh->prepare("SELECT whine_queries.id " .
"FROM whine_queries " .
"LEFT JOIN whine_events " .
"ON whine_events.id = " .
"whine_queries.eventid " .
"WHERE whine_events.id = ? " .
"AND whine_events.owner_userid = ?");
$sth->execute($eventid, $userid);
my @ids = @{$sth->fetchall_arrayref};
$sth = $dbh->prepare("DELETE FROM whine_queries " .
"WHERE id=?");
for (@ids) {
my $delete_id = $_->[0];
$sth->execute($delete_id);
}
# events
$sth = $dbh->prepare("DELETE FROM whine_events " .
"WHERE id=? AND owner_userid=?");
$sth->execute($eventid, $userid);
}
else {
# check the subject, body and mailifnobugs for changes
my $subject = ($cgi->param("event_${eventid}_subject") or '');
my $body = ($cgi->param("event_${eventid}_body") or '');
my $mailifnobugs = $cgi->param("event_${eventid}_mailifnobugs") ? 1 : 0;
trick_taint($subject) if $subject;
trick_taint($body) if $body;
if ( ($subject ne $events->{$eventid}->subject)
|| ($mailifnobugs != $events->{$eventid}->mail_if_no_bugs)
|| ($body ne $events->{$eventid}->body) ) {
$sth = $dbh->prepare("UPDATE whine_events " .
"SET subject=?, body=?, mailifnobugs=? " .
"WHERE id=?");
$sth->execute($subject, $body, $mailifnobugs, $eventid);
}
# add a schedule
if ($cgi->param("add_schedule_$eventid")) {
# the schedule table must be locked before altering
$sth = $dbh->prepare("INSERT INTO whine_schedules " .
"(eventid, mailto_type, mailto, " .
"run_day, run_time) " .
"VALUES (?, ?, ?, 'Sun', 2)");
$sth->execute($eventid, MAILTO_USER, $userid);
}
# add a query
elsif ($cgi->param("add_query_$eventid")) {
$sth = $dbh->prepare("INSERT INTO whine_queries "
. "(eventid) "
. "VALUES (?)");
$sth->execute($eventid);
}
}
# now check all of the schedules and queries to see if they need
# to be altered or deleted
# Check schedules for changes
my $schedules = Bugzilla::Whine::Schedule->match({ eventid => $eventid });
my @scheduleids = ();
foreach my $schedule (@$schedules) {
push @scheduleids, $schedule->id;
}
# we need to double-check all of the user IDs in mailto to make
# sure they exist
my $arglist = {}; # args for match_field
for my $sid (@scheduleids) {
if ($cgi->param("mailto_type_$sid") == MAILTO_USER) {
$arglist->{"mailto_$sid"} = {
'type' => 'single',
};
}
}
if (scalar %{$arglist}) {
Bugzilla::User::match_field($arglist);
}
for my $sid (@scheduleids) {
if ($cgi->param("remove_schedule_$sid")) {
# having the assignee id in here is a security failsafe
$sth = $dbh->prepare("SELECT whine_schedules.id " .
"FROM whine_schedules " .
"LEFT JOIN whine_events " .
"ON whine_events.id = " .
"whine_schedules.eventid " .
"WHERE whine_events.owner_userid=? " .
"AND whine_schedules.id =?");
$sth->execute($userid, $sid);
my @ids = @{$sth->fetchall_arrayref};
for (@ids) {
$sth = $dbh->prepare("DELETE FROM whine_schedules " .
"WHERE id=?");
$sth->execute($_->[0]);
}
}
else {
my $o_day = $cgi->param("orig_day_$sid") || '';
my $day = $cgi->param("day_$sid") || '';
my $o_time = $cgi->param("orig_time_$sid") || 0;
my $time = $cgi->param("time_$sid") || 0;
my $o_mailto = $cgi->param("orig_mailto_$sid") || '';
my $mailto = $cgi->param("mailto_$sid") || '';
my $o_mailto_type = $cgi->param("orig_mailto_type_$sid") || 0;
my $mailto_type = $cgi->param("mailto_type_$sid") || 0;
my $mailto_id = $userid;
# get an id for the mailto address
if ($can_mail_others && $mailto) {
if ($mailto_type == MAILTO_USER) {
$mailto_id = login_to_id($mailto);
}
elsif ($mailto_type == MAILTO_GROUP) {
# The group name is used in a placeholder.
trick_taint($mailto);
$mailto_id = Bugzilla::Group::ValidateGroupName($mailto, ($user))
|| ThrowUserError('invalid_group_name', { name => $mailto });
}
else {
# bad value, so it will just mail to the whine
# owner. $mailto_id was already set above.
$mailto_type = MAILTO_USER;
}
}
detaint_natural($mailto_type);
if ( ($o_day ne $day) ||
($o_time ne $time) ||
($o_mailto ne $mailto) ||
($o_mailto_type != $mailto_type) ){
trick_taint($day);
trick_taint($time);
# the schedule table must be locked
$sth = $dbh->prepare("UPDATE whine_schedules " .
"SET run_day=?, run_time=?, " .
"mailto_type=?, mailto=?, " .
"run_next=NULL " .
"WHERE id=?");
$sth->execute($day, $time, $mailto_type,
$mailto_id, $sid);
}
}
}
# Check queries for changes
my $queries = Bugzilla::Whine::Query->match({ eventid => $eventid });
for my $query (@$queries) {
my $qid = $query->id;
if ($cgi->param("remove_query_$qid")) {
$sth = $dbh->prepare("SELECT whine_queries.id " .
"FROM whine_queries " .
"LEFT JOIN whine_events " .
"ON whine_events.id = " .
"whine_queries.eventid " .
"WHERE whine_events.owner_userid=? " .
"AND whine_queries.id =?");
$sth->execute($userid, $qid);
for (@{$sth->fetchall_arrayref}) {
$sth = $dbh->prepare("DELETE FROM whine_queries " .
"WHERE id=?");
$sth->execute($_->[0]);
}
}
else {
my $o_sort = $cgi->param("orig_query_sort_$qid") || 0;
my $sort = $cgi->param("query_sort_$qid") || 0;
my $o_queryname = $cgi->param("orig_query_name_$qid") || '';
my $queryname = $cgi->param("query_name_$qid") || '';
my $o_title = $cgi->param("orig_query_title_$qid") || '';
my $title = $cgi->param("query_title_$qid") || '';
my $o_onemailperbug =
$cgi->param("orig_query_onemailperbug_$qid") || 0;
my $onemailperbug =
$cgi->param("query_onemailperbug_$qid") ? 1 : 0;
if ( ($o_sort != $sort) ||
($o_queryname ne $queryname) ||
($o_onemailperbug != $onemailperbug) ||
($o_title ne $title) ){
detaint_natural($sort);
trick_taint($queryname);
trick_taint($title);
$sth = $dbh->prepare("UPDATE whine_queries " .
"SET sortkey=?, " .
"query_name=?, " .
"title=?, " .
"onemailperbug=? " .
"WHERE id=?");
$sth->execute($sort, $queryname, $title,
$onemailperbug, $qid);
}
}
}
}
}
delete_token($token);
}
$vars->{'mail_others'} = $can_mail_others;
# Return the appropriate HTTP response headers.
print $cgi->header();
# Get events again, to cover any updates that were made
$events = get_events($userid);
# Here is the data layout as sent to the template:
#
# events
# event_id #
# schedule
# day
# time
# mailto
# queries
# name
# title
# sort
#
# build the whine list by event id
for my $event_id (keys %{$events}) {
$events->{$event_id}->{'schedule'} = [];
$events->{$event_id}->{'queries'} = [];
# schedules
my $schedules = Bugzilla::Whine::Schedule->match({ eventid => $event_id });
foreach my $schedule (@$schedules) {
my $mailto_type = $schedule->mailto_is_group ? MAILTO_GROUP
: MAILTO_USER;
my $mailto = '';
if ($mailto_type == MAILTO_USER) {
$mailto = $schedule->mailto->login;
}
elsif ($mailto_type == MAILTO_GROUP) {
$mailto = $schedule->mailto->name;
}
push @{$events->{$event_id}->{'schedule'}},
{
'day' => $schedule->run_day,
'time' => $schedule->run_time,
'mailto_type' => $mailto_type,
'mailto' => $mailto,
'id' => $schedule->id,
};
}
# queries
my $queries = Bugzilla::Whine::Query->match({ eventid => $event_id });
for my $query (@$queries) {
push @{$events->{$event_id}->{'queries'}},
{
'name' => $query->name,
'title' => $query->title,
'sort' => $query->sortkey,
'id' => $query->id,
'onemailperbug' => $query->one_email_per_bug,
};
}
}
$vars->{'events'} = $events;
# get the available queries
$sth = $dbh->prepare("SELECT name FROM namedqueries WHERE userid=?");
$sth->execute($userid);
$vars->{'available_queries'} = [];
while (my ($query) = $sth->fetchrow_array) {
push @{$vars->{'available_queries'}}, $query;
}
$vars->{'token'} = issue_session_token('edit_whine');
$vars->{'local_timezone'} = Bugzilla->local_timezone->short_name_for_datetime(DateTime->now());
$template->process("whine/schedule.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
# get_events takes a userid and returns a hash of
# Bugzilla::Whine objects keyed by event ID.
sub get_events {
my $userid = shift;
my $event_rows = Bugzilla::Whine->match({ owner_userid => $userid });
my %events = map { $_->{id} => $_ } @$event_rows;
return \%events;
}