Commit 246f6778 authored by lpsolit%gmail.com's avatar lpsolit%gmail.com

Bug 44595: Implement an interface for administrators to delete attachments -…

Bug 44595: Implement an interface for administrators to delete attachments - Patch by Frédéric Buclin <LpSolit@gmail.com> r=wicked, justdave a=justdave
parent 3811d9d8
...@@ -339,16 +339,16 @@ sub datasize { ...@@ -339,16 +339,16 @@ sub datasize {
# If we have already retrieved the data, return its size. # If we have already retrieved the data, return its size.
return length($self->{data}) if exists $self->{data}; return length($self->{data}) if exists $self->{data};
($self->{datasize}) = $self->{datasize} =
Bugzilla->dbh->selectrow_array("SELECT LENGTH(thedata) Bugzilla->dbh->selectrow_array("SELECT LENGTH(thedata)
FROM attach_data FROM attach_data
WHERE id = ?", WHERE id = ?",
undef, undef, $self->{id}) || 0;
$self->{id});
# If there's no attachment data in the database, the attachment # If there's no attachment data in the database, either the attachment
# is stored in a local file, so retrieve its size from the file. # is stored in a local file, and so retrieve its size from the file,
if ($self->{datasize} == 0) { # or the attachment has been deleted.
unless ($self->{datasize}) {
if (open(AH, $self->_get_local_filename())) { if (open(AH, $self->_get_local_filename())) {
binmode AH; binmode AH;
$self->{datasize} = (stat(AH))[7]; $self->{datasize} = (stat(AH))[7];
......
...@@ -41,6 +41,11 @@ sub get_param_list { ...@@ -41,6 +41,11 @@ sub get_param_list {
my $class = shift; my $class = shift;
my @param_list = ( my @param_list = (
{ {
name => 'allow_attachment_deletion',
type => 'b',
default => 0
},
{
name => 'allow_attach_url', name => 'allow_attach_url',
type => 'b', type => 'b',
default => 0 default => 0
......
...@@ -49,6 +49,7 @@ use Bugzilla::Util; ...@@ -49,6 +49,7 @@ use Bugzilla::Util;
use Bugzilla::Bug; use Bugzilla::Bug;
use Bugzilla::Field; use Bugzilla::Field;
use Bugzilla::Attachment; use Bugzilla::Attachment;
use Bugzilla::Token;
Bugzilla->login(); Bugzilla->login();
...@@ -103,6 +104,9 @@ elsif ($action eq "update") ...@@ -103,6 +104,9 @@ elsif ($action eq "update")
Bugzilla->login(LOGIN_REQUIRED); Bugzilla->login(LOGIN_REQUIRED);
update(); update();
} }
elsif ($action eq "delete") {
delete_attachment();
}
else else
{ {
ThrowCodeError("unknown_action", { action => $action }); ThrowCodeError("unknown_action", { action => $action });
...@@ -1329,3 +1333,82 @@ sub update ...@@ -1329,3 +1333,82 @@ sub update
$template->process("attachment/updated.html.tmpl", $vars) $template->process("attachment/updated.html.tmpl", $vars)
|| ThrowTemplateError($template->error()); || ThrowTemplateError($template->error());
} }
# Only administrators can delete attachments.
sub delete_attachment {
my $user = Bugzilla->login(LOGIN_REQUIRED);
my $dbh = Bugzilla->dbh;
print $cgi->header();
$user->in_group('admin')
|| ThrowUserError('auth_failure', {group => 'admin',
action => 'delete',
object => 'attachment'});
Param('allow_attachment_deletion')
|| ThrowUserError('attachment_deletion_disabled');
# Make sure the administrator is allowed to edit this attachment.
my ($attach_id, $bug_id) = validateID();
validateCanEdit($attach_id);
validateCanChangeAttachment($attach_id);
my $attachment = Bugzilla::Attachment->get($attach_id);
$attachment->datasize || ThrowUserError('attachment_removed');
# We don't want to let a malicious URL accidentally delete an attachment.
my $token = trim($cgi->param('token'));
if ($token) {
my ($creator_id, $date, $event) = Bugzilla::Token::GetTokenData($token);
unless ($creator_id
&& ($creator_id == $user->id)
&& ($event eq "attachment$attach_id"))
{
# The token is invalid.
ThrowUserError('token_inexistent');
}
# The token is valid. Delete the content of the attachment.
my $msg;
$vars->{'attachid'} = $attach_id;
$vars->{'bugid'} = $bug_id;
$vars->{'date'} = $date;
$vars->{'reason'} = clean_text($cgi->param('reason') || '');
$vars->{'mailrecipients'} = { 'changer' => $user->login };
$template->process("attachment/delete_reason.txt.tmpl", $vars, \$msg)
|| ThrowTemplateError($template->error());
$dbh->bz_lock_tables('attachments WRITE', 'attach_data WRITE', 'flags WRITE');
$dbh->do('DELETE FROM attach_data WHERE id = ?', undef, $attach_id);
$dbh->do('UPDATE attachments SET mimetype = ?, ispatch = ?, isurl = ?
WHERE attach_id = ?', undef, ('text/plain', 0, 0, $attach_id));
$dbh->do('DELETE FROM flags WHERE attach_id = ?', undef, $attach_id);
$dbh->bz_unlock_tables;
# If the attachment is stored locally, remove it.
if (-e $attachment->_get_local_filename) {
unlink $attachment->_get_local_filename;
}
# Now delete the token.
Bugzilla::Token::DeleteToken($token);
# Paste the reason provided by the admin into a comment.
AppendComment($bug_id, $user->id, $msg);
$template->process("attachment/updated.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
else {
# Create a token.
$token = Bugzilla::Token::IssueSessionToken('attachment' . $attach_id);
$vars->{'a'} = $attachment;
$vars->{'token'} = $token;
$template->process("attachment/confirm-delete.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
}
...@@ -25,9 +25,13 @@ ...@@ -25,9 +25,13 @@
%] %]
[% param_descs = { [% param_descs = {
allow_attachment_deletion => "If this option is on, administrators will be able to delete " _
"the content of attachments.",
allow_attach_url => "If this option is on, it will be possible to " _ allow_attach_url => "If this option is on, it will be possible to " _
"specify a URL when creating an attachment and " _ "specify a URL when creating an attachment and " _
"treat the URL itself as if it were an attachment.", "treat the URL itself as if it were an attachment.",
maxpatchsize => "The maximum size (in kilobytes) of patches. $terms.Bugzilla will not " _ maxpatchsize => "The maximum size (in kilobytes) of patches. $terms.Bugzilla will not " _
"accept patches greater than this number of kilobytes in size. " _ "accept patches greater than this number of kilobytes in size. " _
"To accept patches of any size (subject to the limitations of " _ "To accept patches of any size (subject to the limitations of " _
......
[%# 1.0@bugzilla.org %]
[%# 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.
#
# Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
#%]
[%# INTERFACE:
# a: attachment object; attachment the user wants to delete.
# token: string; The token used to identify the session.
#%]
[% PROCESS global/variables.none.tmpl %]
[% title = BLOCK %]
Delete Attachment [% a.id FILTER html %] of
[%+ "$terms.Bug " _ a.bug_id FILTER bug_link(a.bug_id) FILTER none %]
[% END %]
[% PROCESS global/header.html.tmpl title = title %]
<table border="1" cellpadding="4" cellspacing="0">
<tr bgcolor="#6666FF">
<th valign="top" align="left">Field</th>
<th valign="top" align="left">Value</th>
</tr>
<tr>
<td valign="top">Attachment ID:</td>
<td valign="top">
<a href="attachment.cgi?id=[% a.id FILTER html %]">[% a.id FILTER html %]</a>
</td>
</tr>
<tr>
<td valign="top">File name:</td>
<td valign="top">[% a.filename FILTER html %]</td>
</tr>
<tr>
<td valign="top">Description:</td>
<td valign="top">[% a.description FILTER html %]</td>
</tr>
<tr>
<td valign="top">Contained in [% terms.Bug %]:</td>
<td valign="top">[% a.bug_id FILTER bug_link(a.bug_id) FILTER none %]</td>
</tr>
<tr>
<td valign="top">Creator:</td>
<td valign="top">[% a.attacher.identity FILTER html %]</td>
</tr>
<tr>
<td valign="top">Creation Date:</td>
<td valign="top">[% a.attached FILTER time %]</td>
</tr>
</table>
<h2>Confirmation</h2>
<table border="0" cellpadding="20" width="70%" bgcolor="red">
<tr>
<td>
The content of this attachment will be deleted in a <b>irreversible</b> way.
</td>
</tr>
</table>
<p>Do you really want to delete this attachment?</p>
<form action="attachment.cgi" method="POST">
<label for="reason">Reason of the deletion:</label>
<input type="text" id="reason" name="reason" value="" size="80" maxlength="200">
<p>
<input type="submit" value="Yes, delete">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="[% a.id FILTER html %]">
<input type="hidden" name="token" value="[% token FILTER html %]">
</form>
<p>
No, cancel this deletion and return to
[%+ "$terms.bug " _ a.bug_id FILTER bug_link(a.bug_id) FILTER none %].
</p>
[% PROCESS global/footer.html.tmpl %]
[%# 1.0@bugzilla.org %]
[%# 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.
#
# Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
#%]
[%# INTERFACE:
# attachid: ID of the attachment the user wants to delete.
# reason: string; The reason provided by the user.
# date: the date when the request to delete the attachment was made.
#%]
The content of attachment [% attachid %] has been deleted by
[%+ user.identity %]
[% IF reason %]
who provided the following reason:
[%+ reason %]
[% ELSE %]
without providing any reason.
[% END %]
The token used to delete this attachment was generated at [% date FILTER time %].
...@@ -229,7 +229,12 @@ ...@@ -229,7 +229,12 @@
<b>Filename:</b><br> <b>Filename:</b><br>
<input type="text" size="20" name="filename" <input type="text" size="20" name="filename"
value="[% attachment.filename FILTER html %]"><br> value="[% attachment.filename FILTER html %]"><br>
<b>Size: </b>[% attachment.datasize FILTER unitconvert %]<br> <b>Size:</b>
[% IF attachment.datasize %]
[%+ attachment.datasize FILTER unitconvert %]
[% ELSE %]
<em>deleted</em>
[% END %]<br>
<b>MIME Type:</b><br> <b>MIME Type:</b><br>
<input type="text" size="20" name="contenttypeentry" <input type="text" size="20" name="contenttypeentry"
...@@ -269,10 +274,17 @@ ...@@ -269,10 +274,17 @@
[% IF attachment.ispatch && patchviewerinstalled %] [% IF attachment.ispatch && patchviewerinstalled %]
| <a href="attachment.cgi?id=[% attachment.id %]&action=diff">Diff</a> | <a href="attachment.cgi?id=[% attachment.id %]&action=diff">Diff</a>
[% END %] [% END %]
[% IF Param("allow_attachment_deletion")
&& user.groups.admin
&& attachment.datasize > 0 %]
| <a href="attachment.cgi?id=[% attachment.id %]&action=delete">Delete</a>
[% END %]
</small> </small>
</td> </td>
[% IF isviewable %] [% IF !attachment.datasize %]
<td width="75%"><b>The content of this attachment has been deleted.</b></td>
[% ELSIF isviewable %]
<td width="75%"> <td width="75%">
[% INCLUDE global/textarea.html.tmpl [% INCLUDE global/textarea.html.tmpl
id = 'editFrame' id = 'editFrame'
......
...@@ -56,7 +56,13 @@ ...@@ -56,7 +56,13 @@
</a> </a>
</td> </td>
<td valign="top">[% attachment.attached FILTER time %]</td> <td valign="top">[% attachment.attached FILTER time %]</td>
<td valign="top">[% attachment.datasize FILTER unitconvert %]</td> <td valign="top">
[% IF attachment.datasize %]
[% attachment.datasize FILTER unitconvert %]
[% ELSE %]
<em>deleted</em>
[% END %]
</td>
[% IF show_attachment_flags %] [% IF show_attachment_flags %]
<td valign="top"> <td valign="top">
......
...@@ -194,6 +194,10 @@ ...@@ -194,6 +194,10 @@
versions versions
[% END %]. [% END %].
[% ELSIF error == "attachment_deletion_disabled" %]
[% title = "Attachment Deletion Disabled" %]
Attachment deletion is disabled on this installation.
[% ELSIF error == "attachment_removed" %] [% ELSIF error == "attachment_removed" %]
[% title = "Attachment Removed" %] [% title = "Attachment Removed" %]
The attachment you are attempting to access has been removed. The attachment you are attempting to access has been removed.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment