diff options
-rw-r--r-- | conf/general-example | 3 | ||||
-rw-r--r-- | perllib/Page.pm | 5 | ||||
-rw-r--r-- | web/css/core.css | 51 | ||||
-rwxr-xr-x | web/index.cgi | 58 | ||||
-rw-r--r-- | web/js.js | 89 | ||||
-rwxr-xr-x | web/upload.cgi | 56 |
6 files changed, 250 insertions, 12 deletions
diff --git a/conf/general-example b/conf/general-example index 7b3c79c72..701401540 100644 --- a/conf/general-example +++ b/conf/general-example @@ -14,7 +14,7 @@ * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. * Email: francis@mysociety.org; WWW: http://www.mysociety.org * - * $Id: general-example,v 1.15 2008-01-28 15:27:00 matthew Exp $ + * $Id: general-example,v 1.16 2008-03-29 03:03:34 matthew Exp $ * */ @@ -36,6 +36,7 @@ define('OPTION_CONTACT_EMAIL', 'team@example.org'); define('OPTION_CONTACT_NAME', 'FixMyStreet'); define('OPTION_STAGING_SITE', 1); +define('OPTION_UPLOAD_CACHE', '/upload/'); define('OPTION_GEO_CACHE', '/cache/'); define('OPTION_GOOGLE_MAPS_API_KEY', ''); diff --git a/perllib/Page.pm b/perllib/Page.pm index 916918686..8d0ac69d4 100644 --- a/perllib/Page.pm +++ b/perllib/Page.pm @@ -6,7 +6,7 @@ # Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ # -# $Id: Page.pm,v 1.83 2008-03-28 16:36:47 matthew Exp $ +# $Id: Page.pm,v 1.84 2008-03-29 03:03:35 matthew Exp $ # package Page; @@ -108,6 +108,9 @@ sub header ($%) { <html lang="en-gb"> <head> <script type="text/javascript" src="/yui/utilities.js"></script> + <script type="text/javascript" src="/jslib/swfupload/swfupload.js"></script> + <script type="text/javascript" src="/jslib/swfupload/FileProgress.js"></script> + <script type="text/javascript" src="/jslib/swfupload/swfupload.graceful_degradation.js"></script> <script type="text/javascript" src="/js.js"></script> <title>${title}FixMyStreet</title> <style type="text/css">\@import url("/css/core.css"); \@import url("/css/main.css");</style> diff --git a/web/css/core.css b/web/css/core.css index 9a40bd052..c2e32909a 100644 --- a/web/css/core.css +++ b/web/css/core.css @@ -357,3 +357,54 @@ p#copyright { #content { max-width: none; } #side { margin-right: 0; } } + +/* File upload */ +.progressContainer { + margin: 5px; + padding: 4px; + width: 357px; + border: solid 1px #E8E8E8; + background-color: #F7F7F7; + overflow: hidden; +} +.red { border: solid 1px #B50000; background-color: #FFEBEB; } +.green { border: solid 1px #DDF0DD; background-color: #EBFFEB; } +.blue { border: solid 1px #CEE2F2; background-color: #F0F5FF; } + +.progressName { + font-size: 8pt; + font-weight: bold; + color: #555555; + width: 323px; + height: 14px; + text-align: left; + white-space: nowrap; + overflow: hidden; +} +.progressBarInProgress, .progressBarComplete, .progressBarError { + font-size: 0px; + width: 0%; + height: 2px; + background-color: blue; + margin-top: 2px; +} +.progressBarComplete { + width: 100%; + background-color: green; + visibility: hidden; +} +.progressBarError { + width: 100%; + background-color: red; + visibility: hidden; +} +.progressBarStatus { + margin-top: 2px; + width: 337px; + font-size: 7pt; + font-family: Verdana; + text-align: left; + white-space: nowrap; +} + + diff --git a/web/index.cgi b/web/index.cgi index ee2586f39..3f5794a86 100755 --- a/web/index.cgi +++ b/web/index.cgi @@ -6,7 +6,7 @@ # Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org. WWW: http://www.mysociety.org # -# $Id: index.cgi,v 1.184 2008-03-28 16:36:48 matthew Exp $ +# $Id: index.cgi,v 1.185 2008-03-29 03:03:35 matthew Exp $ use strict; use Standard; @@ -155,7 +155,7 @@ EOF sub submit_update { my $q = shift; - my @vars = qw(id name email update fixed); + my @vars = qw(id name email update fixed upload_fileid); my %input = map { $_ => $q->param($_) || '' } @vars; my @errors; @@ -183,6 +183,12 @@ sub submit_update { }; } + if ($input{upload_fileid}) { + open FP, mySociety::Config::get('UPLOAD_CACHE') . $input{upload_fileid}; + $image = join('', <FP>); + close FP; + } + return display_problem($q, @errors) if (@errors); my $id = dbh()->selectrow_array("select nextval('comment_id_seq');"); @@ -217,7 +223,7 @@ sub workaround_pg_bytea { sub submit_problem { my $q = shift; - my @vars = qw(council title detail name email phone pc easting northing skipped anonymous category flickr); + my @vars = qw(council title detail name email phone pc easting northing skipped anonymous category flickr upload_fileid); my %input = map { $_ => scalar $q->param($_) } @vars; for (qw(title detail)) { $input{$_} = lc $input{$_} if $input{$_} !~ /[a-z]/; @@ -311,6 +317,12 @@ sub submit_problem { }; } + if ($input{upload_fileid}) { + open FP, mySociety::Config::get('UPLOAD_CACHE') . $input{upload_fileid}; + $image = join('', <FP>); + close FP; + } + return display_form($q, @errors) if (@errors); delete $input{council} if $input{council} eq '-1'; @@ -359,7 +371,7 @@ sub submit_problem { sub display_form { my ($q, @errors) = @_; my ($pin_x, $pin_y, $pin_tile_x, $pin_tile_y) = (0,0,0,0); - my @vars = qw(title detail name email phone pc easting northing x y skipped council anonymous flickr); + my @vars = qw(title detail name email phone pc easting northing x y skipped council anonymous flickr upload_fileid); my %input = map { $_ => $q->param($_) || '' } @vars; my %input_h = map { $_ => $q->param($_) ? ent($q->param($_)) : '' } @vars; my @ps = $q->param; @@ -546,8 +558,16 @@ EOF } } else { $out .= <<EOF; -<div><label for="form_photo">Photo:</label> -<input type="file" name="photo" id="form_photo"></div> +<div id="fileupload_flashUI" style="display:none"> +<label for="form_photo">Photo:</label> +<input type="text" id="txtfilename" disabled="true" style="background-color: #ffffff;"> +<input type="button" value="Browse..." onclick="document.getElementById('txtfilename').value=''; swfu.cancelUpload(); swfu.selectFile();"> +<input type="hidden" name="upload_fileid" id="upload_fileid" value="$input_h{upload_fileid}"> +</div> +<div id="fileupload_normalUI"> +<label for="form_photo">Photo:</label> +<input type="file" name="photo" id="form_photo"> +</div> EOF } $out .= <<EOF; @@ -576,6 +596,11 @@ directly using their own website. </div> EOF $out .= Page::display_map_end(1); + $out .= <<EOF; +<script type="text/javascript"> +swfu = new SWFUpload(swfu_settings); +</script> +EOF return $out; } @@ -678,7 +703,7 @@ EOF sub display_problem { my ($q, @errors) = @_; - my @vars = qw(id name email update fixed x y); + my @vars = qw(id name email update fixed upload_fileid x y); my %input = map { $_ => $q->param($_) || '' } @vars; my %input_h = map { $_ => $q->param($_) ? ent($q->param($_)) : '' } @vars; $input{x} ||= 0; $input{x} += 0; @@ -761,12 +786,25 @@ EOF <div><label for="form_update">Update:</label> <textarea name="update" id="form_update" rows="7" cols="30">$input_h{update}</textarea></div> $fixedline -<div><label for="form_photo">Photo:</label> -<input type="file" name="photo" id="form_photo"></div> -<div class="checkbox"><input type="submit" value="Post"></div> +<div id="fileupload_flashUI" style="display:none"> +<label for="form_photo">Photo:</label> +<input type="text" id="txtfilename" disabled="true" style="background-color: #ffffff;"> +<input type="button" value="Browse..." onclick="document.getElementById('txtfilename').value=''; swfu.cancelUpload(); swfu.selectFile();"> +<input type="hidden" name="upload_fileid" id="upload_fileid" value="$input_h{upload_fileid}"> +</div> +<div id="fileupload_normalUI"> +<label for="form_photo">Photo:</label> +<input type="file" name="photo" id="form_photo"> +</div> +<div class="checkbox"><input type="submit" id="update_post" value="Post"></div> </form> EOF $out .= Page::display_map_end(0); + $out .= <<EOF; +<script type="text/javascript"> +swfu = new SWFUpload(swfu_settings); +</script> +EOF my %params = ( rss => [ 'Updates to this problem, FixMyStreet', "/rss/$input_h{id}" ], @@ -56,6 +56,10 @@ YAHOO.util.Event.onContentReady('mapForm', function() { } this.x.value = x + 2; this.y.value = y + 2; + if (swfu && swfu.getStats().files_queued > 0) { + swfu.startUpload(); + return false; + } return true; } }); @@ -110,6 +114,91 @@ YAHOO.util.Event.onContentReady('email_alert_box', function() { }); }); +/* File upload */ +function doSubmit(e) { + e = e || window.event; + if (e.stopPropagation) e.stopPropagation(); + e.cancelBubble = true; + try { + if (swfu.getStats().files_queued > 0) + swfu.startUpload(); + else + return true; + } catch (e) {} + return false; +} + +function uploadDone() { + var m = document.getElementById('mapForm'); + if (m) { + m.submit(); + } else { + document.getElementById('fieldset').submit(); + } +} + +var swfu; +var swfu_settings = { + upload_url : "http://matthew.bci.mysociety.org/upload.cgi", + flash_url : "http://matthew.bci.mysociety.org/jslib/swfupload/swfupload_f9.swf", + file_size_limit : "10240", + file_types : "*.jpg;*.jpeg;*.pjpeg", + file_types_description : "JPEG files", + file_upload_limit : "0", + + swfupload_loaded_handler : function() { + var d = document.getElementById("fieldset"); + if (d) d.onsubmit = doSubmit; + }, + file_queued_handler : function(obj) { + document.getElementById('txtfilename').value = obj.name; + }, +//file_queue_error_handler : fileQueueError, + // file_dialog_complete_handler : fileDialogComplete, +//upload_start_handler : uploadStartEventHandler, + upload_progress_handler : function(obj, bytesLoaded, bytesTotal) { + var percent = Math.ceil((bytesLoaded / bytesTotal) * 100); + obj.id = "singlefile"; + var progress = new FileProgress(obj, this.customSettings.progress_target); + progress.setProgress(percent); + progress.setStatus("Uploading..."); + }, + upload_success_handler : function(obj, server_data) { + obj.id = "singlefile"; + var progress = new FileProgress(obj, this.customSettings.progress_target); + progress.setComplete(); + progress.setStatus("Complete!"); + if (server_data == ' ') { + this.customSettings.upload_successful = false; + } else { + this.customSettings.upload_successful = true; + document.getElementById('upload_fileid').value = server_data; + } + }, + upload_complete_handler : function(obj) { + if (this.customSettings.upload_successful) { + var d = document.getElementById('update_post'); + if (d) d.disabled = 'true'; + uploadDone(); + } else { + obj.id = 'singlefile'; + var progress = new FileProgress(obj, this.customSettings.progress_target); + progress.setError(); + progress.setStatus("File rejected"); + document.getElementById('txtfilename').value = ''; + } + + }, +//upload_error_handler : uploadError, + + swfupload_element_id : "fileupload_flashUI", + degraded_element_id : "fileupload_normalUI", + custom_settings : { + upload_successful : false, + progress_target : 'fileupload_flashUI' + } +}; + // I love the global var tile_x = 0; var tile_y = 0; diff --git a/web/upload.cgi b/web/upload.cgi new file mode 100755 index 000000000..bc42716f8 --- /dev/null +++ b/web/upload.cgi @@ -0,0 +1,56 @@ +#!/usr/bin/perl -w -I../perllib -I../../perllib + +# upload.cgi: +# Receiver of flash upload files +# +# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved. +# Email: matthew@mysociety.org. WWW: http://www.mysociety.org +# +# $Id: upload.cgi,v 1.1 2008-03-29 03:03:35 matthew Exp $ + +use strict; +use Standard -db; + +use Error qw(:try); +use Image::Magick; +use mySociety::Random qw(random_bytes); + +# Main code for index.cgi +sub main { + my $q = shift; + + print $q->header(-type => 'text/plain'); + my $out = ' '; + try { + my $fh = $q->upload('Filedata'); + my $image; + if ($fh) { + $q->delete('photo'); # Can't check content/type when uploaded with Flash + $image = process_photo($fh); + my $name = unpack('H*', random_bytes(12)); + open FP, '>/data/vhost/matthew.bci.mysociety.org/photos/' . $name or throw Error::Simple('could not open file'); + print FP $image; + close FP; + $out = $name; + }; + } catch Error::Simple with { + my $e = shift; + }; + print $out; +} +Page::do_fastcgi(\&main); + +sub process_photo { + my $fh = shift; + my $photo = Image::Magick->new; + my $err = $photo->Read(file => \*$fh); # Mustn't be stringified + close $fh; + throw Error::Simple("read failed: $err") if "$err"; + $err = $photo->Scale(geometry => "250x250>"); + throw Error::Simple("resize failed: $err") if "$err"; + my @blobs = $photo->ImageToBlob(); + undef $photo; + $photo = $blobs[0]; + return $photo; +} + |