зеркало из https://github.com/mozilla/gecko-dev.git
408 строки
11 KiB
Perl
408 строки
11 KiB
Perl
# -*- 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 Test Runner System.
|
|
#
|
|
# The Initial Developer of the Original Code is Maciej Maczynski.
|
|
# Portions created by Maciej Maczynski are Copyright (C) 2001
|
|
# Maciej Maczynski. All Rights Reserved.
|
|
#
|
|
# Large portions lifted uncerimoniously from Bugzilla::Attachment.pm
|
|
# and bugzilla's attachment.cgi
|
|
# Which are copyrighted by their respective copyright holders:
|
|
# Terry Weissman <terry@mozilla.org>
|
|
# Myk Melez <myk@mozilla.org>
|
|
# Daniel Raichle <draichle@gmx.net>
|
|
# Dave Miller <justdave@syndicomm.com>
|
|
# Alexander J. Vincent <ajvincent@juno.com>
|
|
# Max Kanat-Alexander <mkanat@bugzilla.org>
|
|
# Greg Hendricks <ghendricks@novell.com>
|
|
#
|
|
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
|
|
|
|
=head1 NAME
|
|
|
|
Bugzilla::Testopia::Attachment - Attachment object for Testopia
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
This module provides support for attachments to Test Cases and Test
|
|
Plans in Testopia.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
$attachment = Bugzilla::Testopia::Attachment->new($attachment_id);
|
|
$attachment = Bugzilla::Testopia::Attachment->new(\%attachment_hash);
|
|
|
|
=cut
|
|
|
|
package Bugzilla::Testopia::Attachment;
|
|
|
|
use strict;
|
|
|
|
use Bugzilla::Util;
|
|
use Bugzilla::Config;
|
|
|
|
use base qw(Exporter);
|
|
|
|
###############################
|
|
#### Initialization ####
|
|
###############################
|
|
|
|
=head1 FIELDS
|
|
|
|
attachment_id
|
|
plan_id
|
|
case_id
|
|
submitter_id
|
|
description
|
|
filename
|
|
creation_ts
|
|
mime_type
|
|
|
|
=cut
|
|
|
|
use constant DB_COLUMNS => qw(
|
|
test_attachments.attachment_id
|
|
test_attachments.plan_id
|
|
test_attachments.case_id
|
|
test_attachments.submitter_id
|
|
test_attachments.description
|
|
test_attachments.filename
|
|
test_attachments.creation_ts
|
|
test_attachments.mime_type
|
|
);
|
|
|
|
our $columns = join(", ", DB_COLUMNS);
|
|
|
|
|
|
###############################
|
|
#### Methods ####
|
|
###############################
|
|
|
|
=head1 METHODS
|
|
|
|
=head2 new
|
|
|
|
Instantiates a new Attachment object
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my $invocant = shift;
|
|
my $class = ref($invocant) || $invocant;
|
|
my $self = {};
|
|
bless($self, $class);
|
|
return $self->_init(@_);
|
|
}
|
|
|
|
=head2 _init
|
|
|
|
Private constructor for attachment class
|
|
|
|
=cut
|
|
|
|
sub _init {
|
|
my $self = shift;
|
|
my ($param) = (@_);
|
|
my $dbh = Bugzilla->dbh;
|
|
|
|
my $id = $param unless (ref $param eq 'HASH');
|
|
my $obj;
|
|
|
|
if (defined $id && detaint_natural($id)) {
|
|
|
|
$obj = $dbh->selectrow_hashref(qq{
|
|
SELECT $columns FROM test_attachments
|
|
WHERE attachment_id = ?}, undef, $id);
|
|
} elsif (ref $param eq 'HASH'){
|
|
$obj = $param;
|
|
} else {
|
|
ThrowCodeError('bad_arg',
|
|
{argument => 'param',
|
|
function => 'Testopia::Attachment::_init'});
|
|
}
|
|
|
|
return undef unless (defined $obj);
|
|
|
|
foreach my $field (keys %$obj) {
|
|
$self->{$field} = $obj->{$field};
|
|
}
|
|
return $self;
|
|
}
|
|
|
|
=head2 store
|
|
|
|
Serializes this attachment to the database
|
|
|
|
=cut
|
|
|
|
sub store {
|
|
my ($self) = @_;
|
|
if (!$self->{'case_id'} && !$self->{'plan_id'}){
|
|
ThrowUserError("testopia-missing-attachment-key");
|
|
}
|
|
$self->_validate_data;
|
|
$self->{'filename'} = $self->strip_path($self->{'filename'});
|
|
my $dbh = Bugzilla->dbh;
|
|
my ($timestamp) = Bugzilla::Testopia::Util::get_time_stamp();
|
|
|
|
$dbh->do("INSERT INTO test_attachments ($columns)
|
|
VALUES (?,?,?,?,?,?,?,?)",
|
|
undef, "NULL", $self->{'plan_id'}, $self->{'case_id'},
|
|
$self->{'submitter_id'}, $self->{'description'},
|
|
$self->{'filename'}, $timestamp, $self->{'mime_type'});
|
|
|
|
my $key = $dbh->bz_last_key( 'test_attachments', 'attachment_id' );
|
|
$dbh->do("INSERT INTO test_attachment_data VALUES(?,?)",
|
|
undef, $key, $self->{'contents'});
|
|
|
|
return $key;
|
|
}
|
|
|
|
=head2 _validate_data
|
|
|
|
Private method for validating attachment data. Checks that size
|
|
limit is not exceeded and converts uncompressed BMP to PNG
|
|
|
|
=cut
|
|
|
|
sub _validate_data {
|
|
my $self = shift;
|
|
my $maxsize = Param('maxattachmentsize');
|
|
$maxsize *= 1024; # Convert from K
|
|
|
|
# Windows screenshots are usually uncompressed BMP files which
|
|
# makes for a quick way to eat up disk space. Let's compress them.
|
|
# We do this before we check the size since the uncompressed version
|
|
# could easily be greater than maxattachmentsize.
|
|
if (Param('convert_uncompressed_images')
|
|
&& $self->{'mime_type'} eq 'image/bmp'){
|
|
require Image::Magick;
|
|
my $img = Image::Magick->new(magick=>'bmp');
|
|
$img->BlobToImage($self->{'contents'});
|
|
$img->set(magick=>'png');
|
|
my $imgdata = $img->ImageToBlob();
|
|
$self->{'contents'} = $imgdata;
|
|
$self->{'contenttype'} = 'image/png';
|
|
}
|
|
|
|
# Make sure the attachment does not exceed the maximum permitted size
|
|
my $len = $self->{'contents'} ? length($self->{'contents'}) : 0;
|
|
if ($maxsize && $len > $maxsize) {
|
|
my $vars = { filesize => sprintf("%.0f", $len/1024) };
|
|
ThrowUserError("file_too_large", $vars);
|
|
}
|
|
trick_taint($self->{'contents'});
|
|
|
|
}
|
|
|
|
=head2 strip_path
|
|
|
|
Strips the path from a filename, everything up to the last / or \.
|
|
Note: this was copied directly from bugzilla.
|
|
|
|
=cut
|
|
|
|
sub strip_path {
|
|
my $self = shift;
|
|
my ($filename) = @_;
|
|
|
|
# Remove path info (if any) from the file name. The browser should do this
|
|
# for us, but some are buggy. This may not work on Mac file names and could
|
|
# mess up file names with slashes in them, but them's the breaks. We only
|
|
# use this as a hint to users downloading attachments anyway, so it's not
|
|
# a big deal if it munges incorrectly occasionally.
|
|
$filename =~ s/^.*[\/\\]//;
|
|
|
|
# Truncate the filename to 100 characters, counting from the end of the string
|
|
# to make sure we keep the filename extension.
|
|
$filename = substr($filename, -100, 100);
|
|
|
|
trick_taint($filename);
|
|
return $filename;
|
|
|
|
}
|
|
|
|
=head2 isViewable
|
|
|
|
Returns true if the content type (mime-type) is viewable in a browser
|
|
text/* and img for the most part are viewable, All others are not.
|
|
|
|
=cut
|
|
|
|
# Returns 1 if the parameter is a content-type viewable in this browser
|
|
# Note that we don't use $cgi->Accept()'s ability to check if a content-type
|
|
# matches, because this will return a value even if it's matched by the generic
|
|
# */* which most browsers add to the end of their Accept: headers.
|
|
sub isViewable
|
|
{
|
|
my $self = shift;
|
|
my $cgi = shift;
|
|
my $contenttype = $self->mime_type;
|
|
|
|
# We assume we can view all text and image types
|
|
if ($contenttype =~ /^(text|image)\//) {
|
|
return 1;
|
|
}
|
|
|
|
# Mozilla can view XUL. Note the trailing slash on the Gecko detection to
|
|
# avoid sending XUL to Safari.
|
|
if (($contenttype =~ /^application\/vnd\.mozilla\./) &&
|
|
($cgi->user_agent() =~ /Gecko\//))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
# If it's not one of the above types, we check the Accept: header for any
|
|
# types mentioned explicitly.
|
|
my $accept = join(",", $cgi->Accept());
|
|
|
|
if ($accept =~ /^(.*,)?\Q$contenttype\E(,.*)?$/) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
=head2 update
|
|
|
|
Updates an existing attachment object in the database.
|
|
Takes a reference to a hash, the keys of which must match
|
|
the fields of an attachment and the values representing the
|
|
new data.
|
|
|
|
=cut
|
|
|
|
sub update {
|
|
my $self = shift;
|
|
my ($newvalues) = @_;
|
|
my $dbh = Bugzilla->dbh;
|
|
my $timestamp = Bugzilla::Testopia::Util::get_time_stamp();
|
|
|
|
$dbh->bz_lock_tables('test_attachments WRITE');
|
|
foreach my $field (keys %{$newvalues}){
|
|
if ($self->{$field} ne $newvalues->{$field}){
|
|
trick_taint($newvalues->{$field});
|
|
$dbh->do("UPDATE test_attachments
|
|
SET $field = ? WHERE attachment_id = ?",
|
|
undef, $newvalues->{$field}, $self->{'attachment_id'});
|
|
}
|
|
}
|
|
$dbh->bz_unlock_tables();
|
|
}
|
|
|
|
=head2 obliterate
|
|
|
|
Completely removes an attachment from the database. This is the only
|
|
safe way to do this.
|
|
|
|
=cut
|
|
|
|
sub obliterate {
|
|
my $self = shift;
|
|
my $dbh = Bugzilla->dbh;
|
|
$dbh->do("DELETE FROM test_attachment_data
|
|
WHERE attachment_id = ?", undef, $self->{'attachment_id'});
|
|
$dbh->do("DELETE FROM test_attachments
|
|
WHERE attachment_id = ?", undef, $self->{'attachment_id'});
|
|
}
|
|
|
|
=head2 canview
|
|
|
|
Returns true if the logged in user has rights to view this attachment
|
|
|
|
=cut
|
|
|
|
sub canview {
|
|
}
|
|
|
|
=head2 canedit
|
|
|
|
Returns true if the logged in user has rights to edit this attachment
|
|
|
|
=cut
|
|
|
|
sub canedit {
|
|
}
|
|
|
|
=head2 candelete
|
|
|
|
Returns true if the logged in user has rights to delete this attachment
|
|
|
|
=cut
|
|
|
|
sub candelete {
|
|
}
|
|
|
|
###############################
|
|
#### Accessors ####
|
|
###############################
|
|
|
|
sub id { return $_[0]->{'attachment_id'}; }
|
|
sub plan_id { return $_[0]->{'plan_id'}; }
|
|
sub case_id { return $_[0]->{'case_id'}; }
|
|
sub submitter { return Bugzilla::User->new($_[0]->{'submitter_id'}); }
|
|
sub description { return $_[0]->{'description'}; }
|
|
sub filename { return $_[0]->{'filename'}; }
|
|
sub creation_ts { return $_[0]->{'creation_ts'}; }
|
|
sub mime_type { return $_[0]->{'mime_type'}; }
|
|
|
|
=head2 contents
|
|
|
|
Returns the attachment data
|
|
|
|
=cut
|
|
|
|
sub contents {
|
|
my ($self) = @_;
|
|
my $dbh = Bugzilla->dbh;
|
|
return $self->{'contents'} if exists $self->{'contents'};
|
|
my ($contents) = $dbh->selectrow_array("SELECT contents
|
|
FROM test_attachment_data
|
|
WHERE attachment_id = ?",
|
|
undef, $self->{'attachment_id'});
|
|
|
|
$self->{'contents'} = $contents;
|
|
return $self->{'contents'};
|
|
}
|
|
|
|
=head2 datasize
|
|
|
|
Returns the size of the attachment data
|
|
|
|
=cut
|
|
|
|
sub datasize {
|
|
my ($self) = @_;
|
|
my $dbh = Bugzilla->dbh;
|
|
return $self->{'datasize'} if exists $self->{'datasize'};
|
|
my ($datasize) = $dbh->selectrow_array("SELECT LENGTH(contents)
|
|
FROM test_attachment_data
|
|
WHERE attachment_id = ?",
|
|
undef, $self->{'attachment_id'});
|
|
$self->{'datasize'} = $datasize;
|
|
return $self->{'datasize'};
|
|
}
|
|
|
|
=head1 SEE ALSO
|
|
|
|
Bugzilla::Attachment
|
|
|
|
=head1 AUTHOR
|
|
|
|
Greg Hendricks <ghendricks@novell.com>
|
|
|
|
=cut
|
|
|
|
1;
|