Bug 87188 - SUPA image upload
git-svn-id: svn://svn.office.custis.ru/3rdparty/bugzilla.org/trunk@1404 6955db30-a419-402b-8a0d-67ecbb4d7f56master
parent
d5c6a82002
commit
ab32f0f3ea
|
@ -60,6 +60,7 @@ use Bugzilla::Field;
|
|||
use Bugzilla::Hook;
|
||||
|
||||
use LWP::MediaTypes;
|
||||
use MIME::Base64;
|
||||
|
||||
use base qw(Bugzilla::Object);
|
||||
|
||||
|
@ -558,6 +559,9 @@ sub _check_data {
|
|||
$params->{ispatch} = 0;
|
||||
$params->{store_in_file} = 0;
|
||||
}
|
||||
elsif ($params->{base64_content}) {
|
||||
$data = decode_base64($params->{base64_content});
|
||||
}
|
||||
else {
|
||||
if ($params->{store_in_file} || !ref $params->{data}) {
|
||||
# If it's a filehandle, just store it, not the content of the file
|
||||
|
@ -608,11 +612,15 @@ sub _check_description {
|
|||
}
|
||||
|
||||
sub _check_filename {
|
||||
my ($invocant, $filename, $is_url) = @_;
|
||||
my ($invocant, $filename, $params) = @_;
|
||||
|
||||
$is_url = $invocant->isurl if ref $invocant;
|
||||
# No file is attached, so it has no name.
|
||||
return '' if $is_url;
|
||||
return '' if ref $invocant && $invocant->isurl || $params && $params->{isurl};
|
||||
|
||||
if ($params && $params->{base64_content})
|
||||
{
|
||||
$filename = $params->{description};
|
||||
}
|
||||
|
||||
$filename = trim($filename);
|
||||
$filename || ThrowUserError('file_not_specified');
|
||||
|
@ -914,11 +922,12 @@ sub run_create_validators {
|
|||
$params->{data} = $class->_check_data($params);
|
||||
$params = $class->SUPER::run_create_validators($params);
|
||||
|
||||
$params->{filename} = $class->_check_filename($params->{filename}, $params->{isurl});
|
||||
$params->{filename} = $class->_check_filename($params->{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;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,12 @@ sub get_param_list {
|
|||
default => 0
|
||||
},
|
||||
|
||||
{
|
||||
name => 'use_supa_applet',
|
||||
type => 'b',
|
||||
default => 0,
|
||||
},
|
||||
|
||||
# The maximum size (in bytes) for patches and non-patch attachments.
|
||||
# The default limit is 1000KB, which is 24KB less than mysql's default
|
||||
# maximum packet size (which determines how much data can be sent in a
|
||||
|
|
|
@ -521,6 +521,7 @@ sub insert {
|
|||
isurl => scalar $cgi->param('attachurl'),
|
||||
mimetype => $content_type,
|
||||
store_in_file => scalar $cgi->param('bigfile'),
|
||||
base64_content => scalar $cgi->param('base64_content'),
|
||||
});
|
||||
|
||||
foreach my $obsolete_attachment (@obsolete_attachments) {
|
||||
|
|
|
@ -29,6 +29,11 @@ my $OPTIONAL_MODULES =
|
|||
module => 'Net::IP::Match::XS',
|
||||
feature => 'FOF-Sudo system-to-system authorization',
|
||||
},
|
||||
{
|
||||
package => 'LWP-MediaTypes',
|
||||
module => 'LWP::MediaTypes',
|
||||
feature => 'Guessing attachment types',
|
||||
},
|
||||
];
|
||||
|
||||
required_modules('custis', $REQUIRED_MODULES);
|
||||
|
|
Binary file not shown.
106
js/attachment.js
106
js/attachment.js
|
@ -21,15 +21,103 @@
|
|||
* Marc Schumann <wurblzap@gmail.com>
|
||||
*/
|
||||
|
||||
function switch_aft(n)
|
||||
var SUPA_JAVA_DISABLED_ERROR = 'You cannot paste images from clipboard because Java support'+
|
||||
' is not enabled in your browser. Please download Java plugin'+
|
||||
' from http://java.com/';
|
||||
|
||||
function htmlspecialchars_decode(str)
|
||||
{
|
||||
var f = document.getElementById('form_type_file'+n);
|
||||
var u = document.getElementById('form_type_url'+n);
|
||||
var t = document.getElementById('form_type_text'+n);
|
||||
document.getElementById('tr_file'+n).style.display = f && f.checked ? '' : 'none';
|
||||
document.getElementById('tr_text'+n).style.display = t && t.checked ? '' : 'none';
|
||||
if (u)
|
||||
document.getElementById('tr_url'+n).style.display = u.checked ? '' : 'none';
|
||||
str = str.replace(/>/g, '>');
|
||||
str = str.replace(/</g, '<');
|
||||
str = str.replace(/"/g, '"');
|
||||
str = str.replace(/'/g, '\'');
|
||||
str = str.replace(/&/g, '&');
|
||||
return str;
|
||||
}
|
||||
|
||||
function switchAttype(chk)
|
||||
{
|
||||
var t = chk.value=='text';
|
||||
var s = chk.value=='supa';
|
||||
var u = chk.value=='url';
|
||||
var ur = document.getElementById('attype_url_row');
|
||||
var sr = document.getElementById('attype_supa_row');
|
||||
u = u && ur;
|
||||
s = s && sr;
|
||||
document.getElementById('attype_text_row').style.display = t ? '' : 'none';
|
||||
document.getElementById('attype_file_row').style.display = t || s || u ? 'none' : '';
|
||||
if (ur) ur.style.display = u ? '' : 'none';
|
||||
if (sr) sr.style.display = s ? '' : 'none';
|
||||
document.getElementById('content_type_row').style.display = s ? 'none' : '';
|
||||
var d = document.getElementById('description');
|
||||
if (s)
|
||||
{
|
||||
if (d.value == '')
|
||||
d.value = 'Screenshot.png';
|
||||
document.getElementById('manual').checked = true;
|
||||
document.getElementById('contenttypeentry').value = 'image/png';
|
||||
document.getElementById('ispatch').checked = false;
|
||||
setContentTypeDisabledState(chk.form);
|
||||
var sc = document.getElementById('supa_container');
|
||||
if (sc.innerHTML.toLowerCase().indexOf('<applet') < 0)
|
||||
sc.innerHTML = htmlspecialchars_decode(sc.innerHTML);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (d.value == 'Screenshot.png')
|
||||
d.value = '';
|
||||
document.getElementById('base64_content').value = '';
|
||||
}
|
||||
}
|
||||
|
||||
function supaPasteAgain()
|
||||
{
|
||||
var s = document.getElementById('SupaApplet');
|
||||
if (!s)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
s.pasteFromClipboard();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
alert(SUPA_JAVA_DISABLED_ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function setContentTypeDisabledState(form)
|
||||
{
|
||||
var isdisabled = false;
|
||||
if (form.ispatch.checked)
|
||||
isdisabled = true;
|
||||
for (var i = 0; i < form.contenttypemethod.length; i++)
|
||||
form.contenttypemethod[i].disabled = isdisabled;
|
||||
form.contenttypeselection.disabled = isdisabled;
|
||||
form.contenttypeentry.disabled = isdisabled;
|
||||
}
|
||||
|
||||
function encodeSupaContent()
|
||||
{
|
||||
var s = document.getElementById('attype_supa');
|
||||
if (s && s.checked)
|
||||
{
|
||||
try
|
||||
{
|
||||
s = document.getElementById('SupaApplet').getEncodedString();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
alert(SUPA_JAVA_DISABLED_ERROR);
|
||||
var c = document.getElementById('attype_file');
|
||||
c.checked = true;
|
||||
switchAttype(c);
|
||||
return false;
|
||||
}
|
||||
document.getElementById('base64_content').value = s;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function validateAttachmentForm(theform)
|
||||
|
@ -40,6 +128,8 @@ function validateAttachmentForm(theform)
|
|||
alert(BUGZILLA.string.attach_desc_required);
|
||||
return false;
|
||||
}
|
||||
if (!encodeSupaContent())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -209,7 +209,8 @@ if (defined $cgi->param('version') && length $cgi->param('version'))
|
|||
|
||||
# Add an attachment if requested.
|
||||
if (defined($cgi->upload('data')) || $cgi->param('attachurl') ||
|
||||
$cgi->param('text_attachment')) {
|
||||
$cgi->param('text_attachment') || $cgi->param('base64_content'))
|
||||
{
|
||||
$cgi->param('isprivate', $cgi->param('commentprivacy'));
|
||||
|
||||
# Must be called before create() as it may alter $cgi->param('ispatch').
|
||||
|
@ -240,6 +241,7 @@ if (defined($cgi->upload('data')) || $cgi->param('attachurl') ||
|
|||
isurl => scalar $cgi->param('attachurl'),
|
||||
mimetype => $content_type,
|
||||
store_in_file => scalar $cgi->param('bigfile'),
|
||||
base64_content => scalar $cgi->param('base64_content'),
|
||||
});
|
||||
};
|
||||
Bugzilla->error_mode($error_mode_cache);
|
||||
|
@ -305,9 +307,10 @@ if (Bugzilla->usage_mode != USAGE_MODE_EMAIL)
|
|||
sent => \@all_mail_results,
|
||||
title => $title,
|
||||
header => $header,
|
||||
message => $vars->{message},
|
||||
};
|
||||
# CustIS Bug 38616 - CC list restriction
|
||||
if ($bug->{restricted_cc})
|
||||
if (!$ses->{message} && $bug->{restricted_cc})
|
||||
{
|
||||
$ses->{message_vars} = {
|
||||
restricted_cc => [ map { $_->login } @{ $bug->{restricted_cc} } ],
|
||||
|
|
|
@ -128,7 +128,7 @@ if (my @f = $cgi->param("includefield")) {
|
|||
%displayfields = map { $_ => 1 } grep { $displayfields{$_} } @f;
|
||||
}
|
||||
|
||||
$vars->{'displayfields'} = \%displayfields;
|
||||
$vars->{displayfields} = \%displayfields;
|
||||
|
||||
my $sd;
|
||||
if (Bugzilla->session && ($sd = Bugzilla->session_data) && $sd->{sent})
|
||||
|
@ -139,6 +139,8 @@ if (Bugzilla->session && ($sd = Bugzilla->session_data) && $sd->{sent})
|
|||
header => undef,
|
||||
sent_attrs => undef,
|
||||
failed_checkers => undef,
|
||||
message => undef,
|
||||
message_vars => undef,
|
||||
});
|
||||
$vars->{last_title} = $sd->{title};
|
||||
$vars->{last_header} = $sd->{header};
|
||||
|
@ -152,7 +154,8 @@ if (Bugzilla->session && ($sd = Bugzilla->session_data) && $sd->{sent})
|
|||
$vars->{$_} = $sd->{sent_attrs}->{$_} for keys %{$sd->{sent_attrs} || {}};
|
||||
}
|
||||
|
||||
$cgi->send_header($format->{'ctype'});
|
||||
$cgi->send_header($format->{ctype});
|
||||
|
||||
$template->process("$format->{'template'}", $vars)
|
||||
$template->process($format->{template}, $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
exit;
|
||||
|
|
|
@ -66,6 +66,11 @@
|
|||
"specify a URL when creating an attachment and " _
|
||||
"treat the URL itself as if it were an attachment.",
|
||||
|
||||
use_supa_applet =>
|
||||
"If this option is on, the <a href='http://supa.sourceforge.net/'>SUPA</a> java applet " _
|
||||
"(Screenshot UPload Applet) will be enabled to allow uploading of images from the clipboard. " _
|
||||
"Note this requires <a href='http://www.java.com/'>Java</a> support in user's browser.",
|
||||
|
||||
maxattachmentsize =>
|
||||
"The maximum size (in kilobytes) of attachments <b>stored in the database</b>. " _
|
||||
"$terms.Bugzilla will not accept attachments greater than this number " _
|
||||
|
|
|
@ -21,46 +21,66 @@
|
|||
# Marc Schumann <wurblzap@gmail.com>
|
||||
#%]
|
||||
|
||||
<script language="JavaScript">
|
||||
function switch_afot(fot)
|
||||
{
|
||||
if (fot)
|
||||
{
|
||||
document.getElementById('afot_text_row').style.display='';
|
||||
document.getElementById('afot_file_row').style.display='none';
|
||||
}
|
||||
else
|
||||
{
|
||||
document.getElementById('afot_text_row').style.display='none';
|
||||
document.getElementById('afot_file_row').style.display='';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<tr class="expert_fields">
|
||||
<th style="visibility: hidden; white-space: nowrap">Attachment text:</th><td><input onclick="switch_afot(false)" type="radio" name="att_file_or_text" id="afot_file" value="0" checked /> <label for="afot_file">Attach file</label> or <input onclick="switch_afot(true)" type="radio" name="att_file_or_text" id="afot_text" value="1" /> <label for="afot_text">Enter text</label> </td>
|
||||
</tr>
|
||||
<tr id="afot_file_row">
|
||||
<th><label for="data">File</label>:</th>
|
||||
[%# Don't remove this hidden text, its purpose is to align columns correctly! %]
|
||||
<th style="visibility: hidden; white-space: nowrap">Attachment text:</th>
|
||||
<td>
|
||||
<em>Enter the path to the file on your computer.</em><br>
|
||||
<input type="file" id="data" name="data" size="50"
|
||||
onchange="DataFieldHandler([% Param("allow_attach_url") ? 1 : 0 %])"
|
||||
>
|
||||
<input onclick="switchAttype(this)" type="radio" name="attype" id="attype_file" value="file" checked="checked" />
|
||||
<label for="attype_file">Attach file</label>
|
||||
[% IF Param("allow_attach_url") %]
|
||||
<input onclick="switchAttype(this)" type="radio" name="attype" id="attype_url" value="url" />
|
||||
<label for="attype_url">Attach URL</label>
|
||||
[% END %]
|
||||
<input onclick="switchAttype(this)" type="radio" name="attype" id="attype_text" value="text" />
|
||||
<label for="attype_text">Enter text</label>
|
||||
[% IF Param("use_supa_applet") %]
|
||||
<input onclick="switchAttype(this)" type="radio" name="attype" id="attype_supa" value="supa" />
|
||||
<label for="attype_supa">Paste image from clipboard</label>
|
||||
[% END %]
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="expert_fields" id="afot_text_row" style="display: none">
|
||||
<tr id="attype_file_row">
|
||||
<th><label for="data">File</label>:</th>
|
||||
<td>
|
||||
<em>Enter the path to the file on your computer.</em><br />
|
||||
<input type="file" id="data" name="data" size="50"
|
||||
onchange="DataFieldHandler([% Param("allow_attach_url") ? 1 : 0 %])" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="expert_fields" id="attype_text_row" style="display: none">
|
||||
<th><label for="text_attachment">Attachment text:</label></th>
|
||||
<td>
|
||||
<em>Enter attachment text here instead of selecting file.</em><br>
|
||||
<em>Enter or paste attachment text here:</em><br />
|
||||
<textarea wrap="soft" id="text_attachment" name="text_attachment" rows="4" cols="80"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
[% IF Param("use_supa_applet") %]
|
||||
<tr class="expert_fields" id="attype_supa_row" style="display: none">
|
||||
<th>
|
||||
<a href="javascript:void supaPasteAgain()">Paste again</a>
|
||||
<input type="hidden" name="base64_content" id="base64_content" value="" />
|
||||
</th>
|
||||
<td id="supa_container">
|
||||
[% FILTER html %]
|
||||
<applet id="SupaApplet" archive="js/Supa.jar"
|
||||
code="de.christophlinder.supa.SupaApplet" width="400" height="300">
|
||||
<param name="trace" value="true" />
|
||||
<param name="pasteonload" value="true" />
|
||||
<param name="clickforpaste" value="true" />
|
||||
<param name="imagecodec" value="png" />
|
||||
<param name="encoding" value="base64" />
|
||||
<param name="previewscaler" value="fit to canvas" />
|
||||
Please enable <a href="http://www.java.com/">Java</a> Applet support in your browser.
|
||||
</applet>
|
||||
[% END %]
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
[% IF Param("maxlocalattachment") && !Param("force_attach_bigfile") %]
|
||||
<tr class="expert_fields">
|
||||
<th>BigFile:</th>
|
||||
<td>
|
||||
<input type="checkbox" id="bigfile"
|
||||
name="bigfile" value="bigfile">
|
||||
<input type="checkbox" id="bigfile" name="bigfile" value="bigfile" />
|
||||
<label for="bigfile">
|
||||
Big File - Stored locally and may be purged
|
||||
</label>
|
||||
|
@ -68,10 +88,10 @@ function switch_afot(fot)
|
|||
</tr>
|
||||
[% END %]
|
||||
[% IF Param("allow_attach_url") %]
|
||||
<tr class="expert_fields">
|
||||
<tr class="expert_fields" id="attype_url_row" style="display: none">
|
||||
<th><label for="attachurl">AttachURL</label>:</th>
|
||||
<td>
|
||||
<em>URL to be attached instead.</em><br>
|
||||
<em>URL to be attached instead.</em><br />
|
||||
<input type="text" id="attachurl" name="attachurl" size="60"
|
||||
maxlength="2000"
|
||||
onkeyup="URLFieldHandler()" onblur="URLFieldHandler()">
|
||||
|
@ -82,16 +102,16 @@ function switch_afot(fot)
|
|||
<tr>
|
||||
<th><label for="description">Description</label>:</th>
|
||||
<td>
|
||||
<em>Describe the attachment briefly.</em><br>
|
||||
<em>Describe the attachment briefly.</em><br />
|
||||
<input type="text" id="description" name="description" size="60" maxlength="200" onchange="this._changed=true">
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="expert_fields">
|
||||
<tr class="expert_fields" id="content_type_row">
|
||||
<th>Content Type:</th>
|
||||
<td>
|
||||
<em>If the attachment is a patch, check the box below.</em><br>
|
||||
<em>If the attachment is a patch, check the box below.</em><br />
|
||||
<input type="checkbox" id="ispatch" name="ispatch" value="1"
|
||||
onchange="setContentTypeDisabledState(this.form);">
|
||||
onchange="setContentTypeDisabledState(this.form);" />
|
||||
<label for="ispatch">patch</label><br /><br />
|
||||
[%# Reset this whenever the page loads so that the JS state is up to date %]
|
||||
<script type="text/javascript">
|
||||
|
@ -100,17 +120,17 @@ function switch_afot(fot)
|
|||
});
|
||||
</script>
|
||||
|
||||
<em>Otherwise, choose a method for determining the content type.</em><br>
|
||||
<em>Otherwise, choose a method for determining the content type.</em><br />
|
||||
<input type="radio" id="autodetect"
|
||||
name="contenttypemethod" value="autodetect" checked="checked">
|
||||
<label for="autodetect">auto-detect</label><br>
|
||||
<label for="autodetect">auto-detect</label><br />
|
||||
<input type="radio" id="list"
|
||||
name="contenttypemethod" value="list">
|
||||
<label for="list">select from list</label>:
|
||||
<select name="contenttypeselection" id="contenttypeselection"
|
||||
onchange="this.form.contenttypemethod[1].checked = true;">
|
||||
[% PROCESS "attachment/content-types.html.tmpl" %]
|
||||
</select><br>
|
||||
</select><br />
|
||||
<input type="radio" id="manual"
|
||||
name="contenttypemethod" value="manual">
|
||||
<label for="manual">enter manually</label>:
|
||||
|
@ -123,7 +143,7 @@ function switch_afot(fot)
|
|||
<td> </td>
|
||||
<td>
|
||||
[% IF flag_types && flag_types.size > 0 %]
|
||||
[% PROCESS "flag/list.html.tmpl" bug_id=bugid attach_id=attachid %]<br>
|
||||
[% PROCESS "flag/list.html.tmpl" bug_id=bugid attach_id=attachid %]<br />
|
||||
[% END %]
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -272,7 +272,8 @@ TUI_hide_default('expert_fields');
|
|||
[% END %]
|
||||
|
||||
<form name="Create" id="Create" method="post" action="post_bug.cgi"
|
||||
enctype="multipart/form-data" onkeypress="return ctrlEnter(event||window.event,this)">
|
||||
enctype="multipart/form-data" onkeypress="return ctrlEnter(event||window.event,this)"
|
||||
onsubmit="return encodeSupaContent()">
|
||||
<input type="hidden" name="product" value="[% product.name FILTER html %]">
|
||||
<input type="hidden" name="token" value="[% token FILTER html %]">
|
||||
<input type="hidden" name="cloned_bug_id" value="[% cloned_bug_id FILTER html %]">
|
||||
|
|
|
@ -153,7 +153,7 @@
|
|||
|
||||
[% IF dotweak %]
|
||||
<td class="bz_checkbox_column">
|
||||
<input type="checkbox" name="id_[% bug.bug_id %]">
|
||||
<input type="checkbox" id="id_[% bug.bug_id %]" name="id_[% bug.bug_id %]" />
|
||||
</td>
|
||||
[% END %]
|
||||
|
||||
|
|
Loading…
Reference in New Issue