Commit c58edbae authored by Luc Didry's avatar Luc Didry
Browse files

Add "download zip" URL + better copy to clipboard method

parent c03082c2
Revision history for Lutim
0.7 ?
0.7 2016-06-21
- Use .po files for internationalization
- Add spanish translation (thx to Laura Arjona Reina)
- Allow Lutim to be on a sub-directory (like http://example.org/lutim/) (#46 and #57)
......@@ -19,6 +19,7 @@ Revision history for Lutim
- Use cryptographically secure random generator
- Allow to set the encryption length in lutim.conf
- Add the possibility of displaying images in a gallery
- Add the possibility to download a zip file
- bugfixes
0.6 2014-10-03
......
EXTRACTFILES=utilities/locales_files.txt
EN=lib/Lutim/I18N/en.po
FR=lib/Lutim/I18N/fr.po
DE=lib/Lutim/I18N/de.po
ES=lib/Lutim/I18N/es.po
XGETTEXT=carton exec local/bin/xgettext.pl
CARTON=carton exec
LUTIM=script/lutim
locales:
$(XGETTEXT) -W -f $(EXTRACTFILES) -o $(EN)
tx push -s
$(XGETTEXT) -W -f $(EXTRACTFILES) -o $(EN) 2>/dev/null
$(XGETTEXT) -W -f $(EXTRACTFILES) -o $(FR) 2>/dev/null
$(XGETTEXT) -W -f $(EXTRACTFILES) -o $(DE) 2>/dev/null
$(XGETTEXT) -W -f $(EXTRACTFILES) -o $(ES) 2>/dev/null
dev:
rm public/packed/*
......
......@@ -21,3 +21,4 @@ requires 'IO::Scalar';
requires 'Image::ExifTool';
requires 'Data::Entropy';
requires 'List::MoreUtils', '> 0.33';
requires 'Archive::Zip';
# carton snapshot format: version 1.0
DISTRIBUTIONS
Archive-Zip-1.57
pathname: P/PH/PHRED/Archive-Zip-1.57.tar.gz
provides:
Archive::Zip 1.57
Archive::Zip::Archive 1.57
Archive::Zip::BufferedFileHandle 1.57
Archive::Zip::DirectoryMember 1.57
Archive::Zip::FileMember 1.57
Archive::Zip::Member 1.57
Archive::Zip::MemberRead 1.57
Archive::Zip::MockFileHandle 1.57
Archive::Zip::NewFileMember 1.57
Archive::Zip::StringMember 1.57
Archive::Zip::Tree 1.57
Archive::Zip::ZipFileMember 1.57
requirements:
Compress::Raw::Zlib 2.017
ExtUtils::MakeMaker 0
File::Basename 0
File::Copy 0
File::Find 0
File::Path 0
File::Spec 0.80
File::Temp 0
IO::File 0
IO::Handle 0
IO::Seekable 0
Test::MockModule 0
Test::More 0.88
Time::Local 0
perl 5.006
CSS-Minifier-XS-0.09
pathname: G/GT/GTERMARS/CSS-Minifier-XS-0.09.tar.gz
provides:
......@@ -1847,6 +1878,22 @@ DISTRIBUTIONS
ExtUtils::MakeMaker 6.30
File::Spec 0
strict 0
SUPER-1.20141117
pathname: C/CH/CHROMATIC/SUPER-1.20141117.tar.gz
provides:
SUPER 1.20141117
requirements:
Scalar::Util 1.20
Sub::Identify 0.03
Test::Simple 0.61
perl v5.6.2
Sub-Identify-0.12
pathname: R/RG/RGARCIA/Sub-Identify-0.12.tar.gz
provides:
Sub::Identify 0.12
requirements:
ExtUtils::MakeMaker 0
Test::More 0
Sub-Uplevel-0.24
pathname: D/DA/DAGOLDEN/Sub-Uplevel-0.24.tar.gz
provides:
......@@ -1871,6 +1918,17 @@ DISTRIBUTIONS
Text::Balanced 2
if 0
perl 5.005
Test-MockModule-0.11
pathname: G/GF/GFRANKS/Test-MockModule-0.11.tar.gz
provides:
Test::MockModule 0.11
requirements:
Carp 0
Module::Build 0.38
SUPER 0
Scalar::Util 0
Test::More 0.45
perl 5.006
Test-Script-1.07
pathname: A/AD/ADAMK/Test-Script-1.07.tar.gz
provides:
......
......@@ -9,25 +9,25 @@
{
"uid": "12f4ece88e46abd864e40b35e05b11cd",
"css": "ok",
"code": 59402,
"code": 59392,
"src": "fontawesome"
},
{
"uid": "c5fd349cbd3d23e4ade333789c29c729",
"css": "eye",
"code": 59399,
"code": 59393,
"src": "fontawesome"
},
{
"uid": "9a76bc135eac17d2c8b8ad4a5774fc87",
"css": "download",
"code": 59397,
"code": 59394,
"src": "fontawesome"
},
{
"uid": "4aad6bb50b02c18508aae9cbe14e784e",
"css": "share",
"code": 59400,
"code": 59395,
"src": "fontawesome"
},
{
......@@ -39,37 +39,37 @@
{
"uid": "2cb15eb2b295ee3c33fab1530e18a924",
"css": "bitcoin",
"code": 59395,
"code": 59397,
"src": "fontawesome"
},
{
"uid": "e7cb72a17f3b21e3576f35c3f0a7639b",
"css": "git",
"code": 59393,
"code": 59398,
"src": "fontawesome"
},
{
"uid": "627abcdb627cb1789e009c08e2678ef9",
"css": "twitter",
"code": 59392,
"code": 59399,
"src": "fontawesome"
},
{
"uid": "1a27e6346cdf0480c9c22351378bebbb",
"css": "clipboard",
"code": 59401,
"code": 59400,
"src": "typicons"
},
{
"uid": "fccd3ea0efb711b849045bee686b1ceb",
"css": "spinner",
"code": 59398,
"code": 59401,
"src": "mfglabs"
},
{
"uid": "c71d7db10ede1349b3a8ae0293b1dbf8",
"css": "flattr",
"code": 59394,
"code": 59402,
"src": "zocial"
},
{
......@@ -81,8 +81,14 @@
{
"uid": "baa375529925294ea0a2bc889c93ba2d",
"css": "picture",
"code": 59405,
"code": 59404,
"src": "websymbols"
},
{
"uid": "e80ae555c1413a4ec18b33fb348b4049",
"css": "file-archive",
"code": 59405,
"src": "fontawesome"
}
]
}
\ No newline at end of file
......@@ -60,7 +60,7 @@ sub startup {
$filename = quote($filename);
my $asset;
unless ( -f $path && -r _ ) {
unless (-f $path && -r $path) {
$c->app->log->error("Cannot read file [$path]. error [$!]");
$c->flash(
msg => $c->l('Unable to find the image: it has been deleted.')
......@@ -130,7 +130,7 @@ sub startup {
my $short;
do {
$short= $c->shortener($c->config->{length});
} while (LutimModel::Lutim->count('WHERE short = ?', $short) || $short eq 'about' || $short eq 'stats' || $short eq 'd' || $short eq 'm' || $short eq 'gallery');
} while (LutimModel::Lutim->count('WHERE short = ?', $short) || $short eq 'about' || $short eq 'stats' || $short eq 'd' || $short eq 'm' || $short eq 'gallery' || $short eq 'zip');
LutimModel::Lutim->create(
short => $short,
......@@ -359,6 +359,10 @@ sub startup {
to('Controller#webapp')->
name('manifest.webapp');
$r->get('/zip')
->to('Controller#zip')
->name('zip');
$r->post('/')->
to('Controller#add')->
name('add');
......
......@@ -11,6 +11,7 @@ use Data::Validate::URI qw(is_http_uri is_https_uri);
use File::MimeInfo::Magic qw(mimetype extensions);
use IO::Scalar;
use Image::ExifTool;
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
use vars qw($im_loaded);
BEGIN {
......@@ -614,4 +615,109 @@ sub short {
}
}
sub zip {
my $c = shift;
my $imgs = $c->every_param('i');
my $zip = Archive::Zip->new();
# We HAVE to add a png file at the beginning, otherwise the $zip
# could use the mimetype of an SVG file if it's the first file asked.
$zip->addFile('public/img/favicon.png', 'hosted_with_lutim.png');
$zip->addDirectory('images/');
for my $img (@{$imgs}) {
my ($short, $key) = split('/', $img);
if (defined $key) {
$key =~ s/\.[^.]*//;
} else {
$short =~ s/\.[^.]*//;
}
my @images = LutimModel::Lutim->select('WHERE short = ? AND ENABLED = 1 AND path IS NOT NULL', $short);
if (scalar(@images)) {
my $filename = $images[0]->filename;
if($images[0]->delete_at_day && $images[0]->created_at + $images[0]->delete_at_day * 86400 <= time()) {
# Log deletion
$c->app->log->info('[DELETION] someone tried to view '.$images[0]->filename.' but it has been removed by expiration (path: '.$images[0]->path.')');
# Delete image
$c->delete_image($images[0]);
# Warn user
$zip->addString($c->l('Unable to find the image: it has been deleted.'), 'images/'.$filename.'.txt');
next;
}
# Delete image if needed
if ($images[0]->delete_at_first_view && $images[0]->counter >= 1) {
# Log deletion
$c->app->log->info('[DELETION] someone made '.$images[0]->filename.' removed (path: '.$images[0]->path.')');
# Delete image
$c->delete_image($images[0]);
$zip->addString($c->l('Unable to find the image: it has been deleted.'), 'images/'.$filename.'.txt');
next;
} else {
my $expires = ($images[0]->delete_at_day) ? $images[0]->delete_at_day : 360;
my $dt = DateTime->from_epoch( epoch => $expires * 86400 + $images[0]->created_at);
$dt->set_time_zone('GMT');
$expires = $dt->strftime("%a, %d %b %Y %H:%M:%S GMT");
my $path = $images[0]->path;
unless ( -f $path && -r $path ) {
$c->app->log->error("Cannot read file [$path]. error [$!]");
$zip->addString($c->l('Unable to find the image: it has been deleted.'), 'images/'.$filename.'.txt');
next;
}
if ($key) {
$zip->addString($c->decrypt($key, $path)->slurp, "images/$filename");
} else {
$zip->addFile($path, "images/$filename");
}
# Log access
$c->app->log->info('[VIEW] someone viewed '.$images[0]->filename.' (path: '.$images[0]->path.')');
# Update counter
$images[0]->update(counter => $images[0]->counter + 1);
# Update record
$images[0]->update(last_access_at => time());
}
} else {
@images = LutimModel::Lutim->select('WHERE short = ? AND ENABLED = 0 AND path IS NOT NULL', $short);
if (scalar(@images)) {
# Log access try
$c->app->log->info('[NOT FOUND] someone tried to view '.$short.' but it does\'nt exist anymore.');
# Warn user
$zip->addString($c->l('Unable to find the image: it has been deleted.'), 'images/'.$images[0]->filename.'.txt');
next;
} else {
$zip->addString($c->l('Image not found.'), 'images/'.$short.'.txt');
next;
}
}
}
my ($fh, $zipfile) = Archive::Zip::tempFile();
unless ($zip->writeToFileNamed($zipfile) == AZ_OK) {
$c->flash(
msg => $c->l('Something went wrong when creating the zip file. Try again later or contact the administrator (%1).', $c->config('contact'))
);
return $c->redirect_to('/');
}
$c->res->content->headers->content_type('application/zip;name=images.zip');
$c->res->content->headers->content_disposition('attachment;filename=images.zip');;
my $asset = Mojo::Asset::File->new(path => $zipfile);
$c->res->content->asset($asset);
$c->res->content->headers->content_length($asset->size);
unlink $zipfile;
return $c->rendered(200);
}
1;
......@@ -20,9 +20,9 @@ msgstr ""
#. ($delay)
#. (config('max_delay')
#: templates/partial/lutim.js.ep:141
#: templates/partial/lutim.js.ep:150
#: templates/partial/lutim.js.ep:151
#: templates/partial/lutim.js.ep:238
#: templates/partial/lutim.js.ep:247
#: templates/partial/lutim.js.ep:248
msgid "%1 days"
msgstr "%1 Tage"
......@@ -31,7 +31,7 @@ msgstr "%1 Tage"
msgid "%1 sent images on this instance from beginning."
msgstr "%1 Bilder wurden bisher über diese Instanz versendet."
#: templates/index.html.ep:172
#: templates/index.html.ep:190
msgid "-or-"
msgstr "-oder-"
......@@ -40,7 +40,7 @@ msgid "1 year"
msgstr "1 Jahr"
#: templates/index.html.ep:4
#: templates/partial/lutim.js.ep:150
#: templates/partial/lutim.js.ep:247
msgid "24 hours"
msgstr "24 Stunden"
......@@ -48,7 +48,7 @@ msgstr "24 Stunden"
msgid ": Error while trying to get the counter."
msgstr ":Fehler beim Abrufen des Zählers."
#: lib/Lutim/Controller.pm:269
#: lib/Lutim/Controller.pm:270
msgid "An error occured while downloading the image."
msgstr "Beim Herunterladen des Bildes ist ein Fehler aufgetreten."
......@@ -58,8 +58,8 @@ msgstr "Beim Herunterladen des Bildes ist ein Fehler aufgetreten."
msgid "Back to homepage"
msgstr "Zurück zur Hauptseite"
#: templates/index.html.ep:175
#: templates/index.html.ep:176
#: templates/index.html.ep:193
#: templates/index.html.ep:194
msgid "Click to open the file browser"
msgstr "Klicken um den Dateibrowser zu öffnen"
......@@ -67,21 +67,22 @@ msgstr "Klicken um den Dateibrowser zu öffnen"
msgid "Contributors"
msgstr "Mitwirkende"
#: templates/partial/lutim.js.ep:193
#: templates/partial/lutim.js.ep:238
#: templates/partial/lutim.js.ep:301
#: templates/partial/lutim.js.ep:313
#: templates/partial/lutim.js.ep:361
#: templates/partial/lutim.js.ep:435
msgid "Copy all view links to clipboard"
msgstr "Alle Links zum Anschauen in die Zwischenablage kopieren"
#: templates/index.html.ep:18
#: templates/index.html.ep:51
#: templates/index.html.ep:59
#: templates/index.html.ep:67
#: templates/index.html.ep:75
#: templates/partial/lutim.js.ep:129
#: templates/partial/lutim.js.ep:131
#: templates/partial/lutim.js.ep:133
#: templates/partial/lutim.js.ep:135
#: templates/index.html.ep:36
#: templates/index.html.ep:69
#: templates/index.html.ep:77
#: templates/index.html.ep:85
#: templates/index.html.ep:93
#: templates/partial/lutim.js.ep:180
#: templates/partial/lutim.js.ep:192
#: templates/partial/lutim.js.ep:206
#: templates/partial/lutim.js.ep:220
msgid "Copy to clipboard"
msgstr "In die Zwischenablage kopieren"
......@@ -89,15 +90,15 @@ msgstr "In die Zwischenablage kopieren"
msgid "Counter"
msgstr "Zähler"
#: templates/index.html.ep:129
#: templates/index.html.ep:160
#: templates/index.html.ep:97
#: templates/index.html.ep:115
#: templates/index.html.ep:147
#: templates/index.html.ep:178
#: templates/myfiles.html.ep:16
#: templates/partial/lutim.js.ep:159
#: templates/partial/lutim.js.ep:259
msgid "Delete at first view?"
msgstr "Nach erstem Aufruf löschen?"
#: templates/index.html.ep:80
#: templates/index.html.ep:98
#: templates/myfiles.html.ep:19
#: templates/partial/common.js.ep:36
msgid "Deletion link"
......@@ -108,13 +109,19 @@ msgstr "Link zum Löschen"
msgid "Download all images"
msgstr "Laden Sie alle Bilder"
#: templates/index.html.ep:63
#: templates/index.html.ep:65
#: templates/partial/lutim.js.ep:131
#: templates/index.html.ep:81
#: templates/index.html.ep:83
#: templates/partial/lutim.js.ep:198
#: templates/partial/lutim.js.ep:202
msgid "Download link"
msgstr "Link zum Herunterladen"
#: templates/index.html.ep:171
#: templates/index.html.ep:28
#: templates/index.html.ep:31
msgid "Download zip link"
msgstr "Link zum Archivbilder"
#: templates/index.html.ep:189
msgid "Drag & drop images here"
msgstr "Bilder hierher ziehen"
......@@ -122,12 +129,12 @@ msgstr "Bilder hierher ziehen"
msgid "Drag and drop an image in the appropriate area or use the traditional way to send files and Lutim will provide you four URLs. One to view the image, an other to directly download it, one you can use on social networks and a last to delete the image when you want."
msgstr "Ziehe Bilder in den dafür vorgesehenen Bereich und Lutim wird vier URLs generieren. Eine zum Anschauen, eine zum direkten Herunterladen, eine zum Nutzen in sozialen Netzwerken und eine letzte um das Bild zu löschen."
#: templates/index.html.ep:132
#: templates/index.html.ep:163
#: templates/index.html.ep:150
#: templates/index.html.ep:181
msgid "Encrypt the image (Lutim does not keep the key)."
msgstr "Verschlüssle das Bild (Lutim behält den Key nicht)"
#: templates/partial/lutim.js.ep:46
#: templates/partial/lutim.js.ep:74
msgid "Error while trying to modify the image."
msgstr "Beim bearbeiten des Bildes ist ein Fehler aufgetreten."
......@@ -156,8 +163,8 @@ msgstr "Fork me!"
msgid "Gallery link"
msgstr "Link zur Galerie"
#: templates/partial/lutim.js.ep:110
#: templates/partial/lutim.js.ep:76
#: templates/partial/lutim.js.ep:127
#: templates/partial/lutim.js.ep:145
msgid "Hit Enter, then Ctrl+C to copy the short link"
msgstr "Drücke Enter und dann STRG+C um den Kurz-Link zu kopieren."
......@@ -181,11 +188,15 @@ msgstr "Wie kann ich ein Bild melden?"
msgid "If the files are deleted if you ask it while posting it, their SHA512 footprint are retained."
msgstr "Wenn du versuchst, ein Bild während dem Hochladen zu löschen, wird die SHA512-Summe des Bildes behalten."
#: templates/index.html.ep:145
#: templates/index.html.ep:185
#: templates/index.html.ep:163
#: templates/index.html.ep:203
msgid "Image URL"
msgstr "Bild-URL"
#: lib/Lutim/Controller.pm:711
msgid "Image not found."
msgstr "Bild nicht gefunden"
#: templates/layouts/default.html.ep:49
msgid "Informations"
msgstr "Informationen"
......@@ -206,15 +217,15 @@ msgstr "Is es wirklich kostenlos?"
msgid "Juste like you pronounce the French word <a href=\"https://fr.wikipedia.org/wiki/Lutin\">lutin</a> (/ly.tɛ̃/)."
msgstr "Genauso wie das französische Wort <a href=\"https://fr.wikipedia.org/wiki/Lutin\">lutin</a> (/ly.tɛ̃/)."
#: templates/index.html.ep:135
#: templates/index.html.ep:166
#: templates/index.html.ep:153
#: templates/index.html.ep:184
msgid "Keep EXIF tags"
msgstr "Behalte EXIF-Daten"
#: templates/index.html.ep:100
#: templates/index.html.ep:148
#: templates/index.html.ep:188
#: templates/partial/lutim.js.ep:161
#: templates/index.html.ep:118
#: templates/index.html.ep:166
#: templates/index.html.ep:206
#: templates/partial/lutim.js.ep:263
msgid "Let's go!"
msgstr "Los gehts!"
......@@ -222,9 +233,10 @@ msgstr "Los gehts!"
msgid "License:"
msgstr "Lizenz:"
#: templates/index.html.ep:71
#: templates/index.html.ep:73
#: templates/partial/lutim.js.ep:133
#: templates/index.html.ep:89
#: templates/index.html.ep:91
#: templates/partial/lutim.js.ep:212
#: templates/partial/lutim.js.ep:216
msgid "Link for share on social networks"
msgstr "Links zum teilen auf sozialen Netzwerken"
......@@ -238,9 +250,10 @@ msgstr ""
msgid "Main developers"
msgstr "Haupt-Entwickler"
#: templates/index.html.ep:55
#: templates/index.html.ep:57
#: templates/partial/lutim.js.ep:129
#: templates/index.html.ep:73
#: templates/index.html.ep:75
#: templates/partial/lutim.js.ep:186
#: templates/partial/lutim.js.ep:189
msgid "Markdown syntax"
msgstr "Markdown Syntax"
......@@ -253,8 +266,8 @@ msgstr "Meine Bilder"
msgid "No limit"
msgstr "Keine Begrenzung"
#: templates/index.html.ep:147
#: templates/index.html.ep:180
#: templates/index.html.ep:165
#: templates/index.html.ep:198
msgid "Only images are allowed"
msgstr "Es sind nur Bilder erlaubt"
......@@ -275,11 +288,11 @@ msgstr "Kontaktiere den Administrator: %1"
msgid "Please wait"
msgstr "Warten Sie mal"
#: templates/index.html.ep:140
#: templates/index.html.ep:158
msgid "Send an image"
msgstr "Sende ein Bild"
#: templates/partial/lutim.js.ep:28
#: templates/partial/lutim.js.ep:53
msgid "Share it!"
msgstr "Teile es!"
......@@ -287,11 +300,16 @@ msgstr "Teile es!"
msgid "Share on Twitter"
msgstr "Teile es auf Twitter"
#: templates/index.html.ep:115
#: templates/partial/lutim.js.ep:164
#: templates/index.html.ep:133
#: templates/partial/lutim.js.ep:274
msgid "Something bad happened"
msgstr "Es ist ein Fehler aufgetreten"
#. ($c->config('contact')
#: lib/Lutim/Controller.pm:719
msgid "Something went wrong when creating the zip file. Try again later or contact the administrator (%1)."
msgstr "Es ist ein Fehler aufgetreten. Versuche es erneut oder kontaktiere den Administrator (%1)."
#: templates/about.html.ep:13
msgid "The IP address of the image's sender is retained for a delay which depends of the administrator's choice (for the official instance, which is located in France, it's one year)."
msgstr "Die IP-Adresse des Nutzers wird für eine bestimmte Zeit gespeichert. Diese kann der Administrator frei wählen (für die offizielle Instanz, die in Frankreich gehostet ist, liegt diese Zeit bei einem Jahr)"
......@@ -300,26 +318,26 @@ msgstr "Die IP-Adresse des Nutzers wird für eine bestimmte Zeit gespeichert. Di
msgid "The Lutim software is a <a href=\"http://en.wikipedia.org/wiki/Free_software\">free software</a>, which allows you to download and install it on you own server. Have a look at the <a href=\"https://www.gnu.org/licenses/agpl-3.0.html\">AGPL</a> to see what you can do."
msgstr "Lutim ist <a href=\"https://de.wikipedia.org/wiki/Freie_Software\">freie Software</a>, was dir erlaubt sie herunterzuladen und sie auf deinem eigenem Server zu installieren. Schau dir die <a href=\"https://www.gnu.org/licenses/agpl-3.0.html\">AGPL</a> an um deine Recht zu sehen."
#: lib/Lutim/Controller.pm:288
#: lib/Lutim/Controller.pm:289
msgid "The URL is not valid."
msgstr "Die URL ist nicht gültig."
#: lib/Lutim/Controller.pm:100
#: lib/Lutim/Controller.pm:169
#: lib/Lutim/Controller.pm:101
#: lib/Lutim/Controller.pm:170
msgid "The delete token is invalid."
msgstr "Das Token zum Löschen ist ungültig."
#. ($upload->filename)
#: lib/Lutim/Controller.pm:432
#: lib/Lutim/Controller.pm:433
msgid "The file %1 is not an image."
msgstr "Die Datei %1 ist kein Bild."
#. ($max_file_size)
#. ($tx->res->max_message_size)
#. ($c->req->max_message_size)