8 Commits

Author SHA1 Message Date
Luc Didry
1633a0b0ed WIP - Swift storage 2020-08-23 10:40:42 +02:00
Luc Didry
95745c83d1 🔥 — Remove tap.xml from git 2020-08-23 10:40:13 +02:00
Luc Didry
32dff45a52 Merge branch 'improve-tests' into 'development'
Improve tests

See merge request fiat-tux/hat-softwares/lutim!76
2020-08-23 10:32:03 +02:00
Luc Didry
1a83ebc0d0 👷 — Improve CI
- Refactor .gitlab-ci.yml
- Update Makefile
- Introduce junit test output
- Improve minion test
2020-08-23 10:26:49 +02:00
Luc Didry
721ad30058 Merge branch 'weblate-lutim-default-theme' into 'development'
Translations update from Weblate

See merge request fiat-tux/hat-softwares/lutim!75
2020-06-17 08:37:18 +02:00
Konstantin Timashov
8ec459bdde Translated using Weblate (Russian)
Currently translated at 94.2% (131 of 139 strings)

Translation: Lutim/Default theme
Translate-URL: https://weblate.framasoft.org/projects/lutim/default-theme/ru/
2020-06-16 22:24:42 +02:00
Luc Didry
688293481a Merge branch 'weblate-lutim-default-theme' into 'development'
Translations update from Weblate

See merge request fiat-tux/hat-softwares/lutim!74
2020-06-10 06:52:40 +02:00
roberto marcolin
ad2f4bb724 Translated using Weblate (Italian)
Currently translated at 100.0% (139 of 139 strings)

Translation: Lutim/Default theme
Translate-URL: https://weblate.framasoft.org/projects/lutim/default-theme/it/
2020-06-09 21:24:40 +02:00
98 changed files with 631 additions and 189 deletions

View File

@@ -2,9 +2,6 @@ Revision history for Lutim
0.13.0 ????-??-??
0.12.1 2020-10-08
- ⬆️ Update jQuery
0.12.0 2020-04-17
- Add watermarking feature (#112)

View File

@@ -32,7 +32,6 @@ feature 'postgresql', 'PostgreSQL support' => sub {
feature 'sqlite', 'SQLite support' => sub {
requires 'Mojo::SQLite', '>= 3.000';
requires 'Minion::Backend::SQLite', '>= 4.001';
requires 'DBD::SQLite', '>= 1.66';
};
feature 'minion', 'Minion support' => sub {
requires 'Minion';
@@ -54,6 +53,9 @@ feature 'htpasswd', 'Htpasswd authentication support' => sub {
requires 'Apache::Htpasswd';
requires 'Mojolicious::Plugin::Authentication';
};
feature 'swift-storage', 'Openstack Swift object storage support' => sub {
requires 'Net::OpenStack::Swift';
};
feature 'test' => sub {
requires 'Devel::Cover';
};

View File

@@ -9,6 +9,23 @@ DISTRIBUTIONS
Digest::SHA 2
ExtUtils::MakeMaker 0
MIME::Base64 0
App-Rad-1.05
pathname: G/GA/GARU/App-Rad-1.05.tar.gz
provides:
App::Rad 1.05
App::Rad::Config undef
App::Rad::Exclude 0.01
App::Rad::Help 0.03
App::Rad::Include 0.01
requirements:
Attribute::Handlers 0
B::Deparse 0
Carp 0
ExtUtils::MakeMaker 0
File::Temp 0
FindBin 0
Getopt::Long 2.36
Test::More 0
Archive-Zip-1.60
pathname: P/PH/PHRED/Archive-Zip-1.60.tar.gz
provides:
@@ -173,6 +190,12 @@ DISTRIBUTIONS
strict 0
vars 0
warnings 0
Class-Accessor-Lite-0.08
pathname: K/KA/KAZUHO/Class-Accessor-Lite-0.08.tar.gz
provides:
Class::Accessor::Lite 0.08
requirements:
ExtUtils::MakeMaker 6.36
Class-Data-Inheritable-0.08
pathname: T/TM/TMTM/Class-Data-Inheritable-0.08.tar.gz
provides:
@@ -294,13 +317,13 @@ DISTRIBUTIONS
Test::More 0.88
Time::HiRes 0
version 0
DBD-SQLite-1.66
pathname: I/IS/ISHIGAKI/DBD-SQLite-1.66.tar.gz
DBD-SQLite-1.58
pathname: I/IS/ISHIGAKI/DBD-SQLite-1.58.tar.gz
provides:
DBD::SQLite 1.66
DBD::SQLite 1.58
DBD::SQLite::Constants undef
DBD::SQLite::VirtualTable 1.66
DBD::SQLite::VirtualTable::Cursor 1.66
DBD::SQLite::VirtualTable 1.58
DBD::SQLite::VirtualTable::Cursor 1.58
DBD::SQLite::VirtualTable::FileContent undef
DBD::SQLite::VirtualTable::FileContent::Cursor undef
DBD::SQLite::VirtualTable::PerlData undef
@@ -537,6 +560,23 @@ DISTRIBUTIONS
Data::Validate::Domain 0
Data::Validate::IP 0
ExtUtils::MakeMaker 0
Data-Validator-1.07
pathname: G/GF/GFUJI/Data-Validator-1.07.tar.gz
provides:
Data::Validator 1.07
Data::Validator::Role::AllowExtra undef
Data::Validator::Role::Croak undef
Data::Validator::Role::Method undef
Data::Validator::Role::NoRestricted undef
Data::Validator::Role::NoThrow undef
Data::Validator::Role::Sequenced undef
Data::Validator::Role::SmartSequenced undef
Data::Validator::Role::StrictSequenced undef
requirements:
ExtUtils::MakeMaker 6.59
Module::Build 0.38
Mouse 0.93
perl 5.008001
DateTime-1.48
pathname: D/DR/DROLSKY/DateTime-1.48.tar.gz
provides:
@@ -995,6 +1035,19 @@ DISTRIBUTIONS
perl 5.008004
strict 0
warnings 0
Devel-CheckCompiler-0.07
pathname: S/SY/SYOHEX/Devel-CheckCompiler-0.07.tar.gz
provides:
Devel::AssertC99 undef
Devel::CheckCompiler 0.07
requirements:
Exporter 0
ExtUtils::CBuilder 0
File::Temp 0
Module::Build::Tiny 0.035
Test::More 0.98
parent 0
perl 5.008001
Devel-Cover-1.29
pathname: P/PJ/PJCJ/Devel-Cover-1.29.tar.gz
provides:
@@ -1077,6 +1130,13 @@ DISTRIBUTIONS
perl 5.006
strict 0
warnings 0
Devel-PPPort-3.57
pathname: A/AT/ATOOMIC/Devel-PPPort-3.57.tar.gz
provides:
Devel::PPPort 3.57
requirements:
ExtUtils::MakeMaker 0
FindBin 0
Devel-StackTrace-2.03
pathname: D/DR/DROLSKY/Devel-StackTrace-2.03.tar.gz
provides:
@@ -1329,6 +1389,27 @@ DISTRIBUTIONS
Test::More 0
Test::Warn 0
perl 5.006
Furl-3.13
pathname: T/TO/TOKUHIROM/Furl-3.13.tar.gz
provides:
Furl 3.13
Furl::ConnectionCache undef
Furl::HTTP 3.13
Furl::Headers undef
Furl::Request undef
Furl::Response undef
Furl::ZlibStream undef
requirements:
Class::Accessor::Lite 0
Encode 0
HTTP::Parser::XS 0.11
MIME::Base64 0
Module::Build::Tiny 0.035
Mozilla::CA 0
Scalar::Util 0
Socket 0
Time::HiRes 0
perl 5.008001
HTML-Parser-3.72
pathname: G/GA/GAAS/HTML-Parser-3.72.tar.gz
provides:
@@ -1447,6 +1528,14 @@ DISTRIBUTIONS
ExtUtils::MakeMaker 0
HTTP::Headers 6
perl 5.008001
HTTP-Parser-XS-0.17
pathname: K/KA/KAZUHO/HTTP-Parser-XS-0.17.tar.gz
provides:
HTTP::Parser::XS 0.17
HTTP::Parser::XS::PP undef
requirements:
ExtUtils::MakeMaker 6.36
Test::More 0.96
Hash-Merge-0.300
pathname: R/RE/REHSACK/Hash-Merge-0.300.tar.gz
provides:
@@ -1802,6 +1891,18 @@ DISTRIBUTIONS
constant 0
strict 0
warnings 0
Log-Minimal-0.19
pathname: K/KA/KAZEBURO/Log-Minimal-0.19.tar.gz
provides:
Log::Minimal 0.19
requirements:
CPAN::Meta 0
CPAN::Meta::Prereqs 0
Data::Dumper 0
ExtUtils::CBuilder 0
Module::Build 0.38
Scalar::Util 0
Term::ANSIColor 0
MRO-Compat-0.13
pathname: H/HA/HAARG/MRO-Compat-0.13.tar.gz
provides:
@@ -1918,6 +2019,21 @@ DISTRIBUTIONS
perl 5.006
strict 0
warnings 0
Module-Build-XSUtil-0.19
pathname: H/HI/HIDEAKIO/Module-Build-XSUtil-0.19.tar.gz
provides:
Module::Build::XSUtil 0.19
requirements:
Devel::CheckCompiler 0
Devel::PPPort 0
Exporter 0
ExtUtils::CBuilder 0
File::Basename 0
File::Path 0
Module::Build 0.4005
XSLoader 0
parent 0
perl 5.008001
Module-Implementation-0.09
pathname: D/DR/DROLSKY/Module-Implementation-0.09.tar.gz
provides:
@@ -2082,7 +2198,6 @@ DISTRIBUTIONS
Mojolicious::Lite undef
Mojolicious::Plugin undef
Mojolicious::Plugin::Config undef
Mojolicious::Plugin::Config::Sandbox undef
Mojolicious::Plugin::DefaultHelpers undef
Mojolicious::Plugin::EPLRenderer undef
Mojolicious::Plugin::EPRenderer undef
@@ -2605,6 +2720,44 @@ DISTRIBUTIONS
parent 0.223
strict 1.03
warnings 1.03
Mouse-v2.5.9
pathname: S/SK/SKAJI/Mouse-v2.5.9.tar.gz
provides:
Mouse v2.5.9
Mouse::Exporter undef
Mouse::Meta::Attribute undef
Mouse::Meta::Class undef
Mouse::Meta::Method undef
Mouse::Meta::Method::Accessor undef
Mouse::Meta::Method::Constructor undef
Mouse::Meta::Method::Delegation undef
Mouse::Meta::Method::Destructor undef
Mouse::Meta::Module undef
Mouse::Meta::Role undef
Mouse::Meta::Role::Application undef
Mouse::Meta::Role::Application::RoleSummation undef
Mouse::Meta::Role::Composite undef
Mouse::Meta::Role::Method undef
Mouse::Meta::TypeConstraint undef
Mouse::Object undef
Mouse::PurePerl undef
Mouse::Role v2.5.9
Mouse::Spec v2.5.9
Mouse::TypeRegistry undef
Mouse::Util v2.5.9
Mouse::Util::MetaRole undef
Mouse::Util::TypeConstraints undef
Squirrel undef
Squirrel::Role undef
Test::Mouse undef
ouse undef
requirements:
ExtUtils::CBuilder 0
Module::Build 0.4005
Module::Build::XSUtil 0.19
Scalar::Util 1.14
XSLoader 0.02
perl 5.008005
Mozilla-CA-20180117
pathname: A/AB/ABH/Mozilla-CA-20180117.tar.gz
provides:
@@ -2640,6 +2793,31 @@ DISTRIBUTIONS
strict 0
vars 0
warnings 0
Net-OpenStack-Swift-0.15
pathname: M/MA/MASAKYST/Net-OpenStack-Swift-0.15.tar.gz
provides:
Net::OpenStack::Swift 0.15
Net::OpenStack::Swift::InnerKeystone::Base undef
Net::OpenStack::Swift::InnerKeystone::V1_0 undef
Net::OpenStack::Swift::InnerKeystone::V2_0 undef
Net::OpenStack::Swift::InnerKeystone::V3_0 undef
Net::OpenStack::Swift::Util undef
requirements:
App::Rad 0
Data::Validator 0
Furl 0
IO::Socket::SSL 0
JSON 0
Log::Minimal 0
Module::Build::Tiny 0.035
Mouse 0
Parallel::Fork::BossWorkerAsync 0
Path::Tiny 0
Sys::CPU 0
Text::ASCIITable 0
URI::Escape 0
namespace::clean 0
perl 5.010_001
Net-SSLeay-1.85
pathname: M/MI/MIKEM/Net-SSLeay-1.85.tar.gz
provides:
@@ -2707,6 +2885,12 @@ DISTRIBUTIONS
XSLoader 0
strict 0
warnings 0
Parallel-Fork-BossWorkerAsync-0.09
pathname: J/JV/JVANNUCCI/Parallel-Fork-BossWorkerAsync-0.09.tar.gz
provides:
Parallel::Fork::BossWorkerAsync 0.09
requirements:
ExtUtils::MakeMaker 0
Params-Classify-0.015
pathname: Z/ZE/ZEFRAM/Params-Classify-0.015.tar.gz
provides:
@@ -2749,6 +2933,32 @@ DISTRIBUTIONS
overload 0
strict 0
warnings 0
Path-Tiny-0.112
pathname: D/DA/DAGOLDEN/Path-Tiny-0.112.tar.gz
provides:
Path::Tiny 0.112
Path::Tiny::Error 0.112
requirements:
Carp 0
Cwd 0
Digest 1.03
Digest::SHA 5.45
Encode 0
Exporter 5.57
ExtUtils::MakeMaker 6.17
Fcntl 0
File::Copy 0
File::Glob 0
File::Path 2.07
File::Spec 0.86
File::Temp 0.19
File::stat 0
constant 0
overload 0
perl 5.008001
strict 0
warnings 0
warnings::register 0
Role-Tiny-2.000006
pathname: H/HA/HAARG/Role-Tiny-2.000006.tar.gz
provides:
@@ -2774,17 +2984,6 @@ DISTRIBUTIONS
Sub::Quote 2.000001
Text::Balanced 2.00
perl 5.006
Scalar-List-Utils-1.50
pathname: P/PE/PEVANS/Scalar-List-Utils-1.50.tar.gz
provides:
List::Util 1.50
List::Util::XS 1.50
Scalar::Util 1.50
Sub::Util 1.50
requirements:
ExtUtils::MakeMaker 0
Test::More 0
perl 5.006
Specio-0.42
pathname: D/DR/DROLSKY/Specio-0.42.tar.gz
provides:
@@ -2948,6 +3147,12 @@ DISTRIBUTIONS
Text::Balanced 2
if 0
perl 5.005
Sys-CPU-0.52
pathname: M/MK/MKODERER/Sys-CPU-0.52.tar.gz
provides:
Sys::CPU 0.52
requirements:
ExtUtils::MakeMaker 0
Task-Weaken-1.06
pathname: E/ET/ETHER/Task-Weaken-1.06.tar.gz
provides:
@@ -2993,6 +3198,16 @@ DISTRIBUTIONS
Test::Builder 0.13
Test::Builder::Tester 1.02
perl 5.006
Text-ASCIITable-0.22
pathname: L/LU/LUNATIC/Text-ASCIITable-0.22.tar.gz
provides:
Text::ASCIITable 0.22
Text::ASCIITable::Wrap 0.2
requirements:
Carp 0
Encode 0
List::Util 0
perl v5.6.0
Text-Soundex-3.05
pathname: R/RJ/RJBS/Text-Soundex-3.05.tar.gz
provides:

View File

@@ -109,6 +109,11 @@ sub startup {
$self->plugin('Lutim::Plugin::Helpers');
$self->plugin('Lutim::Plugin::Lang');
# Now helpers has been loaded, time to check Swift container
if ($config->{swift}) {
$self->check_swift_container();
}
# Minion
if ($config->{minion}->{enabled}) {
$self->config->{minion}->{dbtype} = 'sqlite' unless defined $config->{minion}->{dbtype};

View File

@@ -33,7 +33,7 @@ sub run {
$dbi->get_images_to_clean()->each(
sub {
my ($img, $num) = @_;
$l->app->delete_image($img);
$img->delete();
}
);
@@ -42,7 +42,7 @@ sub run {
$dbi->get_no_longer_viewed_files($time)->each(
sub {
my ($img, $num) = @_;
$l->app->delete_image($img);
$img->delete();
}
);
}

View File

@@ -50,7 +50,7 @@ sub run {
$dbi->get_50_oldest()->each(
sub {
my ($img, $num) = @_;
$l->app->delete_image($img);
$img->delete();
}
);
} while (du(qw/files/) > $config->{max_total_size});

View File

@@ -173,7 +173,7 @@ sub delete_short {
chomp $confirm;
}
if ($confirm =~ m/^y(es)?$/i) {
$c->app->delete_image($i);
$i->delete();
} else {
say 'Answer was not "y" or "yes". Aborting deletion.';
}

View File

@@ -231,7 +231,7 @@ sub delete {
} else {
$c->app->log->info('[DELETION] someone made '.$image->filename.' removed with token method (path: '.$image->path.')') unless $c->config('quiet_logs');
$c->delete_image($image);
$image->delete();
return $c->respond_to(
json => {
json => {
@@ -397,7 +397,8 @@ sub add {
# Save file and create record
my $filename = unidecode($upload->filename);
my $ext = ($filename =~ m/([^.]+)$/)[0];
my $path = 'files/'.$record->short.'.'.$ext;
my $path = $record->short.'.'.$ext;
$path = Mojo::File->new('files', $path)->to_string unless ($c->app->config('swift'));
my ($width, $height);
if ($im_loaded && $mediatype ne 'image/svg+xml' && $mediatype !~ m#image/(x-)?xcf# && $mediatype ne 'image/webp') { # ImageMagick don't work in Debian with svg (for now?)
@@ -493,12 +494,11 @@ sub add {
if ($c->param('crypt') || $c->config('always_encrypt')) {
($upload, $key, $iv) = $c->crypt($upload, $filename);
}
$upload->move_to($path);
$record->path($path)
->filename($filename)
->mediatype($mediatype)
->footprint(digest_file_hex($path, 'SHA-512'))
->footprint(digest_file_hex($upload->asset->to_file->path, 'SHA-512'))
->enabled(1)
->delete_at_day(($c->param('delete-day') && ($c->param('delete-day') <= $c->max_delay || $c->max_delay == 0)) ? $c->param('delete-day') : $c->max_delay)
->delete_at_first_view(($c->param('first-view'))? 1 : 0)
@@ -507,7 +507,8 @@ sub add {
->width($width)
->height($height)
->iv($iv)
->write;
->write
->store($upload);
# Log image creation
$c->app->log->info('[CREATION] '.$ip.' pushed '.$filename.' (path: '.$path.')') unless $c->config('quiet_logs');
@@ -605,12 +606,13 @@ sub short {
my $image = Lutim::DB::Image->new(app => $c->app, short => $short);
if ($image->enabled && $image->path) {
# Image deleted
if($image->delete_at_day && $image->created_at + $image->delete_at_day * 86400 <= time()) {
# Log deletion
$c->app->log->info('[DELETION] someone tried to view '.$image->filename.' but it has been removed by expiration (path: '.$image->path.')') unless $c->config('quiet_logs');
# Delete image
$c->delete_image($image);
$image->delete();
# Warn user
$c->flash(
@@ -620,6 +622,7 @@ sub short {
}
my $test;
# Twitter page
if (defined($touit) && $image->mediatype !~ m/svg/) {
$test = 1;
my $short = $image->short;
@@ -629,11 +632,11 @@ sub short {
if (defined($image->width) && defined($image->height)) {
($width, $height) = ($image->width, $image->height);
} elsif ($im_loaded) {
my $upload = $c->decrypt($key, $image->path, $image->iv);
my $im = Image::Magick->new;
$im->BlobToImage($upload->slurp);
$width = $im->Get('width');
$height = $im->Get('height');
my $tmp = $image->decrypt($key);
my $im = Image::Magick->new;
$im->BlobToImage($tmp->slurp);
$width = $im->Get('width');
$height = $im->Get('height');
$image->width($width)
->height($height)
@@ -656,7 +659,7 @@ sub short {
$c->app->log->info('[DELETION] someone made '.$image->filename.' removed (path: '.$image->path.')') unless $c->config('quiet_logs');
# Delete image
$c->delete_image($image);
$image->delete();
$c->flash(
msg => $c->l('Unable to find the image: it has been deleted.')
@@ -688,7 +691,7 @@ sub short {
$c->app->log->info('[DELETION] someone made '.$image->filename.' removed (path: '.$image->path.')') unless $c->config('quiet_logs');
# Delete image
$c->delete_image($image);
$image->delete();
}
});
} else {
@@ -740,7 +743,7 @@ sub zip {
$c->app->log->info('[DELETION] someone tried to view '.$image->filename.' but it has been removed by expiration (path: '.$image->path.')') unless $c->config('quiet_logs');
# Delete image
$c->delete_image($image);
$image->delete();
# Warn user
$zip->addString(encode('UTF-8', $c->l('Unable to find the image: it has been deleted.')), 'images/'.$filename.'.txt');
@@ -753,7 +756,7 @@ sub zip {
$c->app->log->info('[DELETION] someone made '.$image->filename.' removed (path: '.$image->path.')') unless $c->config('quiet_logs');
# Delete image
$c->delete_image($image);
$image->delete();
$zip->addString(encode('UTF-8', $c->l('Unable to find the image: it has been deleted.')), 'images/'.$filename.'.txt');
next;
@@ -764,16 +767,18 @@ sub zip {
$expires = $dt->strftime("%a, %d %b %Y %H:%M:%S GMT");
my $path = $image->path;
unless ( -f $path && -r $path ) {
$c->app->log->error("Cannot read file [$path]. error [$!]");
$zip->addString(encode('UTF-8', $c->l('Unable to find the image: it has been deleted.')), 'images/'.$filename.'.txt');
next;
unless ($c->app->config('swift')) {
unless ( -f $path && -r $path ) {
$c->app->log->error("Cannot read file [$path]. error [$!]");
$zip->addString(encode('UTF-8', $c->l('Unable to find the image: it has been deleted.')), 'images/'.$filename.'.txt');
next;
}
}
if ($key) {
$zip->addString($c->decrypt($key, $path, $image->iv), "images/$filename");
$zip->addString($image->decrypt($key), "images/$filename");
} else {
$zip->addFile($path, "images/$filename");
$zip->addString($image->retrieve, "images/$filename");
}
# Log access

View File

@@ -1,6 +1,10 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lutim::DB::Image;
use bytes;
use Mojo::Base -base;
use Mojo::File;
use Crypt::CBC;
use File::Temp qw(tempfile);
has 'short';
has 'path';
@@ -20,6 +24,8 @@ has 'height';
has 'iv';
has 'app';
=encoding utf8
=head1 NAME
Lutim::DB::Image - DB abstraction layer for Lutim images
@@ -151,13 +157,11 @@ sub to_hash {
=over 1
=item B<Usage> : C<$c-E<gt>count_delete_at_day_endis($delete_at_day, $enabled[, $time])>
=item B<Usage> : C<$c-E<gt>count_delete_at_day_endis($delete_at_day, $enabled, [$time])>
=item B<Arguments> : two mandatory parameters: one integer, the delete_at_day attribute, a boolean (0 or 1), the enabled attribute
an optional parameter: an unix timestamp
=item B<Arguments> : two mandatory parameters: one integer, the delete_at_day attribute, a boolean (0 or 1), the enabled attribute and an optional parameter: an unix timestamp.
=item B<Purpose> : count how many images there are with the given delete_at_day attribute, and enabled or disabled, depending on the given enabled attribute
if the optional parameter is given, count only images according to the given mandatory parameters that were created before the timestamp
=item B<Purpose> : count how many images there are with the given delete_at_day attribute, and enabled or disabled, depending on the given enabled attribute. If the optional parameter is given, count only images according to the given mandatory parameters that were created before the timestamp
=item B<Returns> : integer
@@ -345,6 +349,158 @@ sub to_hash {
=back
=head2 store
=over 1
=item B<Usage> : C<$c-E<gt>store($upload)>
=item B<Arguments> : a Mojo::Upload object
=item B<Purpose> : will store the content to the objects path, either on filesystem or on Swift object storage
=item B<Returns> : the db accessor object
=back
=cut
sub store {
my $c = shift;
my $upload = shift;
if ($c->app->config('swift')) {
$c->app->swift->put_object(
container_name => $c->app->config('swift')->{container},
object_name => $c->path,
content_length => $upload->size,
content => $upload->slurp
);
} else {
$upload->move_to($c->path);
}
return $c;
}
=head2 retrieve
=over 1
=item B<Usage> : C<$c-E<gt>retrieve>
=item B<Arguments> : none
=item B<Purpose> : get file from storage, either filesystem or Swift object storage
=item B<Returns> : the data from the file
=back
=cut
sub retrieve {
my $c = shift;
my $upload = shift;
if ($c->app->config('swift')) {
my $file;
$c->app->swift->get_object(
container_name => $c->app->config('swift')->{container},
object_name => $c->path,
write_code => sub {
my ($status, $message, $headers, $chunk) = @_;
$file .= $chunk;
}
);
return $file;
} else {
return Mojo::File->new($c->path)->slurp;
}
}
=head2 decrypt
=over 1
=item B<Usage> : C<$c-E<gt>decrypt($key)>
=item B<Arguments> : the decryption key
=item B<Purpose> : decrypt the image
=item B<Returns> : a Mojo::Asset::File object
=back
=cut
sub decrypt {
my $c = shift;
my $key = shift;
$c->iv = 'dupajasi' unless $c->iv;
my $cipher = Crypt::CBC->new(
-key => $key,
-cipher => 'Blowfish',
-header => 'none',
-iv => $c->iv
);
$cipher->start('decrypting');
my $decrypt_asset = Mojo::Asset::File->new;
if ($c->app->config('swift')) {
$c->app->swift->get_object(
container_name => $c->app->config('swift')->{container},
object_name => $c->path,
write_code => sub {
my ($status, $message, $headers, $chunk) = @_;
$decrypt_asset->add_chunk($cipher->crypt($chunk));
}
);
} else {
open(my $f, "<", $c->path) or die "Unable to read encrypted file: $!";
binmode $f;
while (read($f, my $buffer, 1024)) {
$decrypt_asset->add_chunk($cipher->crypt($buffer));
}
$decrypt_asset->add_chunk($cipher->finish);
}
return $decrypt_asset->slurp;
}
=head2 delete
=over 1
=item B<Usage> : C<$c-E<gt>delete>
=item B<Arguments> : none
=item B<Purpose> : delete the file on filesystem or Swift object storage and disable the image in database
=item B<Returns> : the db accessor object
=back
=cut
sub delete {
my $c = shift;
if ($c->app->config('cache_max_size') != 0 || scalar(@{$c->app->config('memcached_servers')})) {
$c->app->chi('lutim_images_cache')->remove($c->short);
}
if ($c->app->config('swift')) {
$c->app->swift->delete_object({
container_name => $c->app->config('swift')->{container},
object_name => $c->path
});
} else {
unlink $c->path or warn "Could not unlink ".$c->path.": $!";
}
return $c->disable();
}
1;

View File

@@ -78,15 +78,12 @@ sub select_empty {
}
sub write {
my $c = shift;
my $provisioning = shift;
my $c = shift;
if ($c->record) {
$c->app->pg->db->query('UPDATE lutim SET counter = ?, created_at = ?, created_by = ?, delete_at_day = ?, delete_at_first_view = ?, enabled = ?, filename = ?, footprint = ?, height = ?, last_access_at = ?, mediatype = ?, mod_token = ?, path = ?, short = ?, width = ?, iv = ? WHERE short = ?', $c->counter, $c->created_at, $c->created_by, $c->delete_at_day, $c->delete_at_first_view, $c->enabled, $c->filename, $c->footprint, $c->height, $c->last_access_at, $c->mediatype, $c->mod_token, $c->path, $c->short, $c->width, $c->iv, $c->short);
} else {
my $query = 'INSERT INTO lutim (counter, created_at, created_by, delete_at_day, delete_at_first_view, enabled, filename, footprint, height, last_access_at, mediatype, mod_token, path, short, width, iv) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
$query .= ' ON CONFLICT DO NOTHING' if $provisioning;
$c->app->pg->db->query($query, $c->counter, $c->created_at, $c->created_by, $c->delete_at_day, $c->delete_at_first_view, $c->enabled, $c->filename, $c->footprint, $c->height, $c->last_access_at, $c->mediatype, $c->mod_token, $c->path, $c->short, $c->width, $c->iv);
$c->app->pg->db->query('INSERT INTO lutim (counter, created_at, created_by, delete_at_day, delete_at_first_view, enabled, filename, footprint, height, last_access_at, mediatype, mod_token, path, short, width, iv) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', $c->counter, $c->created_at, $c->created_by, $c->delete_at_day, $c->delete_at_first_view, $c->enabled, $c->filename, $c->footprint, $c->height, $c->last_access_at, $c->mediatype, $c->mod_token, $c->path, $c->short, $c->width, $c->iv);
$c->record(1);
}

View File

@@ -79,15 +79,12 @@ sub select_empty {
}
sub write {
my $c = shift;
my $provisioning = shift;
my $c = shift;
if ($c->record) {
$c->app->sqlite->db->query('UPDATE lutim SET counter = ?, created_at = ?, created_by = ?, delete_at_day = ?, delete_at_first_view = ?, enabled = ?, filename = ?, footprint = ?, height = ?, last_access_at = ?, mediatype = ?, mod_token = ?, path = ?, short = ?, width = ?, iv = ? WHERE short = ?', $c->counter, $c->created_at, $c->created_by, $c->delete_at_day, $c->delete_at_first_view, $c->enabled, $c->filename, $c->footprint, $c->height, $c->last_access_at, $c->mediatype, $c->mod_token, $c->path, $c->short, $c->width, $c->iv, $c->short);
} else {
my $query = 'INSERT INTO lutim (counter, created_at, created_by, delete_at_day, delete_at_first_view, enabled, filename, footprint, height, last_access_at, mediatype, mod_token, path, short, width, iv) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
$query .= ' ON CONFLICT DO NOTHING' if $provisioning;
$c->app->sqlite->db->query($query, $c->counter, $c->created_at, $c->created_by, $c->delete_at_day, $c->delete_at_first_view, $c->enabled, $c->filename, $c->footprint, $c->height, $c->last_access_at, $c->mediatype, $c->mod_token, $c->path, $c->short, $c->width, $c->iv);
$c->app->sqlite->db->query('INSERT INTO lutim (counter, created_at, created_by, delete_at_day, delete_at_first_view, enabled, filename, footprint, height, last_access_at, mediatype, mod_token, path, short, width, iv) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', $c->counter, $c->created_at, $c->created_by, $c->delete_at_day, $c->delete_at_first_view, $c->enabled, $c->filename, $c->footprint, $c->height, $c->last_access_at, $c->mediatype, $c->mod_token, $c->path, $c->short, $c->width, $c->iv);
$c->record(1);
}

View File

@@ -49,26 +49,61 @@ sub register {
$app->helper(is_selected => \&_is_selected);
$app->helper(is_wm_selected => \&_is_wm_selected);
$app->helper(crypt => \&_crypt);
$app->helper(decrypt => \&_decrypt);
$app->helper(delete_image => \&_delete_image);
$app->helper(iso639_native_name => \&_iso639_native_name);
$app->helper(prefix => \&_prefix);
if ($app->config('swift')) {
use Net::OpenStack::Swift;
$app->helper(swift => \&_swift);
$app->helper(check_swift_container => \&_check_swift_container);
$app->helper(find_swift_container => \&_find_swift_container);
}
}
sub _pg {
my $c = shift;
my $c = shift;
state $pg = Mojo::Pg->new($c->app->pg_url($c->app->config('pgdb')));
return $pg;
}
sub _sqlite {
my $c = shift;
my $c = shift;
state $sqlite = Mojo::SQLite->new('sqlite:'.$c->app->config('db_path'));
return $sqlite;
}
sub _swift {
my $c = shift;
state $swift = Net::OpenStack::Swift->new($c->app->config('swift'));
return $swift;
}
sub _check_swift_container {
my $c = shift;
my ($storage_url, $token) = $c->swift->get_auth();
my ($headers, $containers) = $c->swift->get_account(url => $storage_url, token => $token);
unless ($c->find_swift_container($containers)) {
$c->swift->put_container(container_name => $c->app->config('swift')->{container});
my ($headers, $containers) = $c->swift->get_account(url => $storage_url, token => $token);
die sprintf("Swift container %s not found, and unable to create it.", $c->app->config('swift')->{container}) unless $c->find_swift_container($containers);
}
}
sub _find_swift_container {
my $c = shift;
my $containers = shift;
my $found_container = 0;
foreach my $container (@{$containers}) {
$found_container = 1 if $container->{name} eq $c->app->config('swift')->{container};
}
return $found_container;
}
sub _render_file {
my $c = shift;
my ($im_loaded, $img, $dl, $key, $thumb) = @_;
@@ -83,12 +118,15 @@ sub _render_file {
$dl = 'attachment' if ($mediatype =~ m/svg/);
$filename = quote($filename);
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.')
);
return 500;
unless ($c->app->config('swift')) {
# Do we have the file on disk?
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.')
);
return 500;
}
}
$mediatype =~ s/x-//;
@@ -104,21 +142,22 @@ sub _render_file {
$c->res->content->headers($headers);
my $cache;
# Do we have the file in cache?
if ($c->config('cache_max_size') != 0 || scalar(@{$c->config('memcached_servers')})) {
$cache = $c->chi('lutim_images_cache')->compute($img->short, undef, sub {
if ($key) {
return {
asset => $c->decrypt($key, $path, $iv),
asset => $img->decrypt($key),
key => $key
};
} else {
return {
asset => Mojo::File->new($path)->slurp,
asset => $img->retrieve
};
}
});
if ($key && $key ne $cache->{key}) {
my $tmp = $c->decrypt($key, $path, $iv);
my $tmp = $img->decrypt($key);
$cache->{asset} = $tmp;
$c->chi('lutim_images_cache')->replace(
$img->short,
@@ -131,18 +170,18 @@ sub _render_file {
} else {
if ($key) {
$cache = {
asset => $c->decrypt($key, $path, $iv),
asset => $img->decrypt($key),
};
} else {
$cache = {
asset => Mojo::File->new($path)->slurp,
asset => $img->retrieve,
};
}
}
# Extend expiration time
my $asset = Mojo::Asset::Memory->new;
$asset->add_chunk($cache->{asset});
# Do we need to create a thumbnail?
if (defined $thumb && $im_loaded && $mediatype ne 'image/svg+xml' && $mediatype !~ m#image/(x-)?xcf# && $mediatype ne 'image/webp') { # ImageMagick don't work in Debian with svg (for now?)
my $im = Image::Magick->new;
$im->BlobToImage($asset->slurp);
@@ -195,7 +234,7 @@ sub _provisioning {
->delete_at_first_view(0)
->delete_at_day(0)
->mod_token($c->shortener($c->app->config('token_length')))
->write('provisioning');
->write;
$img = Lutim::DB::Image->new(app => $c->app);
}
@@ -287,44 +326,6 @@ sub _crypt {
return ($crypt_upload, $key, $iv);
}
sub _decrypt {
my $c = shift;
my $key = shift;
my $file = shift;
my $iv = shift;
$iv = 'dupajasi' unless $iv;
my $cipher = Crypt::CBC->new(
-key => $key,
-cipher => 'Blowfish',
-header => 'none',
-iv => $iv
);
$cipher->start('decrypting');
my $decrypt_asset = Mojo::Asset::File->new;
open(my $f, "<",$file) or die "Unable to read encrypted file: $!";
binmode $f;
while (read($f, my $buffer, 1024)) {
$decrypt_asset->add_chunk($cipher->crypt($buffer));
}
$decrypt_asset->add_chunk($cipher->finish) ;
return $decrypt_asset->slurp;
}
sub _delete_image {
my $c = shift;
my $img = shift;
if ($c->config('cache_max_size') != 0 || scalar(@{$c->config('memcached_servers')})) {
$c->chi('lutim_images_cache')->remove($img->short);
}
unlink $img->path or warn "Could not unlink ".$img->path.": $!";
$img->disable();
}
sub _iso639_native_name {
my $c = shift;
return ucfirst(decode 'UTF-8', get_iso639_1(shift)->{nativeName});

View File

@@ -205,6 +205,18 @@
# optional, default is 3600
#session_duration => 3600,
# you can store images on Swift object storage (https://en.wikipedia.org/wiki/OpenStack#Swift) instead of filesystem
# please read https://metacpan.org/pod/Net::OpenStack::Swift#SYNOPSIS to know how to configure this setting
# IMPORTANT: add a `container` key in it, to let Lutim know which container to use. This is not a regular Net::OpenStack::Swift setting, but Lutim need it.
# optional, no default
#swift => {
# auth_url => 'https://auth-endpoint-url/v2.0',
# user => 'userid',
# password => 'password',
# tenant_name => 'project_id',
# container => 'lutim'
#},
# disable counters of images
# set to 1 to disable counters
# optional, counters are enabled by default
@@ -251,7 +263,7 @@
# optional, default is 0
#quiet_logs => 0,
# Content-Security-Policy header that will be sent by Lutim
# Content-Security-Policy header that will be sent by Lstu
# Set to '' to disable CSP header
# https://content-security-policy.com/ provides a good documentation about CSP.
# https://report-uri.com/home/generate provides a tool to generate a CSP header.
@@ -261,7 +273,7 @@
# the default value is good for `default` theme
#csp => "base-uri 'self'; connect-src 'self'; default-src 'none'; font-src 'self'; form-action 'self'; img-src 'self' data:; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'",
# X-Frame-Options header that will be sent by Lutim
# X-Frame-Options header that will be sent by Lstu
# Valid values are: 'DENY', 'SAMEORIGIN', 'ALLOW-FROM https://example.com/'
# Set to '' to disable X-Frame-Options header
# See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
@@ -270,13 +282,13 @@
# optional, default is 'DENY'
#x_frame_options => 'DENY',
# X-Content-Type-Options that will be sent by Lutim
# X-Content-Type-Options that will be sent by Lstu
# See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
# Set to '' to disable X-Content-Type-Options header
# optional, default is 'nosniff'
#x_content_type_options => 'nosniff',
# X-XSS-Protection that will be sent by Lutim
# X-XSS-Protection that will be sent by Lstu
# See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
# Set to '' to disable X-XSS-Protection header
# optional, default is '1; mode=block'

View File

@@ -31,11 +31,11 @@ msgstr "%1 sent images on this instance from beginning."
msgid "-or-"
msgstr "-or-"
#: lib/Lutim.pm:342 lib/Lutim/Command/cron/stats.pm:158 lib/Lutim/Command/cron/stats.pm:172 lib/Lutim/Command/cron/stats.pm:189 themes/default/templates/index.html.ep:5 themes/default/templates/myfiles.html.ep:5 themes/default/templates/partial/raw.js.ep:25 themes/default/templates/partial/raw.js.ep:8 themes/default/templates/raw.html.ep:10
#: lib/Lutim.pm:347 lib/Lutim/Command/cron/stats.pm:158 lib/Lutim/Command/cron/stats.pm:172 lib/Lutim/Command/cron/stats.pm:189 themes/default/templates/index.html.ep:5 themes/default/templates/myfiles.html.ep:5 themes/default/templates/partial/raw.js.ep:25 themes/default/templates/partial/raw.js.ep:8 themes/default/templates/raw.html.ep:10
msgid "1 year"
msgstr "1 year"
#: lib/Lutim.pm:341 lib/Lutim/Command/cron/stats.pm:155 lib/Lutim/Command/cron/stats.pm:169 lib/Lutim/Command/cron/stats.pm:186 themes/default/templates/index.html.ep:4 themes/default/templates/myfiles.html.ep:33 themes/default/templates/myfiles.html.ep:4 themes/default/templates/partial/for_my_delay.html.ep:13 themes/default/templates/partial/lutim.js.ep:149 themes/default/templates/partial/raw.js.ep:22 themes/default/templates/partial/raw.js.ep:5 themes/default/templates/raw.html.ep:7
#: lib/Lutim.pm:346 lib/Lutim/Command/cron/stats.pm:155 lib/Lutim/Command/cron/stats.pm:169 lib/Lutim/Command/cron/stats.pm:186 themes/default/templates/index.html.ep:4 themes/default/templates/myfiles.html.ep:33 themes/default/templates/myfiles.html.ep:4 themes/default/templates/partial/for_my_delay.html.ep:13 themes/default/templates/partial/lutim.js.ep:149 themes/default/templates/partial/raw.js.ep:22 themes/default/templates/partial/raw.js.ep:5 themes/default/templates/raw.html.ep:7
msgid "24 hours"
msgstr "24 hours"
@@ -211,7 +211,7 @@ msgstr "Image delay"
msgid "Image deleted"
msgstr "Image deleted"
#: lib/Lutim/Controller/Image.pm:799
#: lib/Lutim/Controller/Image.pm:804
msgid "Image not found."
msgstr "Image not found."
@@ -369,7 +369,7 @@ msgid "Something bad happened"
msgstr "Something bad happened"
#. ($c->config('contact')
#: lib/Lutim/Controller/Image.pm:806
#: lib/Lutim/Controller/Image.pm:811
msgid "Something went wrong when creating the zip file. Try again later or contact the administrator (%1)."
msgstr "Something went wrong when creating the zip file. Try again later or contact the administrator (%1)."
@@ -398,7 +398,7 @@ msgid "The delete token is invalid."
msgstr "The delete token is invalid."
#. ($upload->filename)
#: lib/Lutim/Controller/Image.pm:531
#: lib/Lutim/Controller/Image.pm:532
msgid "The file %1 is not an image."
msgstr "The file %1 is not an image."
@@ -440,7 +440,7 @@ msgid "There is XXXX image(s) in the gallery"
msgstr "There is XXXX image(s) in the gallery"
#. ($c->config->{contact})
#: lib/Lutim/Controller/Image.pm:528
#: lib/Lutim/Controller/Image.pm:529
msgid "There is no more available URL. Retry or contact the administrator. %1"
msgstr "There is no more available URL. Retry or contact the administrator. %1"
@@ -473,7 +473,7 @@ msgstr "Unable to copy to clipboard"
msgid "Unable to find the image %1."
msgstr "Unable to find the image %1."
#: lib/Lutim/Controller/Image.pm:617 lib/Lutim/Controller/Image.pm:662 lib/Lutim/Controller/Image.pm:703 lib/Lutim/Controller/Image.pm:746 lib/Lutim/Controller/Image.pm:758 lib/Lutim/Controller/Image.pm:769 lib/Lutim/Controller/Image.pm:796 lib/Lutim/Plugin/Helpers.pm:89
#: lib/Lutim/Controller/Image.pm:619 lib/Lutim/Controller/Image.pm:665 lib/Lutim/Controller/Image.pm:706 lib/Lutim/Controller/Image.pm:749 lib/Lutim/Controller/Image.pm:761 lib/Lutim/Controller/Image.pm:773 lib/Lutim/Controller/Image.pm:801 lib/Lutim/Plugin/Helpers.pm:126
msgid "Unable to find the image: it has been deleted."
msgstr "Unable to find the image: it has been deleted."
@@ -498,7 +498,7 @@ msgid "Uploaded files by days"
msgstr "Uploaded files by days"
#. ($c->app->config('contact')
#: lib/Lutim/Plugin/Helpers.pm:222
#: lib/Lutim/Plugin/Helpers.pm:261
msgid "Uploading is currently disabled, please try later or contact the administrator (%1)."
msgstr "Uploading is currently disabled, please try later or contact the administrator (%1)."
@@ -558,7 +558,7 @@ msgstr "arabic translation"
msgid "core developer"
msgstr "core developer"
#: lib/Lutim.pm:340 lib/Lutim/Command/cron/stats.pm:154 lib/Lutim/Command/cron/stats.pm:168 lib/Lutim/Command/cron/stats.pm:185 themes/default/templates/index.html.ep:3 themes/default/templates/myfiles.html.ep:3 themes/default/templates/partial/raw.js.ep:21 themes/default/templates/partial/raw.js.ep:4 themes/default/templates/raw.html.ep:6
#: lib/Lutim.pm:345 lib/Lutim/Command/cron/stats.pm:154 lib/Lutim/Command/cron/stats.pm:168 lib/Lutim/Command/cron/stats.pm:185 themes/default/templates/index.html.ep:3 themes/default/templates/myfiles.html.ep:3 themes/default/templates/partial/raw.js.ep:21 themes/default/templates/partial/raw.js.ep:4 themes/default/templates/raw.html.ep:6
msgid "no time limit"
msgstr "no time limit"

View File

@@ -32,11 +32,11 @@ msgstr ""
msgid "-or-"
msgstr ""
#: lib/Lutim.pm:342 lib/Lutim/Command/cron/stats.pm:158 lib/Lutim/Command/cron/stats.pm:172 lib/Lutim/Command/cron/stats.pm:189 themes/default/templates/index.html.ep:5 themes/default/templates/myfiles.html.ep:5 themes/default/templates/partial/raw.js.ep:25 themes/default/templates/partial/raw.js.ep:8 themes/default/templates/raw.html.ep:10
#: lib/Lutim.pm:347 lib/Lutim/Command/cron/stats.pm:158 lib/Lutim/Command/cron/stats.pm:172 lib/Lutim/Command/cron/stats.pm:189 themes/default/templates/index.html.ep:5 themes/default/templates/myfiles.html.ep:5 themes/default/templates/partial/raw.js.ep:25 themes/default/templates/partial/raw.js.ep:8 themes/default/templates/raw.html.ep:10
msgid "1 year"
msgstr ""
#: lib/Lutim.pm:341 lib/Lutim/Command/cron/stats.pm:155 lib/Lutim/Command/cron/stats.pm:169 lib/Lutim/Command/cron/stats.pm:186 themes/default/templates/index.html.ep:4 themes/default/templates/myfiles.html.ep:33 themes/default/templates/myfiles.html.ep:4 themes/default/templates/partial/for_my_delay.html.ep:13 themes/default/templates/partial/lutim.js.ep:149 themes/default/templates/partial/raw.js.ep:22 themes/default/templates/partial/raw.js.ep:5 themes/default/templates/raw.html.ep:7
#: lib/Lutim.pm:346 lib/Lutim/Command/cron/stats.pm:155 lib/Lutim/Command/cron/stats.pm:169 lib/Lutim/Command/cron/stats.pm:186 themes/default/templates/index.html.ep:4 themes/default/templates/myfiles.html.ep:33 themes/default/templates/myfiles.html.ep:4 themes/default/templates/partial/for_my_delay.html.ep:13 themes/default/templates/partial/lutim.js.ep:149 themes/default/templates/partial/raw.js.ep:22 themes/default/templates/partial/raw.js.ep:5 themes/default/templates/raw.html.ep:7
msgid "24 hours"
msgstr ""
@@ -212,7 +212,7 @@ msgstr ""
msgid "Image deleted"
msgstr ""
#: lib/Lutim/Controller/Image.pm:799
#: lib/Lutim/Controller/Image.pm:804
msgid "Image not found."
msgstr ""
@@ -370,7 +370,7 @@ msgid "Something bad happened"
msgstr ""
#. ($c->config('contact')
#: lib/Lutim/Controller/Image.pm:806
#: lib/Lutim/Controller/Image.pm:811
msgid "Something went wrong when creating the zip file. Try again later or contact the administrator (%1)."
msgstr ""
@@ -399,7 +399,7 @@ msgid "The delete token is invalid."
msgstr ""
#. ($upload->filename)
#: lib/Lutim/Controller/Image.pm:531
#: lib/Lutim/Controller/Image.pm:532
msgid "The file %1 is not an image."
msgstr ""
@@ -441,7 +441,7 @@ msgid "There is XXXX image(s) in the gallery"
msgstr ""
#. ($c->config->{contact})
#: lib/Lutim/Controller/Image.pm:528
#: lib/Lutim/Controller/Image.pm:529
msgid "There is no more available URL. Retry or contact the administrator. %1"
msgstr ""
@@ -474,7 +474,7 @@ msgstr ""
msgid "Unable to find the image %1."
msgstr ""
#: lib/Lutim/Controller/Image.pm:617 lib/Lutim/Controller/Image.pm:662 lib/Lutim/Controller/Image.pm:703 lib/Lutim/Controller/Image.pm:746 lib/Lutim/Controller/Image.pm:758 lib/Lutim/Controller/Image.pm:769 lib/Lutim/Controller/Image.pm:796 lib/Lutim/Plugin/Helpers.pm:89
#: lib/Lutim/Controller/Image.pm:619 lib/Lutim/Controller/Image.pm:665 lib/Lutim/Controller/Image.pm:706 lib/Lutim/Controller/Image.pm:749 lib/Lutim/Controller/Image.pm:761 lib/Lutim/Controller/Image.pm:773 lib/Lutim/Controller/Image.pm:801 lib/Lutim/Plugin/Helpers.pm:126
msgid "Unable to find the image: it has been deleted."
msgstr ""
@@ -499,7 +499,7 @@ msgid "Uploaded files by days"
msgstr ""
#. ($c->app->config('contact')
#: lib/Lutim/Plugin/Helpers.pm:222
#: lib/Lutim/Plugin/Helpers.pm:261
msgid "Uploading is currently disabled, please try later or contact the administrator (%1)."
msgstr ""
@@ -559,7 +559,7 @@ msgstr ""
msgid "core developer"
msgstr ""
#: lib/Lutim.pm:340 lib/Lutim/Command/cron/stats.pm:154 lib/Lutim/Command/cron/stats.pm:168 lib/Lutim/Command/cron/stats.pm:185 themes/default/templates/index.html.ep:3 themes/default/templates/myfiles.html.ep:3 themes/default/templates/partial/raw.js.ep:21 themes/default/templates/partial/raw.js.ep:4 themes/default/templates/raw.html.ep:6
#: lib/Lutim.pm:345 lib/Lutim/Command/cron/stats.pm:154 lib/Lutim/Command/cron/stats.pm:168 lib/Lutim/Command/cron/stats.pm:185 themes/default/templates/index.html.ep:3 themes/default/templates/myfiles.html.ep:3 themes/default/templates/partial/raw.js.ep:21 themes/default/templates/partial/raw.js.ep:4 themes/default/templates/raw.html.ep:6
msgid "no time limit"
msgstr ""

View File

@@ -4,17 +4,17 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
"PO-Revision-Date: 2020-10-11 23:59+0000\n"
"Last-Translator: Валентин Бородко <valya.spaces@gmail.com>\n"
"PO-Revision-Date: 2020-06-16 20:24+0000\n"
"Last-Translator: Konstantin Timashov <ktimashov@hse.ru>\n"
"Language-Team: Russian <https://weblate.framasoft.org/projects/lutim/"
"default-theme/ru/>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 4.1\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<="
"4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 3.11.2\n"
#. (7)
#. (30)
@@ -43,11 +43,11 @@ msgstr "24 часа"
#: themes/default/templates/partial/myfiles.js.ep:180
msgid ": Error while trying to get the counter."
msgstr ": Ошибка при подсчете количества ."
msgstr ": Error while trying to get the counter."
#: themes/default/templates/partial/navbar.html.ep:77
msgid "About"
msgstr "Подробнее"
msgstr "О Lutim"
#: lib/Lutim/Command/cron/stats.pm:154 themes/default/templates/raw.html.ep:3
msgid "Active images"
@@ -55,11 +55,11 @@ msgstr "Активные изображения"
#: lib/Lutim/Controller/Image.pm:328
msgid "An error occured while downloading the image."
msgstr "Ошибка при загрузке изображения."
msgstr "Произошла ошибка при скачивании изображения."
#: themes/default/templates/zip.html.ep:2
msgid "Archives download"
msgstr "Загрузить архив"
msgstr "Archives download"
#: themes/default/templates/about.html.ep:44 themes/default/templates/myfiles.html.ep:135 themes/default/templates/stats.html.ep:25
msgid "Back to homepage"
@@ -163,11 +163,11 @@ msgstr "Общее количество файлов"
#: themes/default/templates/myfiles.html.ep:126
msgid "Expires at"
msgstr "Исчезнет через"
msgstr "Истекает в"
#: themes/default/templates/myfiles.html.ep:112
msgid "Export localStorage data"
msgstr "Сохранить данные в хранилище"
msgstr ""
#: themes/default/templates/myfiles.html.ep:121
msgid "File name"
@@ -182,9 +182,8 @@ msgstr ""
"lutim\">главную страницу проекта</a>."
#: themes/default/templates/partial/navbar.html.ep:80
#, fuzzy
msgid "Fork me!"
msgstr "Выложить меня!"
msgstr "Форкни меня!"
#: themes/default/templates/index.html.ep:10 themes/default/templates/index.html.ep:13 themes/default/templates/myfiles.html.ep:60 themes/default/templates/myfiles.html.ep:63
msgid "Gallery link"
@@ -236,7 +235,7 @@ msgstr "Изображение не найдено."
#: themes/default/templates/myfiles.html.ep:113
msgid "Import localStorage data"
msgstr "Загрузить данные с хранилища"
msgstr ""
#: themes/default/templates/partial/navbar.html.ep:69
msgid "Informations"
@@ -322,7 +321,7 @@ msgstr "Синтаксис Маркдауна"
#: themes/default/templates/partial/myfiles.js.ep:149
msgid "Modify expiration delay"
msgstr "Изменить время на удление"
msgstr ""
#: themes/default/templates/myfiles.html.ep:7 themes/default/templates/partial/navbar.html.ep:18
msgid "My images"
@@ -374,7 +373,7 @@ msgstr "Пожалуйста, свяжитесь с администраторо
#: lib/Lutim/Controller/Authent.pm:36
msgid "Please, check your credentials: unable to authenticate."
msgstr "Пожалуйста проверьте свои данные: не удалось идентифицировать."
msgstr ""
#: themes/default/templates/gallery.html.ep:43
msgid "Previous (arrow left)"
@@ -382,7 +381,7 @@ msgstr "Предыдущий (стрелка влево)"
#: themes/default/templates/index.html.ep:46 themes/default/templates/index.html.ep:49 themes/default/templates/myfiles.html.ep:96 themes/default/templates/myfiles.html.ep:99
msgid "Random image link"
msgstr "Случайная ссылка на изображение"
msgstr ""
#: themes/default/templates/stats.html.ep:22
msgid "Raw stats"
@@ -398,7 +397,7 @@ msgstr "Послать изображение"
#: themes/default/templates/login.html.ep:16 themes/default/templates/logout.html.ep:5 themes/default/templates/partial/navbar.html.ep:37
msgid "Signin"
msgstr "Регистрация"
msgstr ""
#: themes/default/templates/index.html.ep:151 themes/default/templates/partial/gallery.js.ep:211 themes/default/templates/partial/lutim.js.ep:176
msgid "Something bad happened"
@@ -693,11 +692,3 @@ msgstr ""
#: themes/default/templates/index.html.ep:177 themes/default/templates/index.html.ep:221
msgid "No watermark"
msgstr "Без водного знака"
#: themes/default/templates/index.html.ep:171 themes/default/templates/index.html.ep:215
msgid "Tiling watermark"
msgstr "Размещение водяного знака"
#: themes/default/templates/index.html.ep:174 themes/default/templates/index.html.ep:218
msgid "Single watermark"
msgstr "Единственный водяной знак"

View File

@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
"PO-Revision-Date: 2020-09-20 09:51+0000\n"
"Last-Translator: Filip Bengtsson <filip@libreradio.org>\n"
"PO-Revision-Date: 2020-03-09 16:23+0000\n"
"Last-Translator: Luc Didry <luc@framasoft.org>\n"
"Language-Team: Swedish <https://weblate.framasoft.org/projects/lutim/"
"default-theme/sv/>\n"
"Language: sv\n"
@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.1\n"
"X-Generator: Weblate 3.11.2\n"
#. (7)
#. (30)
@@ -567,8 +567,6 @@ msgstr "Du försökte ladda ner en zip-fil som innehöll för många filer."
#: themes/default/templates/about.html.ep:8
msgid "You can, optionally, request that the image(s) posted on Lutim to be deleted at first view (or download) or after the delay selected from those proposed."
msgstr ""
"Om du vill, kan bilden raderas en viss tid efter att den har publicerats på "
"Lutim, eller omedelbart efter den första visningen eller nerladdningen."
#: lib/Lutim/Controller/Authent.pm:27
msgid "You have been successfully logged in."
@@ -608,7 +606,7 @@ msgstr "på"
#: themes/default/templates/about.html.ep:39
msgid "paste image to upload ability"
msgstr "infoga en bild för att skicka den"
msgstr ""
#: themes/default/templates/about.html.ep:41
msgid "russian translation"
@@ -627,15 +625,3 @@ msgid "For more details, see the <a href=\"https://framagit.org/fiat-tux/hat-sof
msgstr ""
"Se <a href=\"https://framagit.org/fiat-tux/hat-softwares/lutim\">projektets "
"hemsida</a> för mer information."
#: themes/default/templates/index.html.ep:177 themes/default/templates/index.html.ep:221
msgid "No watermark"
msgstr "Ingen vattenstämpling"
#: themes/default/templates/index.html.ep:171 themes/default/templates/index.html.ep:215
msgid "Tiling watermark"
msgstr "Flera vatenstämplingar"
#: themes/default/templates/index.html.ep:174 themes/default/templates/index.html.ep:218
msgid "Single watermark"
msgstr "En vattenstämpel"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 618 B

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 916 B

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 798 B

After

Width:  |  Height:  |  Size: 858 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 693 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 B

After

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 771 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 829 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 916 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 856 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 B

After

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 B

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 B

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 713 B

After

Width:  |  Height:  |  Size: 913 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 957 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 713 B

After

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 722 B

After

Width:  |  Height:  |  Size: 942 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 B

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 310 B

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 B

After

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 423 B

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 528 B

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

After

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 B

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 750 B

After

Width:  |  Height:  |  Size: 826 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 737 B

After

Width:  |  Height:  |  Size: 799 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 KiB

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 KiB

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1 +0,0 @@
jquery-3.5.1.min.js

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
jquery-3.5.1.min.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long