WIP: attachment->object
parent
af9cf8806e
commit
97257aa8a1
|
@ -1,24 +1,10 @@
|
|||
# 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): Terry Weissman <terry@mozilla.org>
|
||||
# Myk Melez <myk@mozilla.org>
|
||||
# Marc Schumann <wurblzap@gmail.com>
|
||||
# Frédéric Buclin <LpSolit@gmail.com>
|
||||
# Bug attachment class (based on GenericObject)
|
||||
# License: MPL 1.1
|
||||
# Contributor(s): Vitaliy Filippov <vitalif@mail.ru>
|
||||
# Terry Weissman <terry@mozilla.org>
|
||||
# Myk Melez <myk@mozilla.org>
|
||||
# Marc Schumann <wurblzap@gmail.com>
|
||||
# Frédéric Buclin <LpSolit@gmail.com>
|
||||
|
||||
use strict;
|
||||
|
||||
|
@ -61,63 +47,24 @@ use Bugzilla::Hook;
|
|||
use LWP::MediaTypes;
|
||||
use MIME::Base64;
|
||||
|
||||
use base qw(Bugzilla::Object);
|
||||
|
||||
###############################
|
||||
#### Initialization ####
|
||||
###############################
|
||||
use base qw(Bugzilla::GenericObject);
|
||||
|
||||
use constant DB_TABLE => 'attachments';
|
||||
use constant ID_FIELD => 'attach_id';
|
||||
use constant LIST_ORDER => ID_FIELD;
|
||||
use constant NAME_FIELD => 'attach_id';
|
||||
use constant CLASS_NAME => 'attachment';
|
||||
|
||||
sub DB_COLUMNS
|
||||
{
|
||||
my $dbh = Bugzilla->dbh;
|
||||
return qw(
|
||||
attach_id
|
||||
bug_id
|
||||
description
|
||||
filename
|
||||
isobsolete
|
||||
ispatch
|
||||
isprivate
|
||||
mimetype
|
||||
modification_time
|
||||
submitter_id),
|
||||
$dbh->sql_date_format('attachments.creation_ts') . ' AS creation_ts',
|
||||
'creation_ts AS creation_ts_orig';
|
||||
}
|
||||
|
||||
use constant REQUIRED_CREATE_FIELDS => qw(
|
||||
bug
|
||||
data
|
||||
description
|
||||
filename
|
||||
mimetype
|
||||
);
|
||||
|
||||
use constant UPDATE_COLUMNS => qw(
|
||||
description
|
||||
filename
|
||||
isobsolete
|
||||
ispatch
|
||||
isprivate
|
||||
mimetype
|
||||
);
|
||||
|
||||
use constant VALIDATORS => {
|
||||
bug => \&_check_bug,
|
||||
description => \&_check_description,
|
||||
use constant OVERRIDE_SETTERS => {
|
||||
bug => \&_set_bug,
|
||||
bug_id => \&_set_bug,
|
||||
description => \&_set_description,
|
||||
ispatch => \&Bugzilla::Object::check_boolean,
|
||||
isprivate => \&_check_is_private,
|
||||
mimetype => \&_check_content_type,
|
||||
isprivate => \&_set_isprivate,
|
||||
mimetype => \&_set_mimetype,
|
||||
store_in_file => \&_check_store_in_file,
|
||||
};
|
||||
|
||||
use constant UPDATE_VALIDATORS => {
|
||||
filename => \&_check_filename,
|
||||
isobsolete => \&Bugzilla::Object::check_boolean,
|
||||
filename => \&_check_filename,
|
||||
isobsolete => \&_set_isobsolete,
|
||||
};
|
||||
|
||||
=pod
|
||||
|
@ -206,16 +153,6 @@ already set, grouped by flag type.
|
|||
|
||||
=cut
|
||||
|
||||
sub bug_id { $_[0]->{bug_id} }
|
||||
sub description { $_[0]->{description} }
|
||||
sub contenttype { $_[0]->{mimetype} }
|
||||
sub attached { $_[0]->{creation_ts} }
|
||||
sub modification_time { $_[0]->{modification_time} }
|
||||
sub filename { $_[0]->{filename} }
|
||||
sub ispatch { $_[0]->{ispatch} }
|
||||
sub isobsolete { $_[0]->{isobsolete} }
|
||||
sub isprivate { $_[0]->{isprivate} }
|
||||
|
||||
sub bug
|
||||
{
|
||||
my $self = shift;
|
||||
|
@ -416,23 +353,23 @@ sub flag_types
|
|||
return $self->{flag_types};
|
||||
}
|
||||
|
||||
sub set_flags
|
||||
{
|
||||
my ($self, $flags, $new_flags, $comment) = @_;
|
||||
Bugzilla::Flag->set_flag($self, $_) foreach (@$flags, @$new_flags);
|
||||
$self->{flag_notify_comment} = $comment;
|
||||
}
|
||||
|
||||
###############################
|
||||
#### Validators ######
|
||||
###############################
|
||||
|
||||
sub set_content_type { $_[0]->set('mimetype', $_[1]); }
|
||||
sub set_description { $_[0]->set('description', $_[1]); }
|
||||
sub set_filename { $_[0]->set('filename', $_[1]); }
|
||||
sub set_is_patch { $_[0]->set('ispatch', $_[1]); }
|
||||
sub set_is_private { $_[0]->set('isprivate', $_[1]); }
|
||||
|
||||
sub set_is_obsolete
|
||||
sub _set_isobsolete
|
||||
{
|
||||
my ($self, $obsolete) = @_;
|
||||
|
||||
my $old = $self->isobsolete;
|
||||
$self->set('isobsolete', $obsolete);
|
||||
my $new = $self->isobsolete;
|
||||
my $old = $self->{_old_self} ? $self->{_old_self}->{isobsolete} : 0;
|
||||
my $new = Bugzilla::Object::check_boolean($self, $obsolete);
|
||||
|
||||
# If the attachment is being marked as obsolete, cancel pending requests.
|
||||
if ($new && $old != $new)
|
||||
|
@ -446,24 +383,21 @@ sub set_is_obsolete
|
|||
@{$flagtype->{flags}} = grep { !$flag_ids{$_->id} } @{$flagtype->{flags}};
|
||||
}
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
sub set_flags
|
||||
sub _set_bug
|
||||
{
|
||||
my ($self, $flags, $new_flags, $comment) = @_;
|
||||
Bugzilla::Flag->set_flag($self, $_) foreach (@$flags, @$new_flags);
|
||||
$self->{flag_notify_comment} = $comment;
|
||||
}
|
||||
my ($self, $bug) = @_;
|
||||
return undef if $self->id;
|
||||
|
||||
sub _check_bug
|
||||
{
|
||||
my ($invocant, $bug) = @_;
|
||||
my $user = Bugzilla->user;
|
||||
|
||||
$bug = ref $invocant ? $invocant->bug : $bug;
|
||||
$user->can_edit_bug($bug->id) || ThrowUserError("illegal_attachment_edit_bug", { bug_id => $bug->id });
|
||||
|
||||
return $bug;
|
||||
$self->{bug} = $bug;
|
||||
$self->{bug_id} = $bug->id;
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub _legal_content_type
|
||||
|
@ -473,11 +407,11 @@ sub _legal_content_type
|
|||
return $content_type =~ /^($legal_types)\/.+$/;
|
||||
}
|
||||
|
||||
sub _check_content_type
|
||||
sub _set_mimetype
|
||||
{
|
||||
my ($invocant, $content_type) = @_;
|
||||
my ($self, $content_type) = @_;
|
||||
|
||||
$content_type = 'text/plain' if ref $invocant && $invocant->ispatch;
|
||||
$content_type = 'text/plain' if $self->ispatch;
|
||||
$content_type = trim($content_type);
|
||||
if (!$content_type || !_legal_content_type($content_type))
|
||||
{
|
||||
|
@ -488,9 +422,9 @@ sub _check_content_type
|
|||
return $content_type;
|
||||
}
|
||||
|
||||
sub _check_data
|
||||
sub _set_data
|
||||
{
|
||||
my ($invocant, $params) = @_;
|
||||
my ($self, $params) = @_;
|
||||
|
||||
my $data;
|
||||
if ($params->{base64_content})
|
||||
|
@ -521,47 +455,20 @@ sub _check_data
|
|||
return $data if ref $data;
|
||||
|
||||
$data || ThrowUserError('zero_length_file');
|
||||
# Make sure the attachment does not exceed the maximum permitted size.
|
||||
my $len = length($data);
|
||||
my $max_size = $params->{store_in_file} || Bugzilla->params->{force_attach_bigfile}
|
||||
? Bugzilla->params->{maxlocalattachment} * 1048576
|
||||
: Bugzilla->params->{maxattachmentsize} * 1024;
|
||||
if ($len > $max_size)
|
||||
{
|
||||
my $vars = { filesize => sprintf("%.0f", $len/1024) };
|
||||
if ($params->{ispatch})
|
||||
{
|
||||
ThrowUserError('patch_too_large', $vars);
|
||||
}
|
||||
elsif ($params->{store_in_file})
|
||||
{
|
||||
ThrowUserError('local_file_too_large');
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowUserError('file_too_large', $vars);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
sub _check_description
|
||||
sub _set_description
|
||||
{
|
||||
my ($invocant, $description) = @_;
|
||||
|
||||
my ($self, $description) = @_;
|
||||
$description = trim($description);
|
||||
$description || ThrowUserError('missing_attachment_description');
|
||||
return $description;
|
||||
}
|
||||
|
||||
sub _check_filename
|
||||
sub _set_filename
|
||||
{
|
||||
my ($invocant, $filename, undef, $params) = @_;
|
||||
|
||||
if ($params && $params->{base64_content})
|
||||
{
|
||||
$filename = $params->{description};
|
||||
}
|
||||
my ($self, $filename) = @_;
|
||||
|
||||
$filename = trim($filename);
|
||||
$filename || ThrowUserError('file_not_specified');
|
||||
|
@ -581,12 +488,12 @@ sub _check_filename
|
|||
return $filename;
|
||||
}
|
||||
|
||||
sub _check_is_private
|
||||
sub _set_isprivate
|
||||
{
|
||||
my ($invocant, $is_private) = @_;
|
||||
|
||||
my ($self, $is_private) = @_;
|
||||
$is_private = $is_private ? 1 : 0;
|
||||
if ((ref $invocant ? ($invocant->isprivate != $is_private) : $is_private) && !Bugzilla->user->is_insider)
|
||||
my $old = $self->{_old_self} ? $self->{_old_self}->isprivate : 0;
|
||||
if ($old != $is_private && !Bugzilla->user->is_insider)
|
||||
{
|
||||
ThrowUserError('user_not_insider');
|
||||
}
|
||||
|
@ -776,138 +683,120 @@ Returns: The new attachment object.
|
|||
|
||||
=cut
|
||||
|
||||
sub create
|
||||
sub _before_update
|
||||
{
|
||||
my $class = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
|
||||
$class->check_required_create_fields(@_);
|
||||
my $params = $class->run_create_validators(@_);
|
||||
|
||||
# Extract everything which is not a valid column name.
|
||||
my $bug = delete $params->{bug};
|
||||
$params->{bug_id} = $bug->id;
|
||||
my $fh = delete $params->{data};
|
||||
my $store_in_file = delete $params->{store_in_file};
|
||||
|
||||
if (Bugzilla->params->{force_attach_bigfile})
|
||||
my $self = shift;
|
||||
$self->SUPER::_before_update($changes);
|
||||
$self->{modification_time} = $self->{delta_ts};
|
||||
if (!$self->id)
|
||||
{
|
||||
# Force uploading into files instead of DB when force_attach_bigfile = On
|
||||
$store_in_file = 1;
|
||||
$self->{submitter_id} = Bugzilla->user->id || ThrowCodeError('invalid_user');
|
||||
}
|
||||
|
||||
my $attachment = $class->insert_create_data($params);
|
||||
my $attachid = $attachment->id;
|
||||
|
||||
# If the file is to be stored locally, stream the file from the web server
|
||||
# to the local file without reading it into a local variable.
|
||||
if ($store_in_file)
|
||||
if (!$self->id && $self->{data} && !ref $self->{data})
|
||||
{
|
||||
my $attachdir = bz_locations()->{attachdir};
|
||||
my $hash = ($attachid % 100) + 100;
|
||||
$hash =~ s/.*(\d\d)$/group.$1/;
|
||||
mkdir "$attachdir/$hash", 0770;
|
||||
chmod 0770, "$attachdir/$hash";
|
||||
open(AH, '>', "$attachdir/$hash/attachment.$attachid") or die "Could not write into $attachdir/$hash/attachment.$attachid: $!";
|
||||
binmode AH;
|
||||
if (ref $fh)
|
||||
$self->set('filename', $self->{description});
|
||||
# Make sure the attachment does not exceed the maximum permitted size.
|
||||
my $len = length($self->{data});
|
||||
my $max_size = $params->{store_in_file} || Bugzilla->params->{force_attach_bigfile}
|
||||
? Bugzilla->params->{maxlocalattachment} * 1048576
|
||||
: Bugzilla->params->{maxattachmentsize} * 1024;
|
||||
if ($len > $max_size)
|
||||
{
|
||||
my $limit = Bugzilla->params->{maxlocalattachment} * 1048576;
|
||||
my $sizecount = 0;
|
||||
while (<$fh>)
|
||||
my $vars = { filesize => sprintf("%.0f", $len/1024) };
|
||||
if ($self->{ispatch})
|
||||
{
|
||||
print AH $_;
|
||||
$sizecount += length($_);
|
||||
if ($sizecount > $limit)
|
||||
{
|
||||
close AH;
|
||||
close $fh;
|
||||
unlink "$attachdir/$hash/attachment.$attachid";
|
||||
ThrowUserError("local_file_too_large");
|
||||
}
|
||||
ThrowUserError('patch_too_large', $vars);
|
||||
}
|
||||
close $fh;
|
||||
elsif ($self->{store_in_file})
|
||||
{
|
||||
ThrowUserError('local_file_too_large');
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowUserError('file_too_large', $vars);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub _after_update
|
||||
{
|
||||
my $self = shift;
|
||||
my ($changes) = @_;
|
||||
|
||||
if (!$self->id && $self->{data})
|
||||
{
|
||||
my $fh = delete $self->{data};
|
||||
my $store_in_file = delete $self->{store_in_file};
|
||||
if (Bugzilla->params->{force_attach_bigfile})
|
||||
{
|
||||
# Force uploading into files instead of DB when force_attach_bigfile = On
|
||||
$store_in_file = 1;
|
||||
}
|
||||
my $attachid = $self->id;
|
||||
# If the file is to be stored locally, stream the file from the web server
|
||||
# to the local file without reading it into a local variable.
|
||||
if ($store_in_file)
|
||||
{
|
||||
my $attachdir = bz_locations()->{attachdir};
|
||||
my $hash = ($attachid % 100) + 100;
|
||||
$hash =~ s/.*(\d\d)$/group.$1/;
|
||||
mkdir "$attachdir/$hash", 0770;
|
||||
chmod 0770, "$attachdir/$hash";
|
||||
open(AH, '>', "$attachdir/$hash/attachment.$attachid") or die "Could not write into $attachdir/$hash/attachment.$attachid: $!";
|
||||
binmode AH;
|
||||
if (ref $fh)
|
||||
{
|
||||
my $limit = Bugzilla->params->{maxlocalattachment} * 1048576;
|
||||
my $sizecount = 0;
|
||||
while (<$fh>)
|
||||
{
|
||||
print AH $_;
|
||||
$sizecount += length($_);
|
||||
if ($sizecount > $limit)
|
||||
{
|
||||
close AH;
|
||||
close $fh;
|
||||
unlink "$attachdir/$hash/attachment.$attachid";
|
||||
ThrowUserError("local_file_too_large");
|
||||
}
|
||||
}
|
||||
close $fh;
|
||||
}
|
||||
else
|
||||
{
|
||||
print AH $fh;
|
||||
}
|
||||
close AH;
|
||||
}
|
||||
else
|
||||
{
|
||||
print AH $fh;
|
||||
# We only use $fh here in this INSERT with a placeholder, so it's safe.
|
||||
my $sth = $dbh->prepare("INSERT INTO attach_data (id, thedata) VALUES ($attachid, ?)");
|
||||
trick_taint($fh);
|
||||
$sth->bind_param(1, $fh, $dbh->BLOB_TYPE);
|
||||
$sth->execute();
|
||||
}
|
||||
close AH;
|
||||
}
|
||||
else
|
||||
{
|
||||
# We only use $fh here in this INSERT with a placeholder, so it's safe.
|
||||
my $sth = $dbh->prepare("INSERT INTO attach_data (id, thedata) VALUES ($attachid, ?)");
|
||||
trick_taint($fh);
|
||||
$sth->bind_param(1, $fh, $dbh->BLOB_TYPE);
|
||||
$sth->execute();
|
||||
Bugzilla::Hook::process('attachment_post_create', { attachment => $self });
|
||||
}
|
||||
|
||||
Bugzilla::Hook::process('attachment_post_create', { attachment => $attachment });
|
||||
|
||||
# Return the new attachment object.
|
||||
return $attachment;
|
||||
}
|
||||
|
||||
sub run_create_validators
|
||||
{
|
||||
my ($class, $params) = @_;
|
||||
|
||||
# Let's validate the attachment content first as it may
|
||||
# alter some other attachment attributes.
|
||||
$params->{data} = $class->_check_data($params);
|
||||
$params = $class->SUPER::run_create_validators($params);
|
||||
|
||||
$params->{filename} = $class->_check_filename($params->{filename}, 'filename', $params);
|
||||
$params->{creation_ts} ||= Bugzilla->dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
|
||||
$params->{modification_time} = $params->{creation_ts};
|
||||
$params->{submitter_id} = Bugzilla->user->id || ThrowCodeError('invalid_user');
|
||||
|
||||
delete $params->{base64_content};
|
||||
return $params;
|
||||
}
|
||||
|
||||
sub update
|
||||
{
|
||||
my $self = shift;
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $user = Bugzilla->user;
|
||||
my $timestamp = shift || $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
|
||||
|
||||
my ($changes, $old_self) = $self->SUPER::update(@_);
|
||||
|
||||
my ($removed, $added) = Bugzilla::Flag->update_flags($self, $old_self, $timestamp, $self->{flag_notify_comment});
|
||||
my $old_self = $self->{_old_self};
|
||||
my ($removed, $added) = Bugzilla::Flag->update_flags($self, $old_self, $self->{delta_ts}, $self->{flag_notify_comment});
|
||||
if ($removed || $added)
|
||||
{
|
||||
$changes->{'flagtypes.name'} = [$removed, $added];
|
||||
}
|
||||
delete $self->{flag_notify_comment};
|
||||
|
||||
# Log activity
|
||||
my $c;
|
||||
foreach my $field (keys %$changes)
|
||||
{
|
||||
$c = $changes->{$field};
|
||||
$field = "attachments.$field" unless $field eq 'flagtypes.name';
|
||||
Bugzilla::Bug::LogActivityEntry(
|
||||
$self->bug_id, $field, $c->[0], $c->[1],
|
||||
$user->id, $timestamp, $self->id
|
||||
);
|
||||
}
|
||||
|
||||
if (scalar keys %$changes)
|
||||
{
|
||||
$dbh->do(
|
||||
'UPDATE attachments SET modification_time = ? WHERE attach_id = ?',
|
||||
undef, $timestamp, $self->id
|
||||
);
|
||||
$dbh->do(
|
||||
'UPDATE bugs SET delta_ts = ? WHERE bug_id = ?',
|
||||
undef, $timestamp, $self->bug_id
|
||||
undef, $self->{delta_ts}, $self->bug_id
|
||||
);
|
||||
}
|
||||
|
||||
return $changes;
|
||||
$self->SUPER::_after_update($changes);
|
||||
}
|
||||
|
||||
=pod
|
||||
|
|
|
@ -192,14 +192,6 @@ use constant DEFAULT_FIELDS => (map { my $i = 0; $_ = { (map { (DEFAULT_FIELD_CO
|
|||
|
||||
# Comment (never stored in bugs_activity...)
|
||||
[ 'longdesc', 'Comment', 0, 0, 0 ],
|
||||
|
||||
# Attachment fields
|
||||
[ 'attachments.description', 'Attachment description', 0, 0, 0 ],
|
||||
[ 'attachments.filename', 'Attachment filename', 0, 0, 0 ],
|
||||
[ 'attachments.mimetype', 'Attachment mime type', 0, 0, 0 ],
|
||||
[ 'attachments.ispatch', 'Attachment is patch', 0, 0, 0 ],
|
||||
[ 'attachments.isobsolete', 'Attachment is obsolete', 0, 0, 0 ],
|
||||
[ 'attachments.isprivate', 'Attachment is private', 0, 0, 0 ],
|
||||
));
|
||||
|
||||
# Tweaks allowed for standard field properties
|
||||
|
|
|
@ -874,11 +874,29 @@ WHERE description LIKE \'%[CC:%]%\'');
|
|||
$dbh->do(
|
||||
'INSERT INTO objects_activity (class_id, object_id, field_id, who, change_ts, removed, added)'.
|
||||
' SELECT '.Bugzilla->get_class('comment')->id.', comment_id, '.
|
||||
Bugzilla->get_class_field('comment', 'thetext')->id.', who, bug_when, oldthetext, thetext'.
|
||||
Bugzilla->get_class_field('thetext', 'comment')->id.', who, bug_when, oldthetext, thetext'.
|
||||
' FROM longdescs_history'
|
||||
);
|
||||
$dbh->bz_drop_table('longdescs_history');
|
||||
}
|
||||
# Migrate attachments.* from bugs_activity to objects_activity
|
||||
if (Bugzilla->get_field('attachments.description'))
|
||||
{
|
||||
my $cid = Bugzilla->get_class('attachment')->id;
|
||||
$dbh->do(
|
||||
'INSERT INTO objects_activity (class_id, object_id, field_id, who, change_ts, removed, added)'.
|
||||
' SELECT '.$cid.', a.attach_id, f2.id, a.who, a.bug_when, a.removed, a.added'.
|
||||
' FROM bugs_activity a, fielddefs f, fielddefs f2 WHERE f.class_id=1'.
|
||||
' AND f.name LIKE \'attachments.%\' AND a.fieldid=f.id AND f2.class_id='.$cid.' AND f2.name=SUBSTR(f.name, 13)'
|
||||
);
|
||||
$dbh->do(
|
||||
'DELETE FROM bugs_activity WHERE fieldid IN (SELECT f.id FROM fielddefs f WHERE f.class_id=1'.
|
||||
' AND f.name LIKE \'attachments.%\')'
|
||||
);
|
||||
$dbh->do(
|
||||
'DELETE FROM fielddefs WHERE f.class_id=1 AND f.name LIKE \'attachments.%\''
|
||||
);
|
||||
}
|
||||
|
||||
_move_old_defaults($old_params);
|
||||
|
||||
|
|
|
@ -537,7 +537,8 @@ sub STATIC_COLUMNS
|
|||
|
||||
# Search-only fields that were previously in fielddefs
|
||||
foreach my $col (qw(requestees.login_name setters.login_name longdescs.isprivate content commenter
|
||||
owner_idle_time attachments.submitter days_elapsed percentage_complete))
|
||||
owner_idle_time attachments.submitter attachments.description attachments.filename attachments.mimetype
|
||||
attachments.ispatch attachments.isobsolete attachments.isprivate days_elapsed percentage_complete))
|
||||
{
|
||||
$columns->{$col}->{title} = Bugzilla->messages->{field_descs}->{$col};
|
||||
$columns->{$col}->{nobuglist} = 1;
|
||||
|
|
|
@ -582,14 +582,16 @@ sub insert
|
|||
my $attachment = Bugzilla::Attachment->create({
|
||||
bug => $bug,
|
||||
creation_ts => $timestamp,
|
||||
data => $data,
|
||||
description => $ARGS->{description},
|
||||
filename => $filename,
|
||||
ispatch => $ispatch,
|
||||
isprivate => $ARGS->{isprivate},
|
||||
mimetype => $content_type,
|
||||
store_in_file => $ARGS->{bigfile},
|
||||
base64_content => $ARGS->{base64_content},
|
||||
data => {
|
||||
data => $data,
|
||||
store_in_file => $ARGS->{bigfile},
|
||||
base64_content => $ARGS->{base64_content},
|
||||
},
|
||||
});
|
||||
|
||||
foreach my $obsolete_attachment (@obsolete_attachments)
|
||||
|
@ -726,12 +728,14 @@ sub update
|
|||
|
||||
if ($can_edit)
|
||||
{
|
||||
$attachment->set_description($ARGS->{description});
|
||||
$attachment->set_is_patch($ARGS->{ispatch});
|
||||
$attachment->set_content_type($ARGS->{contenttypeentry});
|
||||
$attachment->set_is_obsolete($ARGS->{isobsolete});
|
||||
$attachment->set_is_private($ARGS->{isprivate});
|
||||
$attachment->set_filename($ARGS->{filename});
|
||||
$attachment->set_all({
|
||||
description => $ARGS->{description},
|
||||
ispatch => $ARGS->{ispatch},
|
||||
mimetype => $ARGS->{contenttypeentry},
|
||||
isobsolete => $ARGS->{isobsolete},
|
||||
isprivate => $ARGS->{isprivate},
|
||||
filename => $ARGS->{filename},
|
||||
});
|
||||
|
||||
# Now make sure the attachment has not been edited since we loaded the page.
|
||||
if (defined $ARGS->{delta_ts} && $ARGS->{delta_ts} ne $attachment->modification_time)
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Creation Date:</td>
|
||||
<td valign="top">[% a.attached FILTER time %]</td>
|
||||
<td valign="top">[% a.creation_ts FILTER time %]</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -89,9 +89,9 @@
|
|||
<label for="contenttypeentry">MIME Type:</label>
|
||||
<input type="text" size="20" class="block[% editable_or_hide %]"
|
||||
id="contenttypeentry" name="contenttypeentry"
|
||||
value="[% attachment.contenttype FILTER html %]" />
|
||||
value="[% attachment.mimetype FILTER html %]" />
|
||||
[% IF !can_edit %]
|
||||
[%+ attachment.contenttype FILTER truncate(25) FILTER html %]
|
||||
[%+ attachment.mimetype FILTER truncate(25) FILTER html %]
|
||||
[% END %]
|
||||
</div>
|
||||
|
||||
|
@ -206,7 +206,7 @@
|
|||
minrows = 10
|
||||
cols = 80
|
||||
wrap = 'soft'
|
||||
defaultcontent = (attachment.contenttype.match('^text\/')) ?
|
||||
defaultcontent = (attachment.mimetype.match('^text\/')) ?
|
||||
attachment.data.replace('(.*\n|.+)', '>$1') : undef
|
||||
%]
|
||||
<iframe id="viewFrame" src="attachment.cgi?id=[% attachment.id %]" style="height: 400px; width: 100%;">
|
||||
|
@ -237,7 +237,7 @@
|
|||
<td id="noview" width="50%">
|
||||
<p><b>
|
||||
Attachment is not viewable in your browser because its MIME type
|
||||
([% attachment.contenttype FILTER html %]) is not one that your browser is
|
||||
([% attachment.mimetype FILTER html %]) is not one that your browser is
|
||||
able to display.
|
||||
</b></p>
|
||||
<p><b>
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
[% IF attachment.isobsolete %]
|
||||
[% obsolete_attachments = obsolete_attachments + 1 %]
|
||||
[% END %]
|
||||
<tr class="[% "bz_contenttype_" _ attachment.contenttype | css_class_quote %]
|
||||
<tr class="[% "bz_contenttype_" _ attachment.mimetype | css_class_quote %]
|
||||
[% " bz_patch" IF attachment.ispatch %]
|
||||
[% " bz_private" IF attachment.isprivate %]
|
||||
[% " bz_tr_obsolete bz_default_hidden" IF attachment.isobsolete %]">
|
||||
|
@ -60,7 +60,7 @@
|
|||
[% IF attachment.ispatch %]
|
||||
patch)
|
||||
[% ELSE %]
|
||||
[%+ attachment.contenttype FILTER html %])
|
||||
[%+ attachment.mimetype FILTER html %])
|
||||
[% END %]
|
||||
[% ELSE %]
|
||||
(<em>deleted</em>)
|
||||
|
@ -69,7 +69,7 @@
|
|||
<br />
|
||||
<a href="#attach_[% attachment.id %]"
|
||||
title="Go to the comment associated with the attachment">
|
||||
[%- attachment.attached FILTER time %]</a>,
|
||||
[%- attachment.creation_ts FILTER time %]</a>,
|
||||
|
||||
[% INCLUDE global/user.html.tmpl who = attachment.attacher %]
|
||||
</span>
|
||||
|
|
|
@ -54,11 +54,11 @@
|
|||
[% IF a.ispatch %]
|
||||
<i>patch</i>
|
||||
[% ELSE %]
|
||||
[% a.contenttype FILTER html %]
|
||||
[% a.mimetype FILTER html %]
|
||||
[% END %]
|
||||
</td>
|
||||
|
||||
<td valign="top">[% a.attached FILTER time %]</td>
|
||||
<td valign="top">[% a.creation_ts FILTER time %]</td>
|
||||
<td valign="top">[% a.datasize FILTER unitconvert %]</td>
|
||||
|
||||
<td valign="top">
|
||||
|
|
|
@ -94,11 +94,11 @@
|
|||
ispatch="[% a.ispatch | xml %]"
|
||||
isprivate="[% a.isprivate | xml %]">
|
||||
<attachid>[% a.id %]</attachid>
|
||||
<date>[% a.attached | time("%Y-%m-%d %T %z") | xml %]</date>
|
||||
<date>[% a.creation_ts | time("%Y-%m-%d %T %z") | xml %]</date>
|
||||
<delta_ts>[% a.modification_time | time("%Y-%m-%d %T %z") | xml %]</delta_ts>
|
||||
<desc>[% a.description | xml %]</desc>
|
||||
<filename>[% a.filename | xml %]</filename>
|
||||
<type>[% a.contenttype | xml %]</type>
|
||||
<type>[% a.mimetype | xml %]</type>
|
||||
<size>[% a.datasize | xml %]</size>
|
||||
<attacher>[% a.attacher.email | email | xml %]</attacher>
|
||||
[%# This is here so automated clients can still use attachment.cgi %]
|
||||
|
|
Loading…
Reference in New Issue