Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
241e8b8ea1 | ||
|
|
e0f13489a4 | ||
|
|
1ca3137dd1 | ||
|
|
b791c609c2 | ||
|
|
388feba7c0 | ||
|
|
542d3efdf5 | ||
|
|
a57815a2ea | ||
|
|
44c0d5a9c9 | ||
|
|
ebb5282579 | ||
|
|
d03ce97c8b | ||
|
|
a4ca866790 | ||
|
|
73b09d28c6 | ||
|
|
5c45be0099 | ||
|
|
150f27bf9b | ||
|
|
d0b388834f | ||
|
|
e951a44324 | ||
|
|
9fcefcdbd4 | ||
|
|
05892366d8 | ||
|
|
989412046b | ||
|
|
f2baf273ca | ||
|
|
420a37ee75 | ||
|
|
940faed363 | ||
|
|
f86b0e71d1 | ||
|
|
7f99d73691 | ||
|
|
4633fdacef | ||
|
|
bf0e2d47b9 | ||
|
|
f044c1e953 | ||
|
|
277053d2a8 | ||
|
|
b450ea7607 | ||
|
|
510bfb3eed |
5
Changes
@@ -1,5 +1,10 @@
|
||||
Revision history for Lutim
|
||||
|
||||
0.4 2014-07-12
|
||||
- Webapp ! Downloadable directly from the Lutim instance
|
||||
- Configure expiration delay after uploading (#12)
|
||||
- Twitter share button in the "upload success" message (#35)
|
||||
|
||||
0.3 2014-06-01
|
||||
- Add a delete link to images (#28)
|
||||
- Concatenated css and js with Mojolicious::Plugin::AssetPack
|
||||
|
||||
47
README.md
@@ -58,26 +58,26 @@ vi lutim.conf
|
||||
## Configuration
|
||||
The `lutim.conf.template` is self-documented but here is the options that you can set:
|
||||
|
||||
* hypnotoad: address and port to listen to, user and group which runs hypnotoad (if you run Lutim with a different user from what is defined here, be sure that the user which launchs hypnotoad is able to setuid/setgid to the defined user/group, otherwise it will not work and you'll have 100% CPU consumption. Launch hypnotoad with the root user or with the user which is defined here);
|
||||
* contact: write something which make people able to contact you (contact form URL, email address, whatever);
|
||||
* secrets: an array of random string. Used by Mojolicious for encrypting session cookies.
|
||||
* piwik_img: the Piwik image provides you records of visits without javascript (better privacy than js and cookies);
|
||||
* length: length of the random string part of image's URL (default is 8);
|
||||
* provis_step: Lutim provisions random strings for image's URL per pack of `provis_step` (default is 5);
|
||||
* provisioning: number of random strings to provision (default is 100);
|
||||
* hosted_by: if someone hosts your Lutim instance, you can add some HTML (a logo for example) to make it appear on index page;
|
||||
* tweet_card_via: a Twitter account which will appear on Twitter cards;
|
||||
* max_file_size: well, this is explicit (default is 10Mio = 10485760 octets);
|
||||
* https: 1 if you want to provide secure images URLs (default is 0) DEPRECATED, PASS A `X-Forwarded-Proto` HEADER TO LUTIM FROM YOUR REVERSE PROXY INSTEAD;
|
||||
* token_length: length of the secret token used to allow people to delete their images when they want;
|
||||
* stats_day_num: when you generate statistics with `script/lutim cron stats`, you will have stats for the last `stats_day_num` days (default is 365);
|
||||
* keep_ip_during: when you delete IP addresses of image's senders with `script/lutim cron cleanbdd`, the IP addresses of images older than `keep_ip_during` days will be deleted (default is 365);
|
||||
* broadcast_message: put some string (not HTML) here and this message will be displayed on all Lutim pages (not in JSON responses);
|
||||
* allowed_domains: array of authorized domains for API calls. Example: `['http://1.example.com', 'http://2.example.com']`. If you want to authorize everyone to use the API: `['\*']`.
|
||||
* default_delay: what is the default time limit for files? Valid values are 0, 1, 7, 30 and 365;
|
||||
* max_delay: if defined, the images will be deleted after that delay (in days), even if they were uploaded with "no delay" (or value superior to max_delay) option and a warning message will be displayed on homepage;
|
||||
* always_encrypt: if set to 1, all images will be encrypted.
|
||||
* delete_no_longer_viewed_files: if set, the images which have not been viewed since `delete_no_longer_viewed_files` days will be deleted by the `script/lutim cron cleanfiles` command
|
||||
* **hypnotoad :** address and port to listen to, user and group which runs hypnotoad (if you run Lutim with a different user from what is defined here, be sure that the user which launchs hypnotoad is able to setuid/setgid to the defined user/group, otherwise it will not work and you'll have 100% CPU consumption. Launch hypnotoad with the root user or with the user which is defined here);
|
||||
* **contact :** write something which make people able to contact you (contact form URL, email address, whatever);
|
||||
* **secrets :** an array of random string. Used by Mojolicious for encrypting session cookies.
|
||||
* **piwik_img :** the Piwik image provides you records of visits without javascript (better privacy than js and cookies);
|
||||
* **length :** length of the random string part of image's URL (default is 8);
|
||||
* **provis_step :** Lutim provisions random strings for image's URL per pack of `provis_step` (default is 5);
|
||||
* **provisioning :** number of random strings to provision (default is 100);
|
||||
* **hosted_by :** if someone hosts your Lutim instance, you can add some HTML (a logo for example) to make it appear on index page;
|
||||
* **tweet_card_via :** a Twitter account which will appear on Twitter cards;
|
||||
* **max_file_size :** well, this is explicit (default is 10Mio = 10485760 octets);
|
||||
* **https :** 1 if you want to provide secure images URLs (default is 0) DEPRECATED, PASS A `X-Forwarded-Proto` HEADER TO LUTIM FROM YOUR REVERSE PROXY INSTEAD;
|
||||
* **token_length :** length of the secret token used to allow people to delete their images when they want;
|
||||
* **stats_day_num :** when you generate statistics with `script/lutim cron stats`, you will have stats for the last `stats_day_num` days (default is 365);
|
||||
* **keep_ip_during :** when you delete IP addresses of image's senders with `script/lutim cron cleanbdd`, the IP addresses of images older than `keep_ip_during` days will be deleted (default is 365);
|
||||
* **broadcast_message :** put some string (not HTML) here and this message will be displayed on all Lutim pages (not in JSON responses);
|
||||
* **allowed_domains :** array of authorized domains for API calls. Example: `['http://1.example.com', 'http://2.example.com']`. If you want to authorize everyone to use the API: `['\*']`.
|
||||
* **default_delay :** what is the default time limit for files? Valid values are 0, 1, 7, 30 and 365;
|
||||
* **max_delay :** if defined, the images will be deleted after that delay (in days), even if they were uploaded with "no delay" (or value superior to max_delay) option and a warning message will be displayed on homepage;
|
||||
* **always_encrypt :** if set to 1, all images will be encrypted.
|
||||
* **delete_no_longer_viewed_files :** if set, the images which have not been viewed since `delete_no_longer_viewed_files` days will be deleted by the `script/lutim cron cleanfiles` command
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -264,7 +264,7 @@ Lutim comes with English and French languages. It will choose the language to di
|
||||
|
||||
If you want to add more languages, for example German:
|
||||
```shell
|
||||
cd lib/I18N
|
||||
cd lib/Lutim/I18N
|
||||
cp en.pm de.pm
|
||||
vim de.pm
|
||||
```
|
||||
@@ -274,8 +274,9 @@ There's just a few sentences, so it will be quick to translate. Please consider
|
||||
## Others projects dependancies
|
||||
Lutim is written in Perl with the [Mojolicious](http://mojolicio.us) framework, uses the [Twitter bootstrap](http://getbootstrap.com) framework to look not too ugly, [JQuery](http://jquery.com) and [JQuery File Uploader](https://github.com/danielm/uploader/) (slightly modified) to add some modernity, [Raphaël](http://raphaeljs.com/) and [morris.js](http://www.oesmith.co.uk/morris.js/) for stats graphs.
|
||||
|
||||
## Core developer
|
||||
* Luc Didry, aka Sky (<http://www.fiat-tux.fr>), main developer, [@framasky](https://twitter.com/framasky)
|
||||
## Main developers
|
||||
* Luc Didry, aka Sky (<http://www.fiat-tux.fr>), core developer, [@framasky](https://twitter.com/framasky)
|
||||
* Dattaz (<http://dattaz.fr>), webapp developer, [@dat_taz](https://twitter.com/dat_taz)
|
||||
|
||||
## Contributors
|
||||
* Jean-Bernard Marcon, aka Goofy (<https://github.com/goofy-bz>)
|
||||
|
||||
2
cpanfile
@@ -1,5 +1,5 @@
|
||||
requires 'Mojolicious';
|
||||
requires 'IO::Socket::SSL';
|
||||
requires 'EV';
|
||||
requires 'Data::Validate::URI';
|
||||
requires 'Mojolicious::Plugin::I18N';
|
||||
requires 'Mojolicious::Plugin::ConfigHashMerge';
|
||||
|
||||
@@ -8,6 +8,13 @@ DISTRIBUTIONS
|
||||
Algorithm::DiffOld 1.1
|
||||
requirements:
|
||||
ExtUtils::MakeMaker 0
|
||||
CSS-Minifier-XS-0.09
|
||||
pathname: G/GT/GTERMARS/CSS-Minifier-XS-0.09.tar.gz
|
||||
provides:
|
||||
CSS::Minifier::XS 0.09
|
||||
requirements:
|
||||
ExtUtils::CBuilder 0
|
||||
Test::More 0
|
||||
Carp-1.3301
|
||||
pathname: Z/ZE/ZEFRAM/Carp-1.3301.tar.gz
|
||||
provides:
|
||||
@@ -224,16 +231,16 @@ DISTRIBUTIONS
|
||||
Data::Validate::Domain 0
|
||||
Data::Validate::IP 0
|
||||
ExtUtils::MakeMaker 0
|
||||
DateTime-1.08
|
||||
pathname: D/DR/DROLSKY/DateTime-1.08.tar.gz
|
||||
DateTime-1.10
|
||||
pathname: D/DR/DROLSKY/DateTime-1.10.tar.gz
|
||||
provides:
|
||||
DateTime 1.08
|
||||
DateTime::Duration 1.08
|
||||
DateTime::Helpers 1.08
|
||||
DateTime::Infinite 1.08
|
||||
DateTime::Infinite::Future 1.08
|
||||
DateTime::Infinite::Past 1.08
|
||||
DateTime::LeapSecond 1.08
|
||||
DateTime 1.10
|
||||
DateTime::Duration 1.10
|
||||
DateTime::Helpers 1.10
|
||||
DateTime::Infinite 1.10
|
||||
DateTime::Infinite::Future 1.10
|
||||
DateTime::Infinite::Past 1.10
|
||||
DateTime::LeapSecond 1.10
|
||||
inc::MyModuleBuild undef
|
||||
requirements:
|
||||
Carp 0
|
||||
@@ -244,9 +251,6 @@ DISTRIBUTIONS
|
||||
POSIX 0
|
||||
Params::Validate 0.76
|
||||
Scalar::Util 0
|
||||
Storable 0
|
||||
Test::Fatal 0
|
||||
Test::More 0.88
|
||||
Try::Tiny 0
|
||||
XSLoader 0
|
||||
base 0
|
||||
@@ -255,9 +259,9 @@ DISTRIBUTIONS
|
||||
overload 0
|
||||
perl 5.008001
|
||||
strict 0
|
||||
utf8 0
|
||||
vars 0
|
||||
warnings 0
|
||||
warnings::register 0
|
||||
DateTime-Locale-0.45
|
||||
pathname: D/DR/DROLSKY/DateTime-Locale-0.45.tar.gz
|
||||
provides:
|
||||
@@ -1187,6 +1191,14 @@ DISTRIBUTIONS
|
||||
base 0
|
||||
strict 0
|
||||
warnings 0
|
||||
EV-4.17
|
||||
pathname: M/ML/MLEHMANN/EV-4.17.tar.gz
|
||||
provides:
|
||||
EV 4.17
|
||||
EV::MakeMaker undef
|
||||
requirements:
|
||||
ExtUtils::MakeMaker 0
|
||||
common::sense 0
|
||||
Exception-Class-1.37
|
||||
pathname: D/DR/DROLSKY/Exception-Class-1.37.tar.gz
|
||||
provides:
|
||||
@@ -1306,6 +1318,17 @@ DISTRIBUTIONS
|
||||
requirements:
|
||||
IO::File 0.01
|
||||
Test::More 0.01
|
||||
File-Which-1.09
|
||||
pathname: A/AD/ADAMK/File-Which-1.09.tar.gz
|
||||
provides:
|
||||
File::Which 1.09
|
||||
requirements:
|
||||
Exporter 0
|
||||
ExtUtils::MakeMaker 0
|
||||
File::Spec 0.60
|
||||
Getopt::Std 0
|
||||
Test::More 0.80
|
||||
Test::Script 1.05
|
||||
Filesys-DiskUsage-0.05
|
||||
pathname: C/CO/COG/Filesys-DiskUsage-0.05.tar.gz
|
||||
provides:
|
||||
@@ -1323,16 +1346,18 @@ DISTRIBUTIONS
|
||||
ExtUtils::MakeMaker 6.31
|
||||
Storable 0
|
||||
Test::Most 0
|
||||
IO-Socket-SSL-1.982
|
||||
pathname: S/SU/SULLR/IO-Socket-SSL-1.982.tar.gz
|
||||
IO-Socket-SSL-1.997
|
||||
pathname: S/SU/SULLR/IO-Socket-SSL-1.997.tar.gz
|
||||
provides:
|
||||
IO::Socket::SSL 1.982
|
||||
IO::Socket::SSL 1.997
|
||||
IO::Socket::SSL::Intercept 1.93
|
||||
IO::Socket::SSL::OCSP_Cache 1.997
|
||||
IO::Socket::SSL::OCSP_Resolver 1.997
|
||||
IO::Socket::SSL::PublicSuffix undef
|
||||
IO::Socket::SSL::SSL_Context 1.982
|
||||
IO::Socket::SSL::SSL_HANDLE 1.982
|
||||
IO::Socket::SSL::Session_Cache 1.982
|
||||
IO::Socket::SSL::Utils 0.02
|
||||
IO::Socket::SSL::SSL_Context 1.997
|
||||
IO::Socket::SSL::SSL_HANDLE 1.997
|
||||
IO::Socket::SSL::Session_Cache 1.997
|
||||
IO::Socket::SSL::Utils 0.03
|
||||
requirements:
|
||||
ExtUtils::MakeMaker 0
|
||||
Net::SSLeay 1.46
|
||||
@@ -1345,6 +1370,14 @@ DISTRIBUTIONS
|
||||
ExtUtils::MakeMaker 0
|
||||
Test::More 0.31
|
||||
Time::HiRes 0
|
||||
JavaScript-Minifier-XS-0.09
|
||||
pathname: G/GT/GTERMARS/JavaScript-Minifier-XS-0.09.tar.gz
|
||||
provides:
|
||||
JavaScript::Minifier::XS 0.09
|
||||
requirements:
|
||||
ExtUtils::CBuilder 0
|
||||
Test::More 0
|
||||
perl v5.8.8
|
||||
List-MoreUtils-0.33
|
||||
pathname: A/AD/ADAMK/List-MoreUtils-0.33.tar.gz
|
||||
provides:
|
||||
@@ -1459,8 +1492,8 @@ DISTRIBUTIONS
|
||||
perl 5.006
|
||||
strict 0
|
||||
warnings 0
|
||||
Mojolicious-4.97
|
||||
pathname: S/SR/SRI/Mojolicious-4.97.tar.gz
|
||||
Mojolicious-5.12
|
||||
pathname: S/SR/SRI/Mojolicious-5.12.tar.gz
|
||||
provides:
|
||||
Mojo undef
|
||||
Mojo::Asset undef
|
||||
@@ -1523,7 +1556,7 @@ DISTRIBUTIONS
|
||||
Mojo::UserAgent::Server undef
|
||||
Mojo::UserAgent::Transactor undef
|
||||
Mojo::Util undef
|
||||
Mojolicious 4.97
|
||||
Mojolicious 5.12
|
||||
Mojolicious::Command undef
|
||||
Mojolicious::Command::cgi undef
|
||||
Mojolicious::Command::cpanify undef
|
||||
@@ -1572,6 +1605,19 @@ DISTRIBUTIONS
|
||||
requirements:
|
||||
ExtUtils::MakeMaker 0
|
||||
perl 5.010001
|
||||
Mojolicious-Plugin-AssetPack-0.16
|
||||
pathname: J/JH/JHTHORSEN/Mojolicious-Plugin-AssetPack-0.16.tar.gz
|
||||
provides:
|
||||
Mojolicious::Plugin::AssetPack 0.16
|
||||
Mojolicious::Plugin::AssetPack::Preprocessors 0.01
|
||||
requirements:
|
||||
CSS::Minifier::XS 0.01
|
||||
ExtUtils::MakeMaker 0
|
||||
File::Which 1.00
|
||||
IPC::Run3 0.04
|
||||
JavaScript::Minifier::XS 0.01
|
||||
Mojolicious 4.30
|
||||
Test::More 0.88
|
||||
Mojolicious-Plugin-ConfigHashMerge-0.01
|
||||
pathname: D/DO/DOTAN/Mojolicious-Plugin-ConfigHashMerge-0.01.tar.gz
|
||||
provides:
|
||||
@@ -1580,14 +1626,14 @@ DISTRIBUTIONS
|
||||
ExtUtils::MakeMaker 0
|
||||
Hash::Merge::Simple 0.051
|
||||
Mojolicious 4.85
|
||||
Mojolicious-Plugin-I18N-1.21
|
||||
pathname: S/SH/SHARIFULN/Mojolicious-Plugin-I18N-1.21.tar.gz
|
||||
Mojolicious-Plugin-I18N-1.3
|
||||
pathname: S/SH/SHARIFULN/Mojolicious-Plugin-I18N-1.3.tar.gz
|
||||
provides:
|
||||
Mojolicious::Plugin::I18N 1.21
|
||||
Mojolicious::Plugin::I18N 1.3
|
||||
requirements:
|
||||
I18N::LangTags 0.35
|
||||
Module::Build 0.42
|
||||
Mojolicious 4
|
||||
Mojolicious 5
|
||||
Test::More 0
|
||||
perl 5.010001
|
||||
Net-Domain-TLD-1.70
|
||||
@@ -2004,12 +2050,13 @@ DISTRIBUTIONS
|
||||
Algorithm::Diff 1.19
|
||||
Exporter 0
|
||||
ExtUtils::MakeMaker 0
|
||||
Text-Unidecode-0.04
|
||||
pathname: S/SB/SBURKE/Text-Unidecode-0.04.tar.gz
|
||||
Text-Unidecode-1.01
|
||||
pathname: S/SB/SBURKE/Text-Unidecode-1.01.tar.gz
|
||||
provides:
|
||||
Text::Unidecode 0.04
|
||||
Text::Unidecode 1.01
|
||||
requirements:
|
||||
ExtUtils::MakeMaker 0
|
||||
perl 5.008
|
||||
Try-Tiny-0.19
|
||||
pathname: D/DO/DOY/Try-Tiny-0.19.tar.gz
|
||||
provides:
|
||||
@@ -2021,3 +2068,9 @@ DISTRIBUTIONS
|
||||
constant 0
|
||||
strict 0
|
||||
warnings 0
|
||||
common-sense-3.73
|
||||
pathname: M/ML/MLEHMANN/common-sense-3.73.tar.gz
|
||||
provides:
|
||||
common::sense 3.73
|
||||
requirements:
|
||||
ExtUtils::MakeMaker 0
|
||||
|
||||
22
lib/Lutim.pm
@@ -10,6 +10,8 @@ mkdir($ENV{MOJO_TMPDIR}, 0700) unless (-d $ENV{MOJO_TMPDIR});
|
||||
sub startup {
|
||||
my $self = shift;
|
||||
|
||||
push @{$self->commands->namespaces}, 'Lutim::Command';
|
||||
|
||||
$self->{wait_for_it} = {};
|
||||
|
||||
$self->plugin('I18N');
|
||||
@@ -86,11 +88,7 @@ sub startup {
|
||||
my $c = shift;
|
||||
my $ip_only = shift || 0;
|
||||
|
||||
my $proxy = '';
|
||||
my @x_forward = $c->req->headers->header('X-Forwarded-For');
|
||||
for my $x (@x_forward) {
|
||||
$proxy .= join(', ', @$x);
|
||||
}
|
||||
my $proxy = $c->req->headers->header('X-Forwarded-For');
|
||||
|
||||
my $ip = ($proxy) ? $proxy : $c->tx->remote_address;
|
||||
|
||||
@@ -111,7 +109,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');
|
||||
} while (LutimModel::Lutim->count('WHERE short = ?', $short) || $short eq 'about' || $short eq 'stats' || $short eq 'd' || $short eq 'm');
|
||||
|
||||
LutimModel::Lutim->create(
|
||||
short => $short,
|
||||
@@ -292,8 +290,8 @@ sub startup {
|
||||
);
|
||||
|
||||
$self->asset('index.css' => 'css/bootstrap.min.css', 'css/fontello-embedded.css', 'css/animation.css', 'css/uploader.css', 'css/hennypenny.css', 'css/lutim.css');
|
||||
$self->asset('stats.css' => 'css/bootstrap.min.css', 'css/fontello-embedded.css', 'css/animation.css', 'css/morris-0.4.3.min.css', 'css/hennypenny.css', 'css/lutim.css');
|
||||
$self->asset('about.css' => 'css/bootstrap.min.css', 'css/fontello-embedded.css', 'css/animation.css', 'css/hennypenny.css', 'css/lutim.css');
|
||||
$self->asset('stats.css' => 'css/bootstrap.min.css', 'css/fontello-embedded.css', 'css/morris-0.4.3.min.css', 'css/hennypenny.css', 'css/lutim.css');
|
||||
$self->asset('about.css' => 'css/bootstrap.min.css', 'css/fontello-embedded.css', 'css/hennypenny.css', 'css/lutim.css');
|
||||
|
||||
$self->asset('index.js' => 'js/jquery-2.1.0.min.js', 'js/bootstrap.min.js', 'js/lutim.js', 'js/dmuploader.min.js');
|
||||
$self->asset('stats.js' => 'js/jquery-2.1.0.min.js', 'js/bootstrap.min.js', 'js/lutim.js', 'js/raphael-min.js', 'js/morris-0.4.3.min.js', 'js/stats.js');
|
||||
@@ -323,6 +321,10 @@ sub startup {
|
||||
to('Controller#stats')->
|
||||
name('stats');
|
||||
|
||||
$r->get('/manifest.webapp')->
|
||||
to('Controller#webapp')->
|
||||
name('manifest.webapp');
|
||||
|
||||
$r->post('/')->
|
||||
to('Controller#add')->
|
||||
name('add');
|
||||
@@ -331,6 +333,10 @@ sub startup {
|
||||
to('Controller#delete')->
|
||||
name('delete');
|
||||
|
||||
$r->post('/m/:short/:token')->
|
||||
to('Controller#modify')->
|
||||
name('modify');
|
||||
|
||||
$r->get('/:short')->
|
||||
to('Controller#short')->
|
||||
name('short');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package Mojolicious::Command::cron;
|
||||
package Lutim::Command::cron;
|
||||
use Mojo::Base 'Mojolicious::Commands';
|
||||
|
||||
has description => 'Execute tasks.';
|
||||
@@ -7,7 +7,7 @@ has hint => <<EOF;
|
||||
See 'script/lutim cron help TASK' for more information on a specific task.
|
||||
EOF
|
||||
has message => sub { shift->extract_usage . "\nCron tasks:\n" };
|
||||
has namespaces => sub { ['Mojolicious::Command::cron'] };
|
||||
has namespaces => sub { ['Lutim::Command::cron'] };
|
||||
|
||||
sub help { shift->run(@_) }
|
||||
|
||||
@@ -17,7 +17,7 @@ sub help { shift->run(@_) }
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Command::cron - Cron commands
|
||||
Lutim::Command::cron - Cron commands
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package Mojolicious::Command::cron::cleanbdd;
|
||||
package Lutim::Command::cron::cleanbdd;
|
||||
use Mojo::Base 'Mojolicious::Command';
|
||||
use LutimModel;
|
||||
use Mojo::Util qw(slurp decode);
|
||||
@@ -28,7 +28,7 @@ sub run {
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Command::cron::cleanbdd - Delete IP addresses from database after configured delay
|
||||
Lutim::Command::cron::cleanbdd - Delete IP addresses from database after configured delay
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package Mojolicious::Command::cron::cleanfiles;
|
||||
package Lutim::Command::cron::cleanfiles;
|
||||
use Mojo::Base 'Mojolicious::Command';
|
||||
use LutimModel;
|
||||
use Mojo::Util qw(slurp decode);
|
||||
@@ -32,7 +32,7 @@ sub run {
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Command::cron::cleanfiles - Delete expired files
|
||||
Lutim::Command::cron::cleanfiles - Delete expired files
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package Mojolicious::Command::cron::stats;
|
||||
package Lutim::Command::cron::stats;
|
||||
use Mojo::Base 'Mojolicious::Command';
|
||||
use LutimModel;
|
||||
use Mojo::DOM;
|
||||
@@ -55,7 +55,7 @@ sub run {
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Command::cron::stats - Stats generator
|
||||
Lutim::Command::cron::stats - Stats generator
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package Mojolicious::Command::cron::watch;
|
||||
package Lutim::Command::cron::watch;
|
||||
use Mojo::Base 'Mojolicious::Command';
|
||||
use Mojo::Util qw(slurp decode);
|
||||
use Filesys::DiskUsage qw/du/;
|
||||
@@ -56,7 +56,7 @@ sub run {
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Command::cron::watch - Delete IP addresses from database after configured delay
|
||||
Lutim::Command::cron::watch - Delete IP addresses from database after configured delay
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
@@ -46,6 +46,89 @@ sub stats {
|
||||
);
|
||||
}
|
||||
|
||||
sub webapp {
|
||||
my $c = shift;
|
||||
|
||||
my $headers = Mojo::Headers->new();
|
||||
$headers->add('Content-Type' => 'application/x-web-app-manifest+json');
|
||||
$c->res->content->headers($headers);
|
||||
|
||||
$c->render(
|
||||
template => 'manifest',
|
||||
format => 'webapp'
|
||||
);
|
||||
}
|
||||
|
||||
sub modify {
|
||||
my $c = shift;
|
||||
my $short = $c->param('short');
|
||||
my $token = $c->param('token');
|
||||
my $url = $c->param('url');
|
||||
|
||||
my @images = LutimModel::Lutim->select('WHERE short = ? AND path IS NOT NULL', $short);
|
||||
if (scalar(@images)) {
|
||||
my $image = $images[0];
|
||||
my $msg;
|
||||
if ($image->mod_token() ne $token || $token eq '') {
|
||||
$msg = $c->l('invalid_token');
|
||||
} else {
|
||||
$c->app->log->info('[MODIFICATION] someone modify '.$image->filename.' with token method (path: '.$image->path.')');
|
||||
|
||||
$image->update(
|
||||
delete_at_day => ($c->param('delete-day') && $c->param('delete-day') <= $c->max_delay) ? $c->param('delete-day') : $c->max_delay,
|
||||
delete_at_first_view => ($c->param('first-view')) ? 1 : 0,
|
||||
);
|
||||
$msg = $c->l('image_delay_modified');
|
||||
if (defined($c->param('format')) && $c->param('format') eq 'json') {
|
||||
return $c->render(
|
||||
json => {
|
||||
success => Mojo::JSON->true,
|
||||
msg => $msg
|
||||
}
|
||||
);
|
||||
} else {
|
||||
$msg .= ' (<a href="'.$url.'">'.$url.'</a>)' unless (!defined($url));
|
||||
$c->flash(
|
||||
success => $msg
|
||||
);
|
||||
return $c->redirect_to('/');
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($c->param('format')) && $c->param('format') eq 'json') {
|
||||
return $c->render(
|
||||
json => {
|
||||
success => Mojo::JSON->false,
|
||||
msg => $msg
|
||||
}
|
||||
);
|
||||
} else {
|
||||
$c->flash(
|
||||
msg => $msg
|
||||
);
|
||||
return $c->redirect_to('/');
|
||||
}
|
||||
} else {
|
||||
$c->app->log->info('[UNSUCCESSFUL] someone tried to modify '.$short.' but it does\'nt exist.');
|
||||
|
||||
# Image never existed
|
||||
my $msg = $c->l('image_mod_not_found', $short);
|
||||
if (defined($c->param('format')) && $c->param('format') eq 'json') {
|
||||
return $c->render(
|
||||
json => {
|
||||
success => Mojo::JSON->false,
|
||||
msg => $msg
|
||||
}
|
||||
);
|
||||
} else {
|
||||
$c->flash(
|
||||
msg => $msg
|
||||
);
|
||||
return $c->redirect_to('/');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub delete {
|
||||
my $c = shift;
|
||||
my $short = $c->param('short');
|
||||
@@ -55,7 +138,7 @@ sub delete {
|
||||
if (scalar(@images)) {
|
||||
my $image = $images[0];
|
||||
my $msg;
|
||||
if ($image->mod_token() ne $token) {
|
||||
if ($image->mod_token() ne $token || $token eq '') {
|
||||
$msg = $c->l('invalid_token');
|
||||
} elsif ($image->enabled() == 0) {
|
||||
$msg = $c->l('already_deleted', $image->filename);
|
||||
@@ -227,6 +310,11 @@ sub add {
|
||||
# Give url to user
|
||||
$short = $records[0]->short;
|
||||
$real_short = $short;
|
||||
if (!defined($records[0]->mod_token)) {
|
||||
$records[0]->update(
|
||||
mod_token => $c->shortener($c->config->{token_length})
|
||||
);
|
||||
}
|
||||
$token = $records[0]->mod_token;
|
||||
$short .= '/'.$key if (defined($key));
|
||||
} else {
|
||||
@@ -332,12 +420,26 @@ sub short {
|
||||
filename => $images[0]->filename
|
||||
);
|
||||
} 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");
|
||||
# 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.')');
|
||||
|
||||
$test = $c->render_file($images[0]->filename, $images[0]->path, $images[0]->mediatype, $dl, $expires, $images[0]->delete_at_first_view, $key);
|
||||
# Delete image
|
||||
$c->delete_image($images[0]);
|
||||
|
||||
$c->flash(
|
||||
msg => $c->l('image_not_found')
|
||||
);
|
||||
return $c->redirect_to('/');
|
||||
} 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");
|
||||
|
||||
$test = $c->render_file($images[0]->filename, $images[0]->path, $images[0]->mediatype, $dl, $expires, $images[0]->delete_at_first_view, $key);
|
||||
}
|
||||
}
|
||||
|
||||
if ($test != 500) {
|
||||
@@ -367,7 +469,7 @@ sub short {
|
||||
|
||||
if (scalar(@images)) {
|
||||
# Log access try
|
||||
$c->app->log->info('[NOT FOUND] someone tried to view '.$short.' but it does\'nt exist.');
|
||||
$c->app->log->info('[NOT FOUND] someone tried to view '.$short.' but it does\'nt exist anymore.');
|
||||
|
||||
# Warn user
|
||||
$c->flash(
|
||||
|
||||
@@ -21,9 +21,10 @@ my $inf_body = <<EOF;
|
||||
<h4>What about the software which provides the service?</h4>
|
||||
<p>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.</p>
|
||||
<p>For more details, see the <a href="https://github.com/ldidry/lutim">Github</a> page of the project.</p>
|
||||
<h4>Core developer</h4>
|
||||
<h4>Main developers</h4>
|
||||
<ul>
|
||||
<li>Luc Didry, aka Sky (<a href="http://www.fiat-tux.fr">http://www.fiat-tux.fr</a>), main developer</li>
|
||||
<li>Luc Didry, aka Sky (<a href="http://www.fiat-tux.fr">http://www.fiat-tux.fr</a>), core developer, <a href="https://twitter.com/framasky">\@framasky</a></li>
|
||||
<li>Dattaz (<a href="http://dattaz.fr">http://dattaz.fr</a>), webapp developer, <a href="https://twitter.com/dat_taz">\@dat_taz</a></li>
|
||||
</ul>
|
||||
<h4>Contributors</h4>
|
||||
<ul>
|
||||
@@ -43,6 +44,8 @@ our %Lexicon = (
|
||||
'view-link' => 'View link',
|
||||
'download-link' => 'Download link',
|
||||
'twitter-link' => 'Link for put in a tweet',
|
||||
'tweet_it' => 'Tweet it!',
|
||||
'share_it' => 'Share it!',
|
||||
'delete-link' => 'Deletion link',
|
||||
'some-bad' => 'Something bad happened',
|
||||
'delete-first' => 'Delete at first view?',
|
||||
@@ -81,6 +84,10 @@ our %Lexicon = (
|
||||
'image_deleted' => 'The image [_1] has been successfully deleted',
|
||||
'invalid_token' => 'The delete token is invalid.',
|
||||
'already_deleted' => 'The image [_1] has already been deleted.',
|
||||
'install_as_webapp' => 'Install webapp',
|
||||
'image_delay_modified' => 'The image\'s delay has been successfully modified',
|
||||
'image_mod_not_found' => 'Unable to find the image [_1].',
|
||||
'modify_image_error' => 'Error while trying to modify the image.',
|
||||
);
|
||||
|
||||
1;
|
||||
|
||||
@@ -21,9 +21,10 @@ my $inf_body = <<EOF;
|
||||
<h4>Et à propos du logiciel qui fournit le service ?</h4>
|
||||
<p>Le logiciel Lutim est un <a href="https://fr.wikipedia.org/wiki/Logiciel_libre">logiciel libre</a>, ce qui vous permet de le télécharger et de l’installer sur votre propre serveur. Jetez un coup d’œil à l’<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL</a> pour voir quels sont vos droits.</p>
|
||||
<p>Pour plus de détails, consultez la page <a href="https://github.com/ldidry/lutim">Github</a> du projet.</p>
|
||||
<h4>Développeur de l'application</h4>
|
||||
<h4>Développeurs de l'application</h4>
|
||||
<ul>
|
||||
<li>Luc Didry, aka Sky (<a href="http://www.fiat-tux.fr">http://www.fiat-tux.fr</a>), développeur principal</li>
|
||||
<li>Luc Didry, aka Sky (<a href="http://www.fiat-tux.fr">http://www.fiat-tux.fr</a>), développeur principal, <a href="https://twitter.com/framasky">\@framasky</a></li>
|
||||
<li>Dattaz (<a href="http://dattaz.fr">http://dattaz.fr</a>), développeur de la webapp, <a href="https://twitter.com/dat_taz">\@dat_taz</a></li>
|
||||
</ul>
|
||||
<h4>Contributeurs</h4>
|
||||
<ul>
|
||||
@@ -43,6 +44,8 @@ our %Lexicon = (
|
||||
'view-link' => 'Lien d\'affichage',
|
||||
'download-link' => 'Lien de téléchargement',
|
||||
'twitter-link' => 'Lien pour mettre dans un tweet',
|
||||
'tweet_it' => 'Tweetez !',
|
||||
'share_it' => 'Partagez !',
|
||||
'delete-link' => 'Lien de suppression',
|
||||
'some-bad' => 'Un problème est survenu',
|
||||
'delete-first' => 'Supprimer au premier accès ?',
|
||||
@@ -81,6 +84,10 @@ our %Lexicon = (
|
||||
'image_deleted' => 'L\'image [_1] a été supprimée avec succès.',
|
||||
'invalid_token' => 'Le jeton de suppression est invalide.',
|
||||
'already_deleted' => 'L\'image [_1] a déjà été supprimée.',
|
||||
'install_as_webapp' => 'Installer la webapp',
|
||||
'image_delay_modified' => 'Le délai de l\'image a été modifié avec succès.',
|
||||
'image_mod_not_found' => 'Impossible de trouver l\'image [_1].',
|
||||
'modify_image_error' => 'Une erreur est survenue lors de la tentative de modification de l\'image.',
|
||||
);
|
||||
|
||||
1;
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
body {
|
||||
padding-top: 40px;
|
||||
padding-bottom: 40px;
|
||||
@media (max-width: 767px) {
|
||||
body {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
body {
|
||||
padding-top: 40px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
@@ -32,3 +41,10 @@ label.always-encrypt {
|
||||
color: #000000;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#install-app img {
|
||||
height: 22px;
|
||||
}
|
||||
#install-app {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,18 @@
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
@media (max-width:768px){
|
||||
.uploader div.browser label {
|
||||
max-width:95%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width:768px){
|
||||
.uploader div.browser label {
|
||||
width:300px;
|
||||
}
|
||||
}
|
||||
|
||||
.uploader div.browser label {
|
||||
background-color: #5a7bc2;
|
||||
padding: 5px 15px;
|
||||
@@ -38,7 +50,6 @@
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
width: 300px;
|
||||
margin: 20px auto 0px auto;
|
||||
|
||||
box-shadow: 2px 2px 2px #888888;
|
||||
|
||||
BIN
public/img/lutim120.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/img/lutim128.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/img/lutim152.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
public/img/lutim196.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
public/img/lutim256.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
public/img/lutim32.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
public/img/lutim60.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
public/img/lutim76.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
public/img/lutim90.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
public/img/rocket.png
Normal file
|
After Width: | Height: | Size: 509 B |
@@ -1,3 +1,26 @@
|
||||
$('document').ready(function() {
|
||||
$('.jsonly').show();
|
||||
// Are we in a mozilla navigator? (well, are we in a navigator which can handle webapps?)
|
||||
if (navigator.mozApps !== undefined) {
|
||||
var installCheck = navigator.mozApps.checkInstalled(manifestUrl);
|
||||
installCheck.onsuccess = function() {
|
||||
if(installCheck.result === null) {
|
||||
var button = $('#install-app');
|
||||
// Show app install button when app is not installed
|
||||
button.css('display','inline-block');
|
||||
button.click(function() {
|
||||
var request = window.navigator.mozApps.install(manifestUrl);
|
||||
request.onsuccess = function () {
|
||||
// Save the App object that is returned
|
||||
var appRecord = this.result;
|
||||
button.css('display','none');
|
||||
};
|
||||
request.onerror = function () {
|
||||
// Display the error information from the DOMError object
|
||||
alert('Install failed, error: ' + this.error.name);
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
<img class="pull-left thumbnail" alt="<%= stash('filename') %> thumbnail" src="<%= stash('thumb') %>">
|
||||
% }
|
||||
<div>
|
||||
% # Display image informations
|
||||
% my $url = url_for('/')->to_abs().stash('short');
|
||||
<strong><%= stash('filename') %></strong>
|
||||
<a target="_blank" class="btn btn-default btn-primary btn-xs" href="https://twitter.com/share?url=<%= $url %>?t"><%=l 'tweet_it' %></a>
|
||||
<ul class="list-unstyled">
|
||||
% my $url = url_for('/')->to_abs().stash('short');
|
||||
% my $delete_url = url_for('delete', {short => stash('real_short'), token => stash('token')})->to_abs();
|
||||
<li><i class="icon icon-eye" title =" <%= l 'view-link' %>"></i> <%= link_to $url => begin %> <%= $url %> <%= end %></li>
|
||||
<li><i class="icon icon-download" title =" <%= l 'download-link' %>"></i> <%= link_to $url.'?dl' => begin %> <%= $url.'?dl' %> <%= end %></li>
|
||||
@@ -19,12 +21,49 @@
|
||||
<li><i class="icon icon-trash" title =" <%= l 'delete-link' %>"></i> <%= link_to $delete_url => begin %> <%= $delete_url %> <%= end %></li>
|
||||
</ul>
|
||||
</div>
|
||||
% # Delay modification form
|
||||
% my $modify_url = url_for('modify', {short => stash('real_short'), token => stash('token')})->to_abs();
|
||||
<form class="form" role="form" method="POST" action="<%== $modify_url %>">
|
||||
<div class="form-group form-inline">
|
||||
<input name="image_url" type="hidden" value="<%= $url %>">
|
||||
<select name="delete-day" class="form-control">
|
||||
% for my $delay (qw/0 1 7 30 365/) {
|
||||
% my $text = ($delay == 7 || $delay == 30) ? l('delay_days', $delay) : l("delay_$delay");
|
||||
% if (config('max_delay')) {
|
||||
% if ($delay) {
|
||||
% if ($delay < config('max_delay')) {
|
||||
<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>
|
||||
% } elsif ($delay == config('max_delay')) {
|
||||
<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>
|
||||
% last;
|
||||
% } else {
|
||||
% my $text = ($delay == 1) ? l('delay_1') : l('delay_days', $delay);
|
||||
<option value="<%= config('max_delay') %>" <%== is_selected(config('max_delay')) %>><%=l('delay_days', config('max_delay')) %></option>
|
||||
% last;
|
||||
% }
|
||||
% }
|
||||
% } else {
|
||||
<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>
|
||||
% }
|
||||
% }
|
||||
</select>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="first-view"> <%=l 'delete-first' %>
|
||||
</label>
|
||||
<label <%== (config('always_encrypt')) ? 'class="always-encrypt"' : '' %>>
|
||||
<input type="checkbox" name="crypt"> <%=l 'crypt_image' %>
|
||||
</label>
|
||||
</div>
|
||||
<%= submit_button l('go'), class => 'btn btn-sm btn-default btn-primary', id => 'submitbutton' %>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
% }
|
||||
% if (defined(flash('success'))) {
|
||||
<div class="alert alert-success">
|
||||
<button type="button" class="close jsonly" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
<%= flash('success') %>
|
||||
<p><%== flash('success') %></p>
|
||||
</div>
|
||||
% }
|
||||
% if (defined(flash('msg'))) {
|
||||
@@ -38,48 +77,48 @@
|
||||
|
||||
<noscript>
|
||||
<form class="form" role="form" method="POST" action="<%== url_for('add') %>" enctype="multipart/form-data">
|
||||
<div class="form-group form-inline">
|
||||
<select name="delete-day" class="form-control">
|
||||
% for my $delay (qw/0 1 7 30 365/) {
|
||||
% my $text = ($delay == 7 || $delay == 30) ? l('delay_days', $delay) : l("delay_$delay");
|
||||
% if (config('max_delay')) {
|
||||
% if ($delay) {
|
||||
% if ($delay < config('max_delay')) {
|
||||
<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>
|
||||
% } elsif ($delay == config('max_delay')) {
|
||||
<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>
|
||||
% last;
|
||||
% } else {
|
||||
% my $text = ($delay == 1) ? l('delay_1') : l('delay_days', $delay);
|
||||
<option value="<%= config('max_delay') %>" <%== is_selected(config('max_delay')) %>><%=l('delay_days', config('max_delay')) %></option>
|
||||
% last;
|
||||
% }
|
||||
% }
|
||||
% } else {
|
||||
<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>
|
||||
% }
|
||||
% }
|
||||
</select>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="first-view"> <%=l 'delete-first' %>
|
||||
</label>
|
||||
<label <%== (config('always_encrypt')) ? 'class="always-encrypt"' : '' %>>
|
||||
<input type="checkbox" name="crypt"> <%=l 'crypt_image' %>
|
||||
</label>
|
||||
<div class="form-group form-inline">
|
||||
<select name="delete-day" class="form-control">
|
||||
% for my $delay (qw/0 1 7 30 365/) {
|
||||
% my $text = ($delay == 7 || $delay == 30) ? l('delay_days', $delay) : l("delay_$delay");
|
||||
% if (config('max_delay')) {
|
||||
% if ($delay) {
|
||||
% if ($delay < config('max_delay')) {
|
||||
<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>
|
||||
% } elsif ($delay == config('max_delay')) {
|
||||
<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>
|
||||
% last;
|
||||
% } else {
|
||||
% my $text = ($delay == 1) ? l('delay_1') : l('delay_days', $delay);
|
||||
<option value="<%= config('max_delay') %>" <%== is_selected(config('max_delay')) %>><%=l('delay_days', config('max_delay')) %></option>
|
||||
% last;
|
||||
% }
|
||||
% }
|
||||
% } else {
|
||||
<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>
|
||||
% }
|
||||
% }
|
||||
</select>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="first-view"> <%=l 'delete-first' %>
|
||||
</label>
|
||||
<label <%== (config('always_encrypt')) ? 'class="always-encrypt"' : '' %>>
|
||||
<input type="checkbox" name="crypt"> <%=l 'crypt_image' %>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="lutim-file"><%=l 'upload_image' %></label>
|
||||
<input type="file" name="file" id="lutim-file" accept="image/*">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="lutim-file-url"><%=l 'upload_image_url' %></label>
|
||||
<input type="url" name="lutim-file-url" placeholder="<%=l 'image_url' %>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="lutim-file"><%=l 'upload_image' %></label>
|
||||
<input type="file" name="file" id="lutim-file">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="lutim-file-url"><%=l 'upload_image_url' %></label>
|
||||
<input type="url" name="lutim-file-url" placeholder="<%=l 'image_url' %>">
|
||||
<p class="help-block"><%=l 'image-only' %></p>
|
||||
</div>
|
||||
<%= submit_button l('go'), class => 'btn btn-default btn-primary', id => 'submitbutton' %>
|
||||
</form>
|
||||
<%= submit_button l('go'), class => 'btn btn-default btn-primary', id => 'submitbutton' %>
|
||||
</form>
|
||||
</noscript>
|
||||
|
||||
<!-- D&D Zone-->
|
||||
@@ -121,15 +160,15 @@
|
||||
<div class="browser">
|
||||
<label>
|
||||
<span><%=l 'file-browser' %></span>
|
||||
<input type="file" name="files[]" multiple="multiple" title='<%=l 'file-browser' %>'>
|
||||
<input type="file" name="files[]" multiple="multiple" title='<%=l 'file-browser' %>' accept="image/*">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block"><%=l 'image-only' %></p>
|
||||
<form class="form-horizontal" role="form" method="POST" action="<%== url_for('add') %>">
|
||||
<div class="form-group">
|
||||
<span class="col-sm-3"><span class="hidden-spin" style="font-size:200%; display:none;" > <i class="icon-spinner animate-spin pull-right"></i></span><label for="lutim-file-url" class="control-label pull-right"><%=l 'upload_image_url' %></label></span>
|
||||
<div class="col-sm-9">
|
||||
<span class="col-sm-3 col-xs-12"><span class="hidden-spin" style="font-size:200%; display:none;" > <i class="icon-spinner animate-spin pull-right"></i></span><label for="lutim-file-url" class="control-label pull-right"><%=l 'upload_image_url' %></label></span>
|
||||
<div class="col-sm-9 col-xs-12">
|
||||
<input type="url" name="lutim-file-url" class="form-control" id="lutim-file-url" placeholder="<%=l 'image_url' %>">
|
||||
</div>
|
||||
</div>
|
||||
@@ -139,15 +178,55 @@
|
||||
<!-- /D&D Zone -->
|
||||
|
||||
%= javascript begin
|
||||
function link(url, dl, token) {
|
||||
function link(url, dl, token, modify) {
|
||||
if (token !== undefined) {
|
||||
url = 'd/'+url+'/'+token;
|
||||
if (modify !== undefined && modify === true) {
|
||||
return '<%== url_for('index')->to_abs() %>m/'+url+'/'+token;
|
||||
} else {
|
||||
url = 'd/'+url+'/'+token;
|
||||
}
|
||||
} else if (dl !== '') {
|
||||
url = url+'?'+dl;
|
||||
}
|
||||
return '<a href="<%== url_for('index')->to_abs() %>'+url+'"><%== url_for('index')->to_abs() %>'+url+'</a>';
|
||||
}
|
||||
function message(success, msg) {
|
||||
function share(url) {
|
||||
console.log(url);
|
||||
new MozActivity({
|
||||
name: "share",
|
||||
data: {
|
||||
type: "url",
|
||||
number: 1,
|
||||
url: url
|
||||
}
|
||||
});
|
||||
}
|
||||
function tw_url(url) {
|
||||
var btn = ' <a target="_blank" class="btn btn-default btn-primary btn-xs" href="https://twitter.com/share?url=<%== url_for('index')->to_abs() %>'+url+'?t"><%=l 'tweet_it' %></a>';
|
||||
if (navigator.mozSetMessageHandler !== undefined) {
|
||||
btn = btn+' <a target="_blank" class="btn btn-default btn-primary btn-xs" href="" onclick="share(\'<%== url_for('index')->to_abs() %>'+url+'?t\');return false;"><%=l 'share_it' %></a>';
|
||||
}
|
||||
return btn
|
||||
}
|
||||
function modify(url, short) {
|
||||
$.ajax({
|
||||
url : url,
|
||||
type : "POST",
|
||||
data : {
|
||||
'image_url' : '<%== url_for('index')->to_abs() %>'+short,
|
||||
'format' : 'json',
|
||||
'first-view' : ($("#first-view-"+short).prop('checked')) ? 1 : 0,
|
||||
'delete-day' : $("#day-"+short).val()
|
||||
},
|
||||
success: function(data) {
|
||||
alert(data.msg);
|
||||
},
|
||||
error: function() {
|
||||
alert('<%=l 'modify_image_error' %>');
|
||||
}
|
||||
});
|
||||
}
|
||||
function build_message(success, msg) {
|
||||
if(success) {
|
||||
var thumb = (msg.thumb !== null) ? '<img class="pull-left thumbnail" alt="'+msg.filename+' thumbnail" src="'+msg.thumb+'">' : ''
|
||||
return '<div class="alert alert-success"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>'
|
||||
@@ -155,6 +234,7 @@
|
||||
+'<div><strong>'
|
||||
+msg.filename
|
||||
+'</strong>'
|
||||
+tw_url(msg.short)
|
||||
+'<ul class="list-unstyled"><li><i class="icon icon-eye" title="<%=l 'view-link' %>"></i> '
|
||||
+link(msg.short, '')
|
||||
+'</li><li><i class="icon icon-download" title="<%=l 'download-link' %>"></i> '
|
||||
@@ -163,7 +243,32 @@
|
||||
+link(msg.short, 't')
|
||||
+'</li><li><i class="icon icon-trash" title="<%=l 'delete-link' %>"></i> '
|
||||
+link(msg.real_short, '', msg.token)
|
||||
+'</li></ul></div>';
|
||||
+'</li></ul><form class="form" role="form" method="POST" action="'
|
||||
+link(msg.real_short, '', msg.token, true)
|
||||
+'"><div class="form-group form-inline"><select id="day-'+msg.real_short+'" name="delete-day" class="form-control">'
|
||||
% for my $delay (qw/0 1 7 30 365/) {
|
||||
% my $text = ($delay == 7 || $delay == 30) ? l('delay_days', $delay) : l("delay_$delay");
|
||||
% if (config('max_delay')) {
|
||||
% if ($delay) {
|
||||
% if ($delay < config('max_delay')) {
|
||||
+'<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>'
|
||||
% } elsif ($delay == config('max_delay')) {
|
||||
+'<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>'
|
||||
% last;
|
||||
% } else {
|
||||
% my $text = ($delay == 1) ? l('delay_1') : l('delay_days', $delay);
|
||||
+'<option value="<%= config('max_delay') %>" <%== is_selected(config('max_delay')) %>><%=l('delay_days', config('max_delay')) %></option>'
|
||||
% last;
|
||||
% }
|
||||
% }
|
||||
% } else {
|
||||
+'<option value="<%= $delay %>" <%== is_selected($delay) %>><%= $text %></option>'
|
||||
% }
|
||||
% }
|
||||
+'</select> <div class="checkbox"><label><input id="first-view-'+msg.real_short+'" type="checkbox" name="first-view"> <%=l 'delete-first' %></label>'
|
||||
+'</div> '
|
||||
+'<a href="#" onclick="modify(\''+link(msg.real_short, '', msg.token, true)+'\', \''+msg.real_short+'\');return false;" class="btn btn-sm btn-default btn-primary"><%=l 'go' %></a></div></form>'
|
||||
+'</div>';
|
||||
} else {
|
||||
return '<div class="alert alert-danger"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button><strong><%=l 'some-bad' %></strong><br>'
|
||||
+msg.filename
|
||||
@@ -186,17 +291,16 @@
|
||||
$('#'+id).prop('aria-valuenow', percent);
|
||||
$('#'+id).prop('style', 'width: '+percent+'%;');
|
||||
$('#'+id+'-text').html(percentStr);
|
||||
|
||||
},
|
||||
onUploadSuccess: function(id, data){
|
||||
$('#'+id+'-div').remove();
|
||||
$(".messages").append(message(data.success, data.msg));
|
||||
$(".messages").append(build_message(data.success, data.msg));
|
||||
},
|
||||
onUploadError: function(id, message){
|
||||
$(".messages").append(message(false, ''));
|
||||
$(".messages").append(build_message(false, ''));
|
||||
},
|
||||
onFileSizeError: function(file){
|
||||
$(".messages").append(message(false, { filename: file.name, msg: '<%= l('file_too_big', $max_file_size) %>'}));
|
||||
$(".messages").append(build_message(false, { filename: file.name, msg: '<%= l('file_too_big', $max_file_size) %>'}));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -218,13 +322,13 @@
|
||||
'delete-day' : $("#delete-day").val()
|
||||
},
|
||||
success: function(data) {
|
||||
$(".messages").append(message(data.success, data.msg));
|
||||
$(".messages").append(build_message(data.success, data.msg));
|
||||
if (data.success) {
|
||||
$("#lutim-file-url").val('');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$(".messages").append(message(false, ''));
|
||||
$(".messages").append(build_message(false, ''));
|
||||
},
|
||||
complete: function() {
|
||||
$("#lutim-file-url").prop('disabled', '');
|
||||
@@ -236,6 +340,67 @@
|
||||
}
|
||||
}
|
||||
|
||||
function fileUpload(file) {
|
||||
var fd = new FormData();
|
||||
fd.append('file', file);
|
||||
|
||||
fd.append('format', 'json');
|
||||
fd.append('first-view', ($("#first-view").prop('checked')) ? 1 : 0);
|
||||
fd.append('crypt', ($("#crypt").prop('checked')) ? 1 : 0);
|
||||
fd.append('delete-day', ($("#delete-day").val()));
|
||||
|
||||
$(".messages").append('<div id="1-div">'+file.name+'<br><div class="progress"><div id="1"class="progress-bar progress-striped active" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"><span id="1-text" class="pull-left" style="padding-left: 10px;"> 0%</span></div></div></div>');
|
||||
// Ajax Submit
|
||||
$.ajax({
|
||||
url: '<%== url_for('add') %>',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: fd,
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
forceSync: false,
|
||||
xhr: function(){
|
||||
var xhrobj = $.ajaxSettings.xhr();
|
||||
if(xhrobj.upload){
|
||||
xhrobj.upload.addEventListener('progress', function(event) {
|
||||
var percent = 0;
|
||||
var position = event.loaded || event.position;
|
||||
var total = event.total || e.totalSize;
|
||||
if(event.lengthComputable){
|
||||
percent = Math.ceil(position / total * 100);
|
||||
}
|
||||
|
||||
var percentStr = ' '+percent+'%';
|
||||
$('#1').prop('aria-valuenow', percent);
|
||||
$('#1').prop('style', 'width: '+percent+'%;');
|
||||
$('#1-text').html(percentStr);
|
||||
}, false);
|
||||
}
|
||||
|
||||
return xhrobj;
|
||||
},
|
||||
success: function (data, message, xhr){
|
||||
$('#1-div').remove();
|
||||
$(".messages").append(build_message(data.success, data.msg));
|
||||
},
|
||||
error: function (xhr, status, errMsg){
|
||||
$(".messages").append(build_message(false, ''));
|
||||
},
|
||||
});
|
||||
}
|
||||
window.onload = function() {
|
||||
if (navigator.mozSetMessageHandler !== undefined) {
|
||||
navigator.mozSetMessageHandler('activity', function handler(activityRequest) {
|
||||
var activityName = activityRequest.source.name;
|
||||
if (activityName == 'share') {
|
||||
activity = activityRequest;
|
||||
blob = activity.source.data.blobs[0];
|
||||
fileUpload(blob);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
$('document').ready(function() {
|
||||
var firstview = ($("#first-view").prop('checked')) ? 1 : 0;
|
||||
var deleteday = ($("#delete-day").prop('checked')) ? 1 : 0;
|
||||
|
||||
@@ -11,7 +11,17 @@
|
||||
<title>Lutim</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<link rel="icon" type="image/png" href="<%= url_for('/') %>img/favicon.png">
|
||||
<link rel="icon" sizes="128x128" href="<%= url_for('/') %>img/lutim128.png">
|
||||
<link rel="icon" sizes="196x196" href="<%= url_for('/') %>img/lutim196.png">
|
||||
<link rel="apple-touch-icon" href="<%= url_for('/') %>img/lutim60.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="<%= url_for('/') %>img/lutim76.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="<%= url_for('/') %>img/lutim120.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="<%= url_for('/') %>img/lutim152.png">
|
||||
<link rel="apple-touch-icon-precomposed" sizes="128x128" href="<%= url_for('/') %>img/lutim128.png">
|
||||
% if (current_route 'stats') {
|
||||
%= asset 'stats.css'
|
||||
% } elsif (current_route 'about') {
|
||||
@@ -40,7 +50,8 @@
|
||||
<%= link_to 'https://github.com/ldidry/lutim' => (title => l 'fork-me') => begin %><i class="lead icon icon-github-circled"></i><% end %>
|
||||
<%= link_to $twitter_url => (title => l 'share-twitter') => begin %><i class="lead icon icon-touiteur"></i><% end %>
|
||||
<%= link_to 'https://flattr.com/submit/auto?user_id=_SKy_&url='.$url.'&title=Lutim&category=software' => (title => 'Flattr this') => begin %><i class="lead icon icon-flattr"></i><% end %>
|
||||
<%= link_to 'bitcoin:1K3n4MXNRSMHk28oTfXEvDunWFthePvd8v?label=lutim' => (title => 'Give Bitcoins') => begin %><i class="lead icon icon-bitcoin"></i><% end %>
|
||||
<%= link_to 'bitcoin:1K3n4MXNRSMHk28oTfXEvDunWFthePvd8v?label=lutim' => (title => 'Give Bitcoins') => begin %><i class="lead icon icon-bitcoin"></i><% end %>
|
||||
<a class="btn btn-default btn-xs" href="#" id="install-app"><img src="<%= url_for('/') %>img/rocket.png" alt="mozilla rocket logo"> <%=l 'install_as_webapp' %></a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,6 +65,9 @@
|
||||
<strong><%= stash('stop_upload') %></strong>
|
||||
</div>
|
||||
% }
|
||||
%= javascript begin
|
||||
var manifestUrl = '<%== url_for('manifest.webapp')->to_abs() %>';
|
||||
% end
|
||||
% if (current_route 'stats') {
|
||||
%= asset 'stats.js'
|
||||
% } elsif (!(current_route 'about')) {
|
||||
|
||||
33
templates/manifest.webapp.ep
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "Lutim",
|
||||
"description": "Lets Upload That Image!",
|
||||
"launch_path": "<%= url_for('/') %>",
|
||||
"icons": {
|
||||
"32": "<%= url_for('/img/lutim32.png') %>",
|
||||
"60": "<%= url_for('/img/lutim60.png') %>",
|
||||
"90": "<%= url_for('/img/lutim90.png') %>",
|
||||
"120": "<%= url_for('/img/lutim120.png') %>",
|
||||
"128": "<%= url_for('/img/lutim128.png') %>",
|
||||
"256": "<%= url_for('/img/lutim256.png') %>"
|
||||
},
|
||||
"developer": {
|
||||
"name": "Lutim team !",
|
||||
"url": "https://github.com/ldidry/lutim"
|
||||
},
|
||||
"default_locale": "en",
|
||||
"locales": {
|
||||
"fr": {
|
||||
"description": "Envoyons cette image !"
|
||||
}
|
||||
},
|
||||
"activities": {
|
||||
"share": {
|
||||
"filters": {
|
||||
"type": [ "image/*"]
|
||||
},
|
||||
"href": "<%= url_for('/') %>",
|
||||
"disposition": "window"
|
||||
}
|
||||
},
|
||||
"chrome": { "navigation": true }
|
||||
}
|
||||
@@ -122,6 +122,7 @@ sub upload {
|
||||
$self->{_links}->{'view_image'} = $link;
|
||||
$self->{_links}->{'download_link'} = $link.'?dl';
|
||||
$self->{_links}->{'twitter_link'} = $link.'?t';
|
||||
$self->{_links}->{'delete_link'} = $url.'d/'.$hash->{msg}->{real_short}.'/'.$hash->{msg}->{token};
|
||||
|
||||
#set success code (200)
|
||||
$self->{_links}{'status'} = 200;
|
||||
|
||||