From 2838dad07581a783cfb4bcf32a2c003e22cb13e5 Mon Sep 17 00:00:00 2001 From: Dave Lawrence Date: Wed, 28 Mar 2012 17:23:41 -0400 Subject: Bug 678146: Tell-Us-More extension --- extensions/TellUsMore/lib/Process.pm | 263 +++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 extensions/TellUsMore/lib/Process.pm (limited to 'extensions/TellUsMore/lib/Process.pm') diff --git a/extensions/TellUsMore/lib/Process.pm b/extensions/TellUsMore/lib/Process.pm new file mode 100644 index 000000000..a73866468 --- /dev/null +++ b/extensions/TellUsMore/lib/Process.pm @@ -0,0 +1,263 @@ +# 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::TellUsMore::Process; + +use strict; +use warnings; + +use Bugzilla::Bug; +use Bugzilla::Component; +use Bugzilla::Constants; +use Bugzilla::Error; +use Bugzilla::Hook; +use Bugzilla::Product; +use Bugzilla::User; +use Bugzilla::Util; +use Bugzilla::Version; + +use Bugzilla::Extension::TellUsMore::Constants; + +use Data::Dumper; +use File::Basename; +use MIME::Base64; +use Safe; + +sub new { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my $object = {}; + bless($object, $class); + return $object; +} + +sub execute { + my ($self, $token) = @_; + my $dbh = Bugzilla->dbh; + + my ($bug, $user, $is_new_user); + Bugzilla->error_mode(ERROR_MODE_DIE); + eval { + $self->_delete_stale_issues(); + my ($mail, $params) = $self->_deserialise_token($token); + + $dbh->bz_start_transaction(); + + $self->_fix_invalid_params($params); + + ($user, $is_new_user) = $self->_get_user($mail, $params); + + $bug = $self->_create_bug($user, $params); + $self->_post_bug_hook($bug); + + $self->_delete_token($token); + $dbh->bz_commit_transaction(); + + $self->_send_mail($bug, $user); + }; + $self->{error} = $@; + Bugzilla->error_mode(ERROR_MODE_WEBPAGE); + return $self->{error} ? undef : ($bug, $is_new_user); +} + +sub error { + my ($self) = @_; + return $self->{error}; +} + +sub _delete_stale_issues { + my ($self) = @_; + my $dbh = Bugzilla->dbh; + + # delete issues older than TOKEN_EXPIRY_DAYS + + $dbh->do(" + DELETE FROM tell_us_more + WHERE creation_ts < NOW() - " . + $dbh->sql_interval(TOKEN_EXPIRY_DAYS, 'DAY') + ); +} + +sub _deserialise_token { + my ($self, $token) = @_; + my $dbh = Bugzilla->dbh; + + # validate token + + trick_taint($token); + my ($mail, $params) = $dbh->selectrow_array( + "SELECT mail,content FROM tell_us_more WHERE token=?", + undef, $token + ); + ThrowUserError('token_does_not_exist') unless $mail; + + # deserialise, return ($mail, $params) + + my $compartment = Safe->new(); + $compartment->reval($params) + || ThrowUserError('token_does_not_exist'); + $params = ${$compartment->varglob('VAR1')}; + + return ($mail, $params); +} + +sub _fix_invalid_params { + my ($self, $params) = @_; + + # silently adjust any params which are no longer valid + # so we don't lose the submission + + my $product = Bugzilla::Product->new({ name => TARGET_PRODUCT }) + || ThrowUserError('invalid_product_name', { product => TARGET_PRODUCT }); + + # component --> general + + my $component = Bugzilla::Component->new({ product => $product, name => $params->{component} }) + || Bugzilla::Component->new({ product => $product, name => DEFAULT_COMPONENT }) + || ThrowUserError('tum_invalid_component', { product => TARGET_PRODUCT, name => DEFAULT_COMPONENT }); + $params->{component} = $component->name; + + # version --> unspecified + + my $version = Bugzilla::Version->new({ product => $product, name => $params->{version} }) + || Bugzilla::Version->new({ product => $product, name => DEFAULT_VERSION }); + $params->{version} = $version->name; +} + +sub _get_user { + my ($self, $mail, $params) = @_; + + # return existing bmo user + + my $user = Bugzilla::User->new({ name => $mail }); + return ($user, 0) if $user; + + # or create new user + + $user = Bugzilla::User->create({ + login_name => $mail, + cryptpassword => '*', + realname => $params->{creator_name}, + }); + return ($user, 1); +} + +sub _create_bug { + my ($self, $user, $params) = @_; + my $template = Bugzilla->template; + my $vars = {}; + + # login as the user + + Bugzilla->set_user($user); + + # create the bug + + my $create = { + product => $params->{product}, + component => $params->{component}, + short_desc => $params->{summary}, + comment => $params->{description}, + version => $params->{version}, + rep_platform => $params->{rep_platform}, + op_sys => $params->{op_sys}, + bug_severity => $params->{bug_severity}, + priority => $params->{priority}, + bug_file_loc => $params->{bug_file_loc}, + }; + if ($params->{group}) { + $create->{groups} = [ $params->{group} ]; + }; + + my $bug = Bugzilla::Bug->create($create); + + # add attachments + + foreach my $attachment (@{$params->{attachments}}) { + $self->_add_attachment($bug, $attachment); + } + if (scalar @{$params->{attachments}}) { + $bug->update(); + } + + return $bug; +} + +sub _add_attachment { + my ($self, $bug, $params) = @_; + my $dbh = Bugzilla->dbh; + + # init + + my $timestamp = $dbh->selectrow_array('SELECT creation_ts FROM bugs WHERE bug_id=?', undef, $bug->bug_id); + my $data = decode_base64($params->{content}); + + my $description; + if ($params->{description}) { + $description = $params->{description}; + } else { + $description = $params->{filename}; + $description =~ s/\\/\//g; + $description = basename($description); + } + + # trigger content-type auto detection + + Bugzilla->input_params->{'contenttypemethod'} = 'autodetect'; + + # add attachment + + my $attachment = Bugzilla::Attachment->create({ + bug => $bug, + creation_ts => $timestamp, + data => $data, + description => $description, + filename => $params->{filename}, + mimetype => $params->{content_type}, + }); + + # add comment + + $bug->add_comment('', { + isprivate => 0, + type => CMT_ATTACHMENT_CREATED, + extra_data => $attachment->id, + }); +} + +sub _post_bug_hook { + my ($self, $bug) = @_; + + # trigger post_bug_after_creation hook + + my $vars = { + id => $bug->bug_id, + bug => $bug, + }; + Bugzilla::Hook::process('post_bug_after_creation', { vars => $vars }); +} + +sub _send_mail { + my ($self, $bug, $user) = @_; + + # send new-bug email + + Bugzilla::BugMail::Send($bug->bug_id, { changer => $user }); +} + +sub _delete_token { + my ($self, $token) = @_; + my $dbh = Bugzilla->dbh; + + # delete token + + trick_taint($token); + $dbh->do('DELETE FROM tell_us_more WHERE token=?', undef, $token); +} + +1; + -- cgit v1.2.3-24-g4f1b