2
# -*- Mode: perl; indent-tabs-mode: nil -*-
4
# The contents of this file are subject to the Mozilla Public
5
# License Version 1.1 (the "License"); you may not use this file
6
# except in compliance with the License. You may obtain a copy of
7
# the License at http://www.mozilla.org/MPL/
9
# Software distributed under the License is distributed on an "AS
10
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11
# implied. See the License for the specific language governing
12
# rights and limitations under the License.
14
# The Original Code is the Bugzilla Bug Tracking System.
16
# The Initial Developer of the Original Code is Netscape Communications
17
# Corporation. Portions created by Netscape are
18
# Copyright (C) 1998 Netscape Communications Corporation. All
21
# Contributor(s): Erik Stambaugh <erik@dasbistro.com>
24
################################################################################
25
# Script Initialization
26
################################################################################
33
use Bugzilla::Constants;
40
# require the user to have logged in
41
my $user = Bugzilla->login(LOGIN_REQUIRED);
43
###############################################################################
45
###############################################################################
47
my $cgi = Bugzilla->cgi;
48
my $template = Bugzilla->template;
50
my $dbh = Bugzilla->dbh;
52
my $userid = $user->id;
53
my $token = $cgi->param('token');
54
my $sth; # database statement handle
56
# $events is a hash ref, keyed by event id, that stores the active user's
57
# events. It starts off with:
58
# 'subject' - the subject line for the email message
59
# 'body' - the text to be sent at the top of the message
61
# Eventually, it winds up with:
62
# 'queries' - array ref containing hashes of:
63
# 'name' - the name of the saved query
64
# 'title' - The title line for the search results table
65
# 'sort' - Numeric sort ID
66
# 'id' - row ID for the query entry
67
# 'onemailperbug' - whether a single message must be sent for each
69
# 'schedule' - array ref containing hashes of:
70
# 'day' - Day or range of days this schedule will be run
71
# 'time' - time or interval to run
72
# 'mailto_type' - MAILTO_USER or MAILTO_GROUP
73
# 'mailto' - person/group who will receive the results
74
# 'id' - row ID for the schedule
75
my $events = get_events($userid);
77
# First see if this user may use whines
78
$user->in_group('bz_canusewhines')
79
|| ThrowUserError("auth_failure", {group => "bz_canusewhines",
81
object => "reports"});
83
# May this user send mail to other users?
84
my $can_mail_others = Bugzilla->user->in_group('bz_canusewhineatothers');
86
# If the form was submitted, we need to look for what needs to be added or
87
# removed, then what was altered.
89
if ($cgi->param('update')) {
90
check_token_data($token, 'edit_whine');
92
if ($cgi->param("add_event")) {
93
# we create a new event
94
$sth = $dbh->prepare("INSERT INTO whine_events " .
97
$sth->execute($userid);
100
for my $eventid (keys %{$events}) {
101
# delete an entire event
102
if ($cgi->param("remove_event_$eventid")) {
103
# We need to make sure these belong to the same user,
104
# otherwise we could simply delete whatever matched that ID.
107
$sth = $dbh->prepare("SELECT whine_schedules.id " .
108
"FROM whine_schedules " .
109
"LEFT JOIN whine_events " .
110
"ON whine_events.id = " .
111
"whine_schedules.eventid " .
112
"WHERE whine_events.id = ? " .
113
"AND whine_events.owner_userid = ?");
114
$sth->execute($eventid, $userid);
115
my @ids = @{$sth->fetchall_arrayref};
116
$sth = $dbh->prepare("DELETE FROM whine_schedules "
119
my $delete_id = $_->[0];
120
$sth->execute($delete_id);
124
$sth = $dbh->prepare("SELECT whine_queries.id " .
125
"FROM whine_queries " .
126
"LEFT JOIN whine_events " .
127
"ON whine_events.id = " .
128
"whine_queries.eventid " .
129
"WHERE whine_events.id = ? " .
130
"AND whine_events.owner_userid = ?");
131
$sth->execute($eventid, $userid);
132
@ids = @{$sth->fetchall_arrayref};
133
$sth = $dbh->prepare("DELETE FROM whine_queries " .
136
my $delete_id = $_->[0];
137
$sth->execute($delete_id);
141
$sth = $dbh->prepare("DELETE FROM whine_events " .
142
"WHERE id=? AND owner_userid=?");
143
$sth->execute($eventid, $userid);
146
# check the subject and body for changes
147
my $subject = ($cgi->param("event_${eventid}_subject") or '');
148
my $body = ($cgi->param("event_${eventid}_body") or '');
150
trick_taint($subject) if $subject;
151
trick_taint($body) if $body;
153
if ( ($subject ne $events->{$eventid}->{'subject'})
154
|| ($body ne $events->{$eventid}->{'body'}) ) {
156
$sth = $dbh->prepare("UPDATE whine_events " .
157
"SET subject=?, body=? " .
159
$sth->execute($subject, $body, $eventid);
163
if ($cgi->param("add_schedule_$eventid")) {
164
# the schedule table must be locked before altering
165
$sth = $dbh->prepare("INSERT INTO whine_schedules " .
166
"(eventid, mailto_type, mailto, " .
167
"run_day, run_time) " .
168
"VALUES (?, ?, ?, 'Sun', 2)");
169
$sth->execute($eventid, MAILTO_USER, $userid);
172
elsif ($cgi->param("add_query_$eventid")) {
173
$sth = $dbh->prepare("INSERT INTO whine_queries "
176
$sth->execute($eventid);
180
# now check all of the schedules and queries to see if they need
181
# to be altered or deleted
183
# Check schedules for changes
184
$sth = $dbh->prepare("SELECT id " .
185
"FROM whine_schedules " .
187
$sth->execute($eventid);
188
my @scheduleids = ();
189
while (my ($sid) = $sth->fetchrow_array) {
190
push @scheduleids, $sid;
193
# we need to double-check all of the user IDs in mailto to make
195
my $arglist = {}; # args for match_field
196
for my $sid (@scheduleids) {
197
if ($cgi->param("mailto_type_$sid") == MAILTO_USER) {
198
$arglist->{"mailto_$sid"} = {
203
if (scalar %{$arglist}) {
204
&Bugzilla::User::match_field($cgi, $arglist);
207
for my $sid (@scheduleids) {
208
if ($cgi->param("remove_schedule_$sid")) {
209
# having the assignee id in here is a security failsafe
210
$sth = $dbh->prepare("SELECT whine_schedules.id " .
211
"FROM whine_schedules " .
212
"LEFT JOIN whine_events " .
213
"ON whine_events.id = " .
214
"whine_schedules.eventid " .
215
"WHERE whine_events.owner_userid=? " .
216
"AND whine_schedules.id =?");
217
$sth->execute($userid, $sid);
219
my @ids = @{$sth->fetchall_arrayref};
221
$sth = $dbh->prepare("DELETE FROM whine_schedules " .
223
$sth->execute($_->[0]);
227
my $o_day = $cgi->param("orig_day_$sid") || '';
228
my $day = $cgi->param("day_$sid") || '';
229
my $o_time = $cgi->param("orig_time_$sid") || 0;
230
my $time = $cgi->param("time_$sid") || 0;
231
my $o_mailto = $cgi->param("orig_mailto_$sid") || '';
232
my $mailto = $cgi->param("mailto_$sid") || '';
233
my $o_mailto_type = $cgi->param("orig_mailto_type_$sid") || 0;
234
my $mailto_type = $cgi->param("mailto_type_$sid") || 0;
236
my $mailto_id = $userid;
238
# get an id for the mailto address
239
if ($can_mail_others && $mailto) {
240
if ($mailto_type == MAILTO_USER) {
242
my $emailregexp = Bugzilla->params->{'emailregexp'};
243
if ($mailto =~ /($emailregexp)/) {
244
$mailto_id = login_to_id($1);
247
ThrowUserError("illegal_email_address",
248
{ addr => $mailto });
251
elsif ($mailto_type == MAILTO_GROUP) {
252
# detaint the group parameter
253
if ($mailto =~ /^([0-9a-z_\-\.]+)$/i) {
254
$mailto_id = Bugzilla::Group::ValidateGroupName(
257
'invalid_group_name',
260
ThrowUserError('invalid_group_name',
261
{ name => $mailto });
265
# bad value, so it will just mail to the whine
266
# owner. $mailto_id was already set above.
267
$mailto_type = MAILTO_USER;
271
detaint_natural($mailto_type);
273
if ( ($o_day ne $day) ||
274
($o_time ne $time) ||
275
($o_mailto ne $mailto) ||
276
($o_mailto_type != $mailto_type) ){
281
# the schedule table must be locked
282
$sth = $dbh->prepare("UPDATE whine_schedules " .
283
"SET run_day=?, run_time=?, " .
284
"mailto_type=?, mailto=?, " .
287
$sth->execute($day, $time, $mailto_type,
293
# Check queries for changes
294
$sth = $dbh->prepare("SELECT id " .
295
"FROM whine_queries " .
297
$sth->execute($eventid);
299
while (my ($qid) = $sth->fetchrow_array) {
303
for my $qid (@queries) {
304
if ($cgi->param("remove_query_$qid")) {
306
$sth = $dbh->prepare("SELECT whine_queries.id " .
307
"FROM whine_queries " .
308
"LEFT JOIN whine_events " .
309
"ON whine_events.id = " .
310
"whine_queries.eventid " .
311
"WHERE whine_events.owner_userid=? " .
312
"AND whine_queries.id =?");
313
$sth->execute($userid, $qid);
315
for (@{$sth->fetchall_arrayref}) {
316
$sth = $dbh->prepare("DELETE FROM whine_queries " .
318
$sth->execute($_->[0]);
322
my $o_sort = $cgi->param("orig_query_sort_$qid") || 0;
323
my $sort = $cgi->param("query_sort_$qid") || 0;
324
my $o_queryname = $cgi->param("orig_query_name_$qid") || '';
325
my $queryname = $cgi->param("query_name_$qid") || '';
326
my $o_title = $cgi->param("orig_query_title_$qid") || '';
327
my $title = $cgi->param("query_title_$qid") || '';
328
my $o_onemailperbug =
329
$cgi->param("orig_query_onemailperbug_$qid") || 0;
331
$cgi->param("query_onemailperbug_$qid") ? 1 : 0;
333
if ( ($o_sort != $sort) ||
334
($o_queryname ne $queryname) ||
335
($o_onemailperbug != $onemailperbug) ||
336
($o_title ne $title) ){
338
detaint_natural($sort);
339
trick_taint($queryname);
342
$sth = $dbh->prepare("UPDATE whine_queries " .
348
$sth->execute($sort, $queryname, $title,
349
$onemailperbug, $qid);
355
delete_token($token);
358
$vars->{'mail_others'} = $can_mail_others;
360
# Return the appropriate HTTP response headers.
361
print $cgi->header();
363
# Get events again, to cover any updates that were made
364
$events = get_events($userid);
366
# Here is the data layout as sent to the template:
379
# build the whine list by event id
380
for my $event_id (keys %{$events}) {
382
$events->{$event_id}->{'schedule'} = [];
383
$events->{$event_id}->{'queries'} = [];
386
$sth = $dbh->prepare("SELECT run_day, run_time, mailto_type, mailto, id " .
387
"FROM whine_schedules " .
389
$sth->execute($event_id);
390
for my $row (@{$sth->fetchall_arrayref}) {
391
my $mailto_type = $row->[2];
393
if ($mailto_type == MAILTO_USER) {
394
my $mailto_user = new Bugzilla::User($row->[3]);
395
$mailto = $mailto_user->login;
397
elsif ($mailto_type == MAILTO_GROUP) {
398
$sth = $dbh->prepare("SELECT name FROM groups WHERE id=?");
399
$sth->execute($row->[3]);
400
$mailto = $sth->fetch->[0];
401
$mailto = "" unless Bugzilla::Group::ValidateGroupName(
404
my $this_schedule = {
407
'mailto_type' => $mailto_type,
411
push @{$events->{$event_id}->{'schedule'}}, $this_schedule;
415
$sth = $dbh->prepare("SELECT query_name, title, sortkey, id, " .
417
"FROM whine_queries " .
420
$sth->execute($event_id);
421
for my $row (@{$sth->fetchall_arrayref}) {
424
'title' => $row->[1],
427
'onemailperbug' => $row->[4],
429
push @{$events->{$event_id}->{'queries'}}, $this_query;
433
$vars->{'events'} = $events;
435
# get the available queries
436
$sth = $dbh->prepare("SELECT name FROM namedqueries WHERE userid=?");
437
$sth->execute($userid);
439
$vars->{'available_queries'} = [];
440
while (my ($query) = $sth->fetchrow_array) {
441
push @{$vars->{'available_queries'}}, $query;
443
$vars->{'token'} = issue_session_token('edit_whine');
445
$template->process("whine/schedule.html.tmpl", $vars)
446
|| ThrowTemplateError($template->error());
448
# get_events takes a userid and returns a hash, keyed by event ID, containing
449
# the subject and body of each event that user owns
452
my $dbh = Bugzilla->dbh;
455
my $sth = $dbh->prepare("SELECT DISTINCT id, subject, body " .
456
"FROM whine_events " .
457
"WHERE owner_userid=?");
458
$sth->execute($userid);
459
while (my ($ev, $sub, $bod) = $sth->fetchrow_array) {
461
'subject' => $sub || '',
462
'body' => $bod || '',