123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- #!/usr/bin/env perl -wT
- # -*- Mode: perl; indent-tabs-mode: nil -*-
- #
- # The contents of this file are subject to the Mozilla Public
- # License Version 1.1 (the "License"); you may not use this file
- # except in compliance with the License. You may obtain a copy of
- # the License at http://www.mozilla.org/MPL/
- #
- # Software distributed under the License is distributed on an "AS
- # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- # implied. See the License for the specific language governing
- # rights and limitations under the License.
- #
- # The Original Code is the Bugzilla Bug Tracking System.
- #
- # The Initial Developer of the Original Code is Netscape Communications
- # Corporation. Portions created by Netscape are
- # Copyright (C) 1998 Netscape Communications Corporation. All
- # Rights Reserved.
- #
- # Contributor(s): Erik Stambaugh <erik@dasbistro.com>
- #
- ################################################################################
- # Script Initialization
- ################################################################################
- use strict;
- use lib qw(. lib);
- use Bugzilla;
- use Bugzilla::Constants;
- use Bugzilla::Util;
- use Bugzilla::Error;
- use Bugzilla::User;
- use Bugzilla::Group;
- use Bugzilla::Token;
- # 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, keyed by event id, that stores the active user's
- # events. It starts off with:
- # 'subject' - the subject line for the email message
- # 'body' - the text to be sent at the top of the message
- #
- # 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 = Bugzilla->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
- $sth = $dbh->prepare("SELECT whine_schedules.id " .
- "FROM whine_schedules " .
- "LEFT JOIN whine_events " .
- "ON whine_events.id = " .
- "whine_schedules.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_schedules "
- . "WHERE id=?");
- for (@ids) {
- my $delete_id = $_->[0];
- $sth->execute($delete_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);
- @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 and body for changes
- my $subject = ($cgi->param("event_${eventid}_subject") or '');
- my $body = ($cgi->param("event_${eventid}_body") or '');
- trick_taint($subject) if $subject;
- trick_taint($body) if $body;
- if ( ($subject ne $events->{$eventid}->{'subject'})
- || ($body ne $events->{$eventid}->{'body'}) ) {
- $sth = $dbh->prepare("UPDATE whine_events " .
- "SET subject=?, body=? " .
- "WHERE id=?");
- $sth->execute($subject, $body, $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
- $sth = $dbh->prepare("SELECT id " .
- "FROM whine_schedules " .
- "WHERE eventid=?");
- $sth->execute($eventid);
- my @scheduleids = ();
- while (my ($sid) = $sth->fetchrow_array) {
- push @scheduleids, $sid;
- }
- # 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($cgi, $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) {
- # The user login has already been validated.
- $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
- $sth = $dbh->prepare("SELECT id " .
- "FROM whine_queries " .
- "WHERE eventid=?");
- $sth->execute($eventid);
- my @queries = ();
- while (my ($qid) = $sth->fetchrow_array) {
- push @queries, $qid;
- }
- for my $qid (@queries) {
- 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
- $sth = $dbh->prepare("SELECT run_day, run_time, mailto_type, mailto, id " .
- "FROM whine_schedules " .
- "WHERE eventid=?");
- $sth->execute($event_id);
- for my $row (@{$sth->fetchall_arrayref}) {
- my $mailto_type = $row->[2];
- my $mailto = '';
- if ($mailto_type == MAILTO_USER) {
- my $mailto_user = new Bugzilla::User($row->[3]);
- $mailto = $mailto_user->login;
- }
- elsif ($mailto_type == MAILTO_GROUP) {
- $sth = $dbh->prepare("SELECT name FROM groups WHERE id=?");
- $sth->execute($row->[3]);
- $mailto = $sth->fetch->[0];
- $mailto = "" unless Bugzilla::Group::ValidateGroupName(
- $mailto, ($user));
- }
- my $this_schedule = {
- 'day' => $row->[0],
- 'time' => $row->[1],
- 'mailto_type' => $mailto_type,
- 'mailto' => $mailto,
- 'id' => $row->[4],
- };
- push @{$events->{$event_id}->{'schedule'}}, $this_schedule;
- }
- # queries
- $sth = $dbh->prepare("SELECT query_name, title, sortkey, id, " .
- "onemailperbug " .
- "FROM whine_queries " .
- "WHERE eventid=? " .
- "ORDER BY sortkey");
- $sth->execute($event_id);
- for my $row (@{$sth->fetchall_arrayref}) {
- my $this_query = {
- 'name' => $row->[0],
- 'title' => $row->[1],
- 'sort' => $row->[2],
- 'id' => $row->[3],
- 'onemailperbug' => $row->[4],
- };
- push @{$events->{$event_id}->{'queries'}}, $this_query;
- }
- }
- $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');
- $template->process("whine/schedule.html.tmpl", $vars)
- || ThrowTemplateError($template->error());
- # get_events takes a userid and returns a hash, keyed by event ID, containing
- # the subject and body of each event that user owns
- sub get_events {
- my $userid = shift;
- my $dbh = Bugzilla->dbh;
- my $events = {};
- my $sth = $dbh->prepare("SELECT DISTINCT id, subject, body " .
- "FROM whine_events " .
- "WHERE owner_userid=?");
- $sth->execute($userid);
- while (my ($ev, $sub, $bod) = $sth->fetchrow_array) {
- $events->{$ev} = {
- 'subject' => $sub || '',
- 'body' => $bod || '',
- };
- }
- return $events;
- }
|