Add DB abstraction layer

This commit is contained in:
Luc Didry 2017-07-22 18:56:13 +02:00
parent 5684cbe17f
commit d909b8ad70
27 changed files with 1110 additions and 351 deletions

14
CHANGELOG Normal file
View File

@ -0,0 +1,14 @@
Revision history for Lufi
0.02 2017-?
- Database abstraction layer
- IE 11 and Edge support
- Fix encoding error (#83)
- Htpassword authentication support
- Ability to add a password to a file
0.01 2017-01-09
- Upload files
- Download files
- Preview files in browser depending on mimetype (images and videos)
- LDAP authentication support

View File

@ -20,6 +20,9 @@ locales:
$(XGETTEXT) $(EXTRACTDIR) -o $(PT) 2>/dev/null
$(XGETTEXT) $(EXTRACTDIR) -o $(NL) 2>/dev/null
podcheck:
podchecker lib/Lufi/DB/File.pm lib/Lufi/DB/Slice.pm
test:
$(CARTON) $(REAL_LUFI) test

View File

@ -1,9 +1,11 @@
requires 'Mojolicious', '>= 7.31';
requires 'ORLite';
requires 'Mojolicious::Plugin::DebugDumperHelper';
requires 'Mojolicious::Plugin::PgURLHelper';
requires 'Mojolicious::Plugin::I18N';
requires 'Mojolicious::Plugin::Mail';
requires 'Mojolicious::Plugin::Authentication';
requires 'Mojo::Pg';
requires 'EV';
requires 'Filesys::DiskUsage';
requires 'Switch';

View File

@ -51,6 +51,26 @@ DISTRIBUTIONS
perl 5.006
strict 0
warnings 0
Class-Method-Modifiers-2.12
pathname: E/ET/ETHER/Class-Method-Modifiers-2.12.tar.gz
provides:
Class::Method::Modifiers 2.12
requirements:
B 0
Carp 0
Exporter 0
ExtUtils::MakeMaker 0
base 0
perl 5.006
strict 0
warnings 0
Clone-0.39
pathname: G/GA/GARU/Clone-0.39.tar.gz
provides:
Clone 0.39
requirements:
ExtUtils::MakeMaker 0
Test::More 0
Convert-ASN1-0.27
pathname: G/GB/GBARR/Convert-ASN1-0.27.tar.gz
provides:
@ -85,6 +105,17 @@ DISTRIBUTIONS
ExtUtils::MakeMaker 6.30
Test::Fatal 0
Test::More 0
DBD-Pg-3.6.2
pathname: T/TU/TURNSTEP/DBD-Pg-3.6.2.tar.gz
provides:
Bundle::DBD::Pg v3.6.2
DBD::Pg v3.6.2
requirements:
DBI 1.614
ExtUtils::MakeMaker 6.11
Test::More 0.88
Time::HiRes 0
version 0
DBD-SQLite-1.54
pathname: I/IS/ISHIGAKI/DBD-SQLite-1.54.tar.gz
provides:
@ -241,6 +272,14 @@ DISTRIBUTIONS
perl 5.006
strict 0
warnings 0
Devel-GlobalDestruction-0.14
pathname: H/HA/HAARG/Devel-GlobalDestruction-0.14.tar.gz
provides:
Devel::GlobalDestruction 0.14
requirements:
ExtUtils::MakeMaker 0
Sub::Exporter::Progressive 0.001011
perl 5.006
Digest-HMAC-1.03
pathname: G/GA/GAAS/Digest-HMAC-1.03.tar.gz
provides:
@ -454,6 +493,14 @@ DISTRIBUTIONS
ExtUtils::MakeMaker 0
HTTP::Headers 6
perl 5.008001
Hash-Merge-0.200
pathname: R/RE/REHSACK/Hash-Merge-0.200.tar.gz
provides:
Hash::Merge 0.200
requirements:
Clone 0
ExtUtils::MakeMaker 0
perl 5.008001
IO-HTML-1.001
pathname: C/CJ/CJM/IO-HTML-1.001.tar.gz
provides:
@ -571,6 +618,13 @@ DISTRIBUTIONS
File::Spec 0
List::Util 0
Test::More 0.47
MRO-Compat-0.13
pathname: H/HA/HAARG/MRO-Compat-0.13.tar.gz
provides:
MRO::Compat 0.13
requirements:
ExtUtils::MakeMaker 0
perl 5.006
MailTools-2.18
pathname: M/MA/MARKOV/MailTools-2.18.tar.gz
provides:
@ -654,6 +708,31 @@ DISTRIBUTIONS
Text::ParseWords 0
perl 5.006001
version 0.87
Module-Runtime-0.015
pathname: Z/ZE/ZEFRAM/Module-Runtime-0.015.tar.gz
provides:
Module::Runtime 0.015
requirements:
Module::Build 0
Test::More 0.41
perl 5.006
strict 0
warnings 0
Mojo-Pg-4.0
pathname: S/SR/SRI/Mojo-Pg-4.0.tar.gz
provides:
Mojo::Pg 4.0
Mojo::Pg::Database undef
Mojo::Pg::Migrations undef
Mojo::Pg::PubSub undef
Mojo::Pg::Results undef
Mojo::Pg::Transaction undef
requirements:
DBD::Pg 3.005001
ExtUtils::MakeMaker 0
Mojolicious 7.32
SQL::Abstract 1.81
perl 5.010001
Mojolicious-7.36
pathname: S/SR/SRI/Mojolicious-7.36.tar.gz
provides:
@ -813,6 +892,43 @@ DISTRIBUTIONS
Mojolicious 5
Test::More 0
perl 5.001001
Mojolicious-Plugin-PgURLHelper-0.03
pathname: L/LD/LDIDRY/Mojolicious-Plugin-PgURLHelper-0.03.tar.gz
provides:
Mojolicious::Plugin::PgURLHelper 0.03
requirements:
ExtUtils::MakeMaker 0
Mojolicious 7.23
Moo-2.003002
pathname: H/HA/HAARG/Moo-2.003002.tar.gz
provides:
Method::Generate::Accessor undef
Method::Generate::BuildAll undef
Method::Generate::Constructor undef
Method::Generate::DemolishAll undef
Moo 2.003002
Moo::HandleMoose undef
Moo::HandleMoose::FakeConstructor undef
Moo::HandleMoose::FakeMetaClass undef
Moo::HandleMoose::_TypeMap undef
Moo::Object undef
Moo::Role 2.003002
Moo::_Utils undef
Moo::_mro undef
Moo::_strictures undef
Moo::sification undef
oo undef
requirements:
Class::Method::Modifiers 1.1
Devel::GlobalDestruction 0.11
Exporter 5.57
ExtUtils::MakeMaker 0
Module::Runtime 0.014
Role::Tiny 2.000004
Scalar::Util 0
Sub::Defer 2.003001
Sub::Quote 2.003001
perl 5.006
Mozilla-CA-20160104
pathname: A/AB/ABH/Mozilla-CA-20160104.tar.gz
provides:
@ -909,6 +1025,45 @@ DISTRIBUTIONS
ExtUtils::MakeMaker 6.30
File::Spec 0
strict 0
Role-Tiny-2.000005
pathname: H/HA/HAARG/Role-Tiny-2.000005.tar.gz
provides:
Role::Tiny 2.000005
Role::Tiny::With 2.000005
requirements:
Exporter 5.57
perl 5.006
SQL-Abstract-1.84
pathname: I/IL/ILMARI/SQL-Abstract-1.84.tar.gz
provides:
SQL::Abstract 1.84
SQL::Abstract::Test undef
SQL::Abstract::Tree undef
requirements:
Exporter 5.57
ExtUtils::MakeMaker 0
Hash::Merge 0.12
List::Util 0
MRO::Compat 0.12
Moo 2.000001
Scalar::Util 0
Sub::Quote 2.000001
Text::Balanced 2.00
Sub-Exporter-Progressive-0.001013
pathname: F/FR/FREW/Sub-Exporter-Progressive-0.001013.tar.gz
provides:
Sub::Exporter::Progressive 0.001013
requirements:
ExtUtils::MakeMaker 0
Sub-Quote-2.004000
pathname: H/HA/HAARG/Sub-Quote-2.004000.tar.gz
provides:
Sub::Defer 2.004000
Sub::Quote 2.004000
requirements:
ExtUtils::MakeMaker 0
Scalar::Util 0
perl 5.006
Sub-Uplevel-0.2800
pathname: D/DA/DAGOLDEN/Sub-Uplevel-0.2800.tar.gz
provides:

2
lib/Lufi.pm Executable file → Normal file
View File

@ -1,7 +1,6 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lufi;
use Mojo::Base 'Mojolicious';
use LufiDB;
use Net::LDAP;
use Apache::Htpasswd;
@ -29,6 +28,7 @@ sub startup {
upload_dir => 'files',
session_duration => 3600,
allow_pwd_on_files => 0,
dbtype => 'sqlite',
}
});

View File

@ -1,9 +1,8 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lufi::Command::cron::cleanbdd;
use Mojo::Base 'Mojolicious::Command';
use LufiDB;
use Lufi::DB::File;
use FindBin qw($Bin);
use File::Spec qw(catfile);
has description => 'Delete IP addresses from database after configured delay.';
has usage => sub { shift->extract_usage };
@ -11,20 +10,24 @@ has usage => sub { shift->extract_usage };
sub run {
my $c = shift;
my $cfile = Mojo::File->new($Bin, '..' , 'lufi.conf');
if (defined $ENV{MOJO_CONFIG}) {
$cfile = Mojo::File->new($ENV{MOJO_CONFIG});
unless (-e $cfile->to_abs) {
$cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG});
}
}
my $config = $c->app->plugin('Config', {
file => File::Spec->catfile($Bin, '..' ,'lufi.conf'),
file => $cfile,
default => {
dbtype => 'sqlite',
keep_ip_during => 365,
}
});
my $separation = time() - $config->{keep_ip_during} * 86400;
LufiDB->do(
'UPDATE files SET created_by = NULL WHERE created_by IS NOT NULL AND created_at < ?',
{},
$separation
);
Lufi::DB::File->new(app => $c->app)->delete_creator_before($separation);
}
=encoding utf8

View File

@ -1,10 +1,8 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lufi::Command::cron::cleanfiles;
use Mojo::Base 'Mojolicious::Command';
use LufiDB;
use Lufi::File;
use Lufi::DB::File;
use FindBin qw($Bin);
use File::Spec qw(catfile);
has description => 'Delete expired files.';
has usage => sub { shift->extract_usage };
@ -12,28 +10,39 @@ has usage => sub { shift->extract_usage };
sub run {
my $c = shift;
my $cfile = Mojo::File->new($Bin, '..' , 'lufi.conf');
if (defined $ENV{MOJO_CONFIG}) {
$cfile = Mojo::File->new($ENV{MOJO_CONFIG});
unless (-e $cfile->to_abs) {
$cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG});
}
}
my $config = $c->app->plugin('Config', {
file => $cfile,
default => {
dbtype => 'sqlite',
}
});
my $time = time();
## Select only files expired since two days, to be sure that nobody is still downloading it
my @files = LufiDB::Files->select('WHERE deleted = 0 AND ((delete_at_day + 2) * 86400) < (? - created_at) AND delete_at_day != 0', $time);
for my $file (@files) {
my $f = Lufi::File->new(record => $file);
$file->delete;
}
my $config = $c->app->plugin('Config', {
file => File::Spec->catfile($Bin, '..' ,'lufi.conf'),
});
my $ldfile = Lufi::DB::File->new(app => $c->app);
$ldfile->get_expired($time)->each(
sub {
my ($f, $num) = @_;
$f->delete;
}
);
if (defined($config->{delete_no_longer_viewed_files}) && $config->{delete_no_longer_viewed_files} > 0) {
$time = time() - $config->{delete_no_longer_viewed_files} * 86400;
@files = LufiDB::Files->select('WHERE deleted = 0 AND last_access_at < ?', $time);
for my $file (@files) {
my $f = Lufi::File->new(record => $file);
$file->delete;
}
my $ldfile = Lufi::DB::File->new(app => $c->app);
$ldfile->get_no_longer_viewed($time)->each(
sub {
my ($f, $num) = @_;
$f->delete;
}
);
}
}

View File

@ -1,11 +1,9 @@
package Lufi::Command::cron::watch;
use Mojo::Base 'Mojolicious::Command';
use Filesys::DiskUsage qw/du/;
use LufiDB;
use Lufi::File;
use Lufi::DB::File;
use Switch;
use FindBin qw($Bin);
use File::Spec qw(catfile);
has description => 'Watch the files directory and take action when over quota';
has usage => sub { shift->extract_usage };
@ -13,9 +11,17 @@ has usage => sub { shift->extract_usage };
sub run {
my $c = shift;
my $cfile = Mojo::File->new($Bin, '..' , 'lufi.conf');
if (defined $ENV{MOJO_CONFIG}) {
$cfile = Mojo::File->new($ENV{MOJO_CONFIG});
unless (-e $cfile->to_abs) {
$cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG});
}
}
my $config = $c->app->plugin('Config', {
file => File::Spec->catfile($Bin, '..' ,'lufi.conf'),
file => $cfile,
default => {
dbtype => 'sqlite',
policy_when_full => 'warn'
}
});
@ -36,11 +42,14 @@ sub run {
}
case 'delete' {
say '[Lufi cron job watch] Older files are being deleted';
my $ldfile = Lufi::DB::File->new(app => $c->app);
do {
for my $file (LufiDB::Files->select('WHERE deleted = 0 ORDER BY created_at ASC LIMIT 50')) {
my $f = Lufi::File->new(record => $file);
$file->delete;
}
$ldfile->get_oldest_undeleted_files(50)->each(
sub {
my ($f, $num) = @_;
$f->delete;
}
);
} while (du(qw/files/) > $config->{max_total_size});
}
else {

View File

@ -4,9 +4,8 @@ use Mojo::Base 'Mojolicious::Controller';
use Mojo::JSON qw(encode_json decode_json to_json true false);
use Mojo::Util qw(encode decode);
use Mojo::File;
use LufiDB;
use Lufi::File;
use Lufi::Slice;
use Lufi::DB::File;
use Lufi::DB::Slice;
use File::Spec::Functions;
use Number::Bytes::Human qw(format_bytes);
use Filesys::DfPortable;
@ -38,47 +37,46 @@ sub upload {
# Check if stop_upload file is present
if ($c->stop_upload) {
$stop = 1;
$c->send(encode_json(
$c->send(decode('UTF-8', encode_json(
{
success => false,
msg => $c->l('Sorry, uploading is disabled.'),
sent_delay => $json->{delay},
i => $json->{i}
}
));
)));
}
# Check against max_size
elsif (defined $c->config('max_file_size')) {
if ($json->{size} > $c->config('max_file_size')) {
$stop = 1;
$c->send(encode_json(
$c->send(decode('UTF-8', encode_json(
{
success => false,
msg => $c->l('Your file is too big: %1 (maximum size allowed: %2)', format_bytes($json->{size}), format_bytes($c->config('max_file_size'))),
sent_delay => $json->{delay},
i => $json->{i}
}
));
)));
}
}
# Check that we have enough space (multiplying by 2 since it's encrypted, it takes more place that the original file)
elsif ($json->{part} == 0 && ($json->{size} * 2) >= dfportable($c->config('upload_dir'))->{bavail}) {
$stop = 1;
$c->send(encode_json(
$c->send(decode('UTF-8', encode_json(
{
success => false,
msg => $c->l('No enough space available on the server for this file (size: %1).', format_bytes($json->{size})),
sent_delay => $json->{delay},
i => $json->{i}
}
));
)));
}
unless ($stop) {
my $f;
if (defined($json->{id})) {
my @records = LufiDB::Files->select('WHERE short = ?', $json->{id});
$f = Lufi::File->new(record => $records[0]) if scalar @records;
$f = Lufi::DB::File->new(app => $c->app)->from_short($json->{id});
} else {
my $delay;
unless (defined $json->{delay}) {
@ -113,19 +111,17 @@ sub upload {
if (defined($c->config('ldap')) || defined($c->config('htpasswd'))) {
$creator = 'User: '.$c->current_user.', IP: '.$creator;
}
$f = Lufi::File->new(
record => $c->get_empty,
created_by => $creator,
delete_at_first_view => ($json->{del_at_first_view}) ? 1 : 0,
delete_at_day => $delay,
mediatype => $json->{type},
filename => $json->{name},
filesize => $json->{size},
nbslices => $json->{total},
mod_token => $c->shortener($c->config('token_length')),
passwd => $salted_pwd
);
$f->write;
$f = Lufi::DB::File->new(app => $c->app)->get_empty()
->created_by($creator)
->delete_at_first_view(($json->{del_at_first_view}) ? 1 : 0)
->delete_at_day($delay)
->mediatype($json->{type})
->filename($json->{name})
->filesize($json->{size})
->nbslices($json->{total})
->mod_token($c->shortener($c->config('token_length')))
->passwd($salted_pwd)
->write;
}
# This check is just in case we didn't succeed to find a corresponding record
@ -140,7 +136,8 @@ sub upload {
# Create slice file
my $file = catfile($dir, $json->{part}.'.part');
my $s = Lufi::Slice->new(
my $s = Lufi::DB::Slice->new(
app => $c->app,
short => $f->short,
j => $json->{part},
path => $file
@ -176,14 +173,14 @@ sub upload {
}
));
} else {
$ws->send(encode_json(
$ws->send(decode('UTF-8', encode_json(
{
success => false,
msg => $c->l('The server was unable to find the file record to add your file part to. Please, contact the administrator.'),
sent_delay => $json->{delay},
i => $json->{i}
}
));
)));
}
}
}
@ -203,37 +200,35 @@ sub download {
$c->inactivity_timeout(300000);
$c->app->log->debug('Client connected');
my @records = LufiDB::Files->select('WHERE short = ?', $short);
my $ldfile = Lufi::DB::File->new(app => $c->app)->from_short($short);
# Do we have a file?
if (scalar @records) {
my $record = $records[0];
if (defined $ldfile) {
# Is the file fully uploaded?
if ($record->deleted
if ($ldfile->deleted
|| (
$record->delete_at_day != 0
$ldfile->delete_at_day != 0
&& (
($record->created_at + $record->delete_at_day * 86400) < time()
($ldfile->created_at + $ldfile->delete_at_day * 86400) < time()
)
)
) {
unless ($record->deleted) {
my $f = Lufi::File->new(record => $record);
$f->delete;
unless ($ldfile->deleted) {
$ldfile->delete;
}
$c->on(
message => sub {
my ($ws, $json) = @_;
$c->send(encode_json(
$c->send(decode('UTF-8', encode_json(
{
success => false,
msg => $c->l('Error: the file existed but was deleted.')
}
));
)));
}
);
} elsif ($record->complete) {
my $f = Lufi::File->new(record => $record);
} elsif ($ldfile->complete) {
my $f = $ldfile;
$c->on(
message => sub {
@ -273,7 +268,11 @@ sub download {
}
}
} else {
$c->send(encode_json({msg => $c->l('Your password is not valid. Please refresh the page to retry.')}));
$c->send(decode('UTF-8', encode_json(
{
msg => $c->l('Your password is not valid. Please refresh the page to retry.')
}
)));
}
}
);
@ -286,22 +285,22 @@ sub download {
$c->on(
message => sub {
my ($ws, $json) = @_;
$c->send(encode_json(
$c->send(decode('UTF-8', encode_json(
{
success => false,
msg => $c->l('Error: the file has not been sent entirely.')
}
));
)));
}
);
}
} else {
$c->send(encode_json(
$c->send(decode('UTF-8', encode_json(
{
success => false,
msg => $c->l('Error: unable to find the file. Are you sure of your URL?')
}
));
)));
}
}
@ -309,13 +308,13 @@ sub r {
my $c = shift;
my $short = $c->param('short');
my @records = LufiDB::Files->select('WHERE short = ?', $short);
if (scalar @records) {
my $f = Lufi::File->new(record => $records[0]);
my $ldfile = Lufi::DB::File->new(app => $c->app)->from_short($short);
if (defined $ldfile) {
return $c->render(
template => 'render',
f => $f,
file_pwd => ($c->config('allow_pwd_on_files') && defined($records[0]->{passwd}))
f => $ldfile,
file_pwd => ($c->config('allow_pwd_on_files') && defined($ldfile->passwd))
);
} else {
return $c->render(
@ -331,15 +330,16 @@ sub get_counter {
my $token = $c->param('token');
if ((!defined($c->config('ldap')) && !defined($c->config('htpasswd'))) || $c->is_user_authenticated) {
my @records = LufiDB::Files->select('WHERE short = ?', $short);
if (scalar(@records)) {
if ($records[0]->mod_token eq $token) {
my $ldfile = Lufi::DB::File->new(app => $c->app)->from_short($short);
if (defined $ldfile) {
if ($ldfile->mod_token eq $token) {
return $c->render(
json => {
success => true,
short => $short,
counter => $records[0]->counter,
deleted => ($records[0]->deleted) ? true : false
counter => $ldfile->counter,
deleted => ($ldfile->deleted) ? true : false
}
);
} else {
@ -380,14 +380,16 @@ sub delete {
my $token = $c->param('token');
if ((!defined($c->config('ldap')) && !defined($c->config('htpasswd'))) || $c->is_user_authenticated) {
my @records = LufiDB::Files->select('WHERE short = ? AND mod_token = ?', ($short, $token));
if (scalar(@records)) {
my $f = Lufi::File->new(record => $records[0]);
my $ldfile = Lufi::DB::File->new(app => $c->app)->from_short($short);
$ldfile = undef unless (defined($ldfile) && $ldfile->mod_token eq $token);
if (defined $ldfile) {
my $msg;
if ($f->deleted) {
if ($ldfile->deleted) {
$msg = $c->l('The file has already been deleted');
} else {
$f->delete;
$ldfile->delete;
$msg = $c->l('File deleted');
}
return $c->respond_to(
@ -400,7 +402,7 @@ sub delete {
any => sub {
$c->render(
template => 'msg',
f => $f,
f => $ldfile,
msg => $msg
);
}

View File

@ -2,22 +2,18 @@
package Lufi::Controller::Misc;
use Mojo::Base 'Mojolicious::Controller';
use Mojo::File;
use LufiDB;
use Lufi::File;
use Lufi::Slice;
use Lufi::DB::File;
sub fullstats {
my $c = shift;
my $files = LufiDB::Files->count('WHERE created_at IS NOT null AND deleted = 0');
my $deleted = LufiDB::Files->count('WHERE created_at IS NOT null AND deleted = 1');
my $empty = LufiDB::Files->count('WHERE created_at IS null');
my $stats = Lufi::DB::File->new(app => $c->app)->get_stats;
return $c->render(
json => {
files => $files,
deleted => $deleted,
empty => $empty,
files => $stats->{files},
deleted => $stats->{deleted},
empty => $stats->{empty},
timestamp => time,
}
);

291
lib/Lufi/DB/File.pm Normal file
View File

@ -0,0 +1,291 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lufi::DB::File;
use Mojo::Base -base;
use Mojo::Collection;
has 'short';
has 'deleted' => 0;
has 'mediatype';
has 'filename';
has 'filesize';
has 'counter' => 0;
has 'delete_at_first_view' => 0;
has 'delete_at_day';
has 'created_at' => sub {
return time;
};
has 'created_by';
has 'last_access_at';
has 'mod_token';
has 'nbslices';
has 'complete' => 0;
has 'slices' => sub {
return Mojo::Collection->new();
};
has 'passwd';
has 'app';
=head1 NAME
Lufi::DB::File - DB abstraction layer for Lufi file
=head1 Contributing
When creating a new database accessor, make sure that it provides the following subroutines.
After that, modify this file and modify the C<new> subroutine to allow to use your accessor.
Have a look at Lufi::DB::File::SQLite's code: it's simple and may be more understandable that this doc.
=head1 Attributes
=over 1
=item B<short> : string
=item B<deleted> : boolean
=item B<mediatype> : string
=item B<filename> : string
=item B<filesize> : integer
=item B<counter> : integer
=item B<delete_at_first_view> : boolean
=item B<delete_at_day> : integer
=item B<created_at> : unix timestamp
=item B<created_by> : string
=item B<last_access_at> : unix timestamp
=item B<mod_token> : string
=item B<nbslices> : integer
=item B<complete> : boolean
=item B<slices> : Mojo::Collection of Lufi::DB::Slice
=item B<passwd> : string
=item B<app> : a Mojolicious object
=back
=head1 Sub routines
=head2 new
=over 1
=item B<Usage> : C<$c = Lufi::DB::File-E<gt>new(app =E<gt> $self);>
=item B<Arguments> : any of the attribute above
=item B<Purpose> : construct a new db accessor object. If the C<short> attribute is provided, it have to load the informations from the database.
=item B<Returns> : the db accessor object
=item B<Info> : the app argument is used by Lufi::DB::File to choose which db accessor will be used, you don't need to use it in new(), but you can use it to access helpers or configuration settings in the other subroutines
=back
=cut
sub new {
my $c = shift;
$c = $c->SUPER::new(@_);
if (ref($c) eq 'Lufi::DB::File') {
my $dbtype = $c->app->config('dbtype');
if ($dbtype eq 'sqlite') {
use Lufi::DB::File::SQLite;
$c = Lufi::DB::File::SQLite->new(@_);
#} elsif ($dbtype eq 'postgresql') {
#use Lufi::DB::File::Pg;
#$c = Lufi::DB::File::Pg->new(@_);
}
}
return $c;
}
=head2 delete
=over 1
=item B<Usage> : C<$c-E<gt>delet>
=item B<Arguments> : none
=item B<Purpose> : delete the files of the slices and the directory containing those files, then update the object by setting the deleted attribute to 1 (true)
=item B<Returns> : the db accessor object
=back
=cut
sub delete {
my $c = shift;
$c->slices->each(sub {
my ($e, $num) = @_;
unlink $e->path;
});
rmdir Mojo::File->new($c->app->config('upload_dir'), $c->short);
$c->deleted(1);
$c->write;
return $c;
}
=head2 write
=over 1
=item B<Usage> : C<$c-E<gt>write>
=item B<Arguments> : none
=item B<Purpose> : create or update a record in the database, with the values of the object's attributes
=item B<Returns> : the db accessor object
=back
=head2 count_empty
=over 1
=item B<Usage> : C<$c-E<gt>count_empty>
=item B<Arguments> : none
=item B<Purpose> : count how many records have a null created_at column
=item B<Returns> : integer
=back
=head2 already_exists
=over 1
=item B<Usage> : C<$c-E<gt>already_exists($short)>
=item B<Arguments> : a string
=item B<Purpose> : check if the given string is already used as short attribute for a file
=item B<Returns> : 1 or 0
=back
=head2 get_empty
=over 1
=item B<Usage> : C<$c-E<gt>get_empty>
=item B<Arguments> : none
=item B<Purpose> : select an empty ready-to-use record from the database
=item B<Returns> : a db accessor object
=back
=head2 get_stats
=over 1
=item B<Usage> : C<$c-E<gt>get_stats>
=item B<Arguments> : none
=item B<Purpose> : get stats about how many empty files, deleted files and non-deleted files there is in the database
=item B<Returns> : a hash table reference containing three keys: files, deleted and empty
=back
=head2 from_short
=over 1
=item B<Usage> : C<$c-E<gt>from_short($short)>
=item B<Arguments> : string
=item B<Purpose> : find a file in the database from its short attribute
=item B<Returns> : a db accessor object
=back
=head2 get_oldest_undeleted_files
=over 1
=item B<Usage> : C<$c-E<gt>get_oldest_undeleted_files($num)>
=item B<Arguments> : integer
=item B<Purpose> : get the X oldest non-deleted files
=item B<Returns> : a Mojo::Collection of Lufi::DB::File objects
=back
=head2 get_expired
=over 1
=item B<Usage> : C<$c-E<gt>get_expired($time)>
=item B<Arguments> : unix timestamp
=item B<Purpose> : get the non-deleted files that are expired at the given timestamp minus 2 days
=item B<Returns> : a Mojo::Collection of Lufi::DB::File objects
=back
=head2 get_no_longer_viewed
=over 1
=item B<Usage> : C<$c-E<gt>get_no_longer_viewed($time)>
=item B<Arguments> : unix timestamp
=item B<Purpose> : get the files that have not been viewed after the given timestamp
=item B<Returns> : a Mojo::Collection of Lufi::DB::File objects
=back
=head2 delete_creator_before
=over 1
=item B<Usage> : C<$c-E<gt>delete_creator_before($time)>
=item B<Arguments> : unix timestamp
=item B<Purpose> : empty the created_by column for files created before the given timestamp
=item B<Returns> : nothing
=back
=cut
1;

192
lib/Lufi/DB/File/SQLite.pm Normal file
View File

@ -0,0 +1,192 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lufi::DB::File::SQLite;
use Mojo::Base 'Lufi::DB::File';
use Mojo::File;
use Mojo::Collection 'c';
use Lufi::DB::SQLite;
use Lufi::DB::Slice;
has 'record';
sub new {
my $c = shift;
$c = $c->SUPER::new(@_);
$c = $c->_slurp if defined $c->record;
return $c;
}
sub write {
my $c = shift;
if (defined $c->record) {
$c->record->update(
short => $c->short,
deleted => $c->deleted,
mediatype => $c->mediatype,
filename => $c->filename,
filesize => $c->filesize,
counter => $c->counter,
delete_at_first_view => $c->delete_at_first_view,
delete_at_day => $c->delete_at_day,
created_at => $c->created_at,
created_by => $c->created_by,
last_access_at => $c->last_access_at,
mod_token => $c->mod_token,
nbslices => $c->nbslices,
complete => $c->complete,
passwd => $c->passwd,
);
} else {
my $record = Lufi::DB::SQLite::Files->create(
short => $c->short,
deleted => $c->deleted,
mediatype => $c->mediatype,
filename => $c->filename,
filesize => $c->filesize,
counter => $c->counter,
delete_at_first_view => $c->delete_at_first_view,
delete_at_day => $c->delete_at_day,
created_at => $c->created_at,
created_by => $c->created_by,
last_access_at => $c->last_access_at,
mod_token => $c->mod_token,
nbslices => $c->nbslices,
complete => $c->complete,
passwd => $c->passwd,
);
$c->record($record);
}
return $c;
}
sub count_empty {
my $c = shift;
return Lufi::DB::SQLite::Files->count('WHERE created_at IS NULL');
}
sub already_exists {
my $c = shift;
my $short = shift;
return Lufi::DB::SQLite::Files->count('WHERE short = ?', $short);
}
sub get_empty {
my $c = shift;
my @records = Lufi::DB::SQLite::Files->select('WHERE created_at IS NULL LIMIT 1');
$c->record($records[0]);
$c->record->update(created_at => time);
$c->write;
$c->_slurp;
return $c;
}
sub get_stats {
my $c = shift;
my $files = Lufi::DB::SQLite::Files->count('WHERE created_at IS NOT null AND deleted = 0');
my $deleted = Lufi::DB::SQLite::Files->count('WHERE created_at IS NOT null AND deleted = 1');
my $empty = Lufi::DB::SQLite::Files->count('WHERE created_at IS null');
return {files => $files, deleted => $deleted, empty => $empty};
}
sub from_short {
my $c = shift;
my $short = shift;
my @records = Lufi::DB::SQLite::Files->select('WHERE short = ?', $short);
if (scalar @records) {
$c->record($records[0]);
$c->_slurp;
return $c;
} else {
return undef;
}
}
sub get_oldest_undeleted_files {
my $c = shift;
my $num = shift;
my @files = Lufi::DB::SQLite::Files->select('WHERE deleted = 0 ORDER BY created_at ASC LIMIT ?', $num);
return c(map { Lufi::DB::File->new(app => $c->app, record => $_) } @files);
}
sub get_expired {
my $c = shift;
my $time = shift;
## Select only files expired since two days, to be sure that nobody is still downloading it
my @files = LufiDB::Files->select('WHERE deleted = 0 AND ((delete_at_day + 2) * 86400) < (? - created_at) AND delete_at_day != 0', $time);
return c(map { Lufi::DB::File->new(app => $c->app, record => $_) } @files);
}
sub get_no_longer_viewed {
my $c = shift;
my $time = shift;
my @files = LufiDB::Files->select('WHERE deleted = 0 AND last_access_at < ?', $time);
return c(map { Lufi::DB::File->new(app => $c->app, record => $_) } @files);
}
sub delete_creator_before {
my $c = shift;
my $separation = shift;
Lufi::DB::SQLite->do(
'UPDATE files SET created_by = NULL WHERE created_by IS NOT NULL AND created_at < ?',
{},
$separation
);
}
sub _slurp {
my $c = shift;
my @files;
if ($c->record) {
@files = ($c->record);
} elsif ($c->short) {
@files = Lufi::DB::SQLite::Files->select('WHERE short = ?', $c->short);
}
if (scalar @files) {
my $file = $files[0];
$c->short($file->short);
$c->deleted($file->deleted) if defined $file->deleted;
$c->mediatype($file->mediatype) if defined $file->mediatype;
$c->filename($file->filename) if defined $file->filename;
$c->filesize($file->filesize) if defined $file->filesize;
$c->counter($file->counter) if defined $file->counter;
$c->delete_at_first_view($file->delete_at_first_view) if defined $file->delete_at_first_view;
$c->delete_at_day($file->delete_at_day) if defined $file->delete_at_day;
$c->created_at($file->created_at) if defined $file->created_at;
$c->created_by($file->created_by) if defined $file->created_by;
$c->last_access_at($file->last_access_at) if defined $file->last_access_at;
$c->mod_token($file->mod_token) if defined $file->mod_token;
$c->nbslices($file->nbslices) if defined $file->nbslices;
$c->complete($file->complete) if defined $file->complete;
$c->passwd($file->passwd) if defined $file->passwd;
$c->record($file) unless $c->record;
}
$c->slices(Lufi::DB::Slice->new(app => $c->app)->get_slices_of_file($c->short));
return $c;
}
1;

View File

@ -1,14 +1,21 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package LufiDB;
package Lufi::DB::SQLite;
use Mojolicious;
use Mojo::File;
use FindBin qw($Bin);
use File::Spec::Functions;
BEGIN {
my $m = Mojolicious->new;
my $cfile = Mojo::File->new($Bin, '..' , 'lufi.conf');
if (defined $ENV{MOJO_CONFIG}) {
$cfile = Mojo::File->new($ENV{MOJO_CONFIG});
unless (-e $cfile->to_abs) {
$cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG});
}
}
our $config = $m->plugin('Config' =>
{
file => catfile($Bin, '..' ,'lufi.conf'),
file => $cfile->to_abs->to_string,
default => {
db_path => 'lufi.db'
}

104
lib/Lufi/DB/Slice.pm Normal file
View File

@ -0,0 +1,104 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lufi::DB::Slice;
use Mojo::Base -base;
has 'short';
has 'j';
has 'path';
has 'app';
=head1 NAME
Lufi::DB::Slice - DB abstraction layer for Lufi file
=head1 Contributing
When creating a new database accessor, make sure that it provides the following subroutines.
After that, modify this file and modify the C<new> subroutine to allow to use your accessor.
Have a look at Lufi::DB::Slice::SQLite's code: it's simple and may be more understandable that this doc.
=head1 Attributes
=over 1
=item B<short> : string
=item B<j> : integer
=item B<path> : string
=item B<app> : A mojolicious object
=back
=head1 Sub routines
=head2 new
=over 1
=item B<Usage> : C<$c = Lufi::DB::Slice-E<gt>new(app =E<gt> $self);>
=item B<Arguments> : any of the attribute above
=item B<Purpose> : construct a new db accessor object. If the C<short> attribute is provided, it have to load the informations from the database.
=item B<Returns> : the db accessor object
=item B<Info> : the app argument is used by Lufi::DB::Slice to choose which db accessor will be used, you don't need to use it in new(), but you can use it to access helpers or configuration settings in the other subroutines
=back
=cut
sub new {
my $c = shift;
$c = $c->SUPER::new(@_);
if (ref($c) eq 'Lufi::DB::Slice') {
my $dbtype = $c->app->config('dbtype');
if ($dbtype eq 'sqlite') {
use Lufi::DB::Slice::SQLite;
$c = Lufi::DB::Slice::SQLite->new(@_);
#} elsif ($dbtype eq 'postgresql') {
# use Lufi::DB::Slice::Pg;
# $c = Lufi::DB::Slice::Pg->new(@_);
}
}
return $c;
}
=head2 write
=over 1
=item B<Usage> : C<$c-E<gt>write>
=item B<Arguments> : none
=item B<Purpose> : create or update a record in the database, with the values of the object's attributes
=item B<Returns> : the db accessor object
=back
=head2 get_slices_of_file
=over 1
=item B<Usage> : C<$c-E<gt>get_slices_of_file($short)>
=item B<Arguments> : string
=item B<Purpose> : get all Lufi::DB::Slice objects related to a file
=item B<Returns> : a Mojo::Collection of Lufi::DB::Slice objects
=back
=cut
1;

View File

@ -1,12 +1,10 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lufi::Slice;
use Mojo::Base -base;
use LufiDB;
package Lufi::DB::Slice::SQLite;
use Mojo::Base 'Lufi::DB::Slice';
use Lufi::DB::SQLite;
use Mojo::Collection 'c';
has 'record';
has 'short';
has 'j';
has 'path';
sub new {
my $c = shift;
@ -28,7 +26,7 @@ sub write {
path => $c->path
);
} else {
my $record = LufiDB::Slices->create(
my $record = Lufi::DB::SQLite::Slices->create(
short => $c->short,
j => $c->j,
path => $c->path
@ -39,6 +37,15 @@ sub write {
return $c;
}
sub get_slices_of_file {
my $c = shift;
my $short = shift;
my @slices = Lufi::DB::SQLite::Slices->select('WHERE short = ? ORDER BY j ASC', $short);
return c(map { Lufi::DB::Slice->new(app => $c->app, record => $_) } @slices);
}
sub _slurp {
my $c = shift;

View File

@ -1,103 +0,0 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lufi::File;
use Mojo::Base -base;
use Mojo::Collection;
use LufiDB;
use Lufi::Slice;
has 'record';
has 'short';
has 'deleted' => 0;
has 'mediatype';
has 'filename';
has 'filesize';
has 'counter' => 0;
has 'delete_at_first_view' => 0;
has 'delete_at_day';
has 'created_at' => sub {
return time;
};
has 'created_by';
has 'last_access_at';
has 'mod_token';
has 'nbslices';
has 'complete' => 0;
has 'slices' => sub {
return Mojo::Collection->new();
};
has 'passwd';
sub new {
my $c = shift;
$c = $c->SUPER::new(@_);
$c = $c->_slurp if defined $c->record;
return $c;
}
sub write {
my $c = shift;
$c->record->update(
deleted => $c->deleted,
mediatype => $c->mediatype,
filename => $c->filename,
filesize => $c->filesize,
counter => $c->counter,
delete_at_first_view => $c->delete_at_first_view,
delete_at_day => $c->delete_at_day,
created_at => $c->created_at,
created_by => $c->created_by,
last_access_at => $c->last_access_at,
mod_token => $c->mod_token,
nbslices => $c->nbslices,
complete => $c->complete,
passwd => $c->passwd,
);
return $c;
}
sub delete {
my $c = shift;
$c->slices->each(sub {
my ($e, $num) = @_;
unlink $e->path;
});
$c->deleted(1);
$c->write;
return $c;
}
sub _slurp {
my $c = shift;
$c->short($c->record->short);
$c->deleted($c->record->deleted) if defined $c->record->deleted;
$c->mediatype($c->record->mediatype) if defined $c->record->mediatype;
$c->filename($c->record->filename) if defined $c->record->filename;
$c->filesize($c->record->filesize) if defined $c->record->filesize;
$c->counter($c->record->counter) if defined $c->record->counter;
$c->delete_at_first_view($c->record->delete_at_first_view) if defined $c->record->delete_at_first_view;
$c->delete_at_day($c->record->delete_at_day) if defined $c->record->delete_at_day;
$c->created_at($c->record->created_at) if defined $c->record->created_at;
$c->created_by($c->record->created_by) if defined $c->record->created_by;
$c->last_access_at($c->record->last_access_at) if defined $c->record->last_access_at;
$c->mod_token($c->record->mod_token) if defined $c->record->mod_token;
$c->nbslices($c->record->nbslices) if defined $c->record->nbslices;
$c->complete($c->record->complete) if defined $c->record->complete;
$c->passwd($c->record->passwd) if defined $c->record->passwd;
my @slices = LufiDB::Slices->select('WHERE short = ? ORDER BY j ASC', $c->short);
$c->slices(Mojo::Collection->new(map { Lufi::Slice->new(record => $_) } @slices));
return $c;
}
1;

View File

@ -1,20 +1,37 @@
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lufi::Plugin::Helpers;
use Mojo::Base 'Mojolicious::Plugin';
use Lufi::DB::File;
use Data::Entropy qw(entropy_source);
use LufiDB;
sub register {
my ($self, $app) = @_;
# SQLite database migration if needed
my $columns = LufiDB::Files->table_info;
my $pwd_col = 0;
foreach my $col (@{$columns}) {
$pwd_col = 1 if $col->{name} eq 'passwd';
}
unless ($pwd_col) {
LufiDB->do('ALTER TABLE files ADD COLUMN passwd TEXT;');
$app->plugin('PgURLHelper');
#
# if ($app->config('dbtype') eq 'postgresql') {
# use Mojo::Pg;
# $app->helper(pg => \&_pg);
#
# # Database migration
# my $migrations = Mojo::Pg::Migrations->new(pg => $app->pg);
# if ($app->mode eq 'development' && $ENV{LUFI_DEV} == 1) {
# $migrations->from_file('utilities/migrations.sql')->migrate(0)->migrate(1);
# } else {
# $migrations->from_file('utilities/migrations.sql')->migrate(1);
# }
# } elsif ($app->config('dbtype') eq 'sqlite') {
if ($app->config('dbtype') eq 'sqlite') {
# SQLite database migration if needed
use Lufi::DB::SQLite;
my $columns = Lufi::DB::SQLite::Files->table_info;
my $pwd_col = 0;
foreach my $col (@{$columns}) {
$pwd_col = 1 if $col->{name} eq 'passwd';
}
unless ($pwd_col) {
Lufi::DB::SQLite->do('ALTER TABLE files ADD COLUMN passwd TEXT;');
}
}
$app->helper(provisioning => \&_provisioning);
@ -27,23 +44,26 @@ sub register {
$app->helper(stop_upload => \&_stop_upload);
}
sub _pg {
my $c = shift;
state $pg = Mojo::Pg->new($c->app->pg_url($c->app->config('pgdb')));
return $pg;
}
sub _provisioning {
my $c = shift;
# Create some short patterns for provisioning
if (LufiDB::Files->count('WHERE created_at IS NULL') < $c->config('provisioning')) {
for (my $i = 0; $i < $c->config('provis_step'); $i++) {
if (LufiDB->begin) {
my $short;
do {
$short= $c->shortener($c->config('length'));
} while (LufiDB::Files->count('WHERE short = ?', $short));
my $ldfile = Lufi::DB::File->new(app => $c->app);
if ($ldfile->count_empty < $c->app->config('provisioning')) {
for (my $i = 0; $i < $c->app->config('provis_step'); $i++) {
my $short;
do {
$short = $c->shortener($c->app->config('length'));
} while ($ldfile->already_exists($short));
LufiDB::Files->create(
short => $short
);
LufiDB->commit;
}
$ldfile->created_at(undef)->short($short)->write;
}
}
}
@ -51,8 +71,9 @@ sub _provisioning {
sub _get_empty {
my $c = shift;
my @records = LufiDB::Files->select('WHERE created_at IS NULL LIMIT 1');
return $records[0];
my $ldfile = Lufi::DB::File->new(app => $c->app)->get_empty;
return $ldfile;
}
sub _shortener {
@ -79,7 +100,7 @@ sub _ip {
sub _default_delay {
my $c = shift;
return $c->config('default_delay') if ($c->config('default_delay') >= 0);
return $c->app->config('default_delay') if ($c->app->config('default_delay') >= 0);
warn "default_delay set to a negative value. Default to 0.";
return 0;
@ -88,7 +109,7 @@ sub _default_delay {
sub _max_delay {
my $c = shift;
return $c->config('max_delay') if ($c->config('max_delay') >= 0);
return $c->app->config('max_delay') if ($c->app->config('max_delay') >= 0);
warn "max_delay set to a negative value. Default to 0.";
return 0;

View File

@ -107,12 +107,28 @@
# Optional, default to no-reply@lufi.io
#mail_sender => 'no-reply@lufi.io',
# choose what database you want to use
# valid choices are sqlite and postgresql (all lowercase)
# optional, default is sqlite
#dbtype => 'sqlite',
# SQLite ONLY - only used if dbtype is set to sqlite
# define a path to the SQLite database
# you can define it relative to lufi directory or set an absolute path
# remember that it has to be in a directory writable by Lufi user
# remember that it has to be in a directory writable by Lutim user
# optional, default is lufi.db
#db_path => 'lufi.db',
# PostgreSQL ONLY - only used if dbtype is set to postgresql
# these are the credentials to access the PostgreSQL database
# mandatory if you choosed postgresql as dbtype
#pgdb => {
# database => 'lufi',
# host => 'localhost',
# #user => 'DBUSER',
# #pwd => 'DBPASSWORD'
#},
# define a path to the upload directory, where the uploaded files will be stored
# you can define it relative to lufi directory or set an absolute path
# remember that it has to be in a directory writable by Lufi user

View File

@ -93,15 +93,15 @@ msgstr "Copia tots els enllaços al porta-retalls"
msgid "Copy to clipboard"
msgstr "Copia al porta-retalls"
#: lib/Lufi/Controller/Files.pm:423
#: lib/Lufi/Controller/Files.pm:429
msgid "Could not delete the file. You are not authenticated."
msgstr "No es pot esborrar el fitxer. No esteu autenticat."
#: lib/Lufi/Controller/Files.pm:407
#: lib/Lufi/Controller/Files.pm:411
msgid "Could not find the file. Are you sure of the URL and the token?"
msgstr "No es troba el fitxer. Esteu segur de la URL i el testimoni?"
#: lib/Lufi/Controller/Files.pm:323
#: lib/Lufi/Controller/Files.pm:322
msgid "Could not find the file. Are you sure of the URL?"
msgstr "No trobo el fitxer. Esteu segurs de la URL?"
@ -157,15 +157,15 @@ msgstr "correus electrònics"
msgid "Encrypting part XX1 of XX2"
msgstr "S'està xifrant la part XX1 de XX2"
#: lib/Lufi/Controller/Files.pm:230
#: lib/Lufi/Controller/Files.pm:225
msgid "Error: the file existed but was deleted."
msgstr "Error: el fitxer existia però va ser eliminat."
#: lib/Lufi/Controller/Files.pm:292
#: lib/Lufi/Controller/Files.pm:291
msgid "Error: the file has not been sent entirely."
msgstr "Error: el fitxer no s'ha enviat del tot."
#: lib/Lufi/Controller/Files.pm:302
#: lib/Lufi/Controller/Files.pm:301
msgid "Error: unable to find the file. Are you sure of your URL?"
msgstr "Error: no trobo el fitxer. Esteu segur de la URL ?"
@ -181,7 +181,7 @@ msgstr "Expira el"
msgid "Export localStorage data"
msgstr "Exporta dades a l'emmagatzematge local"
#: lib/Lufi/Controller/Files.pm:391
#: lib/Lufi/Controller/Files.pm:393
msgid "File deleted"
msgstr "Fitxer eliminat"
@ -275,7 +275,7 @@ msgid "My files"
msgstr "Els meus fitxers"
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:70
#: lib/Lufi/Controller/Files.pm:69
msgid "No enough space available on the server for this file (size: %1)."
msgstr "No hi ha prou espai al servidor per a aquest fitxer (mida: %1)"
@ -300,7 +300,7 @@ msgstr "Si us plau contacteu amb l'administrador: %1"
msgid "Please wait while we are getting your file. We first need to download and decrypt all parts before you can get it."
msgstr "Si us plau, espereu mentre obtenim el fitxer. Abans que el tingueu disponible primer cal descarregar i desxifrar tots els trossos."
#: lib/Lufi.pm:300
#: lib/Lufi.pm:191
msgid "Please, check your credentials: unable to authenticate."
msgstr ""
@ -341,7 +341,7 @@ msgstr "Compartiu fitxers amb total privacitat a %1"
msgid "Signin"
msgstr "Autenticació"
#: lib/Lufi.pm:303
#: lib/Lufi.pm:194
msgid "Sorry mate, you are not authorised to use that service. Contact your sysadmin if you think there's a glitch in the matrix."
msgstr ""
@ -349,7 +349,7 @@ msgstr ""
msgid "Sorry, the uploading is currently disabled. Please try again later."
msgstr "Disculpeu, les pujades estan actualment desactivades. Si us plau proveu-ho més tard."
#: lib/Lufi/Controller/Files.pm:44
#: lib/Lufi/Controller/Files.pm:43
msgid "Sorry, uploading is disabled."
msgstr "Disculpeu, les pujades estan deshabilitades"
@ -371,7 +371,7 @@ msgstr "El cos del correu no pot estar buit."
msgid "The email subject can't be empty."
msgstr "L'assumpte dle correu no pot estar buit."
#: lib/Lufi/Controller/Files.pm:388
#: lib/Lufi/Controller/Files.pm:390
msgid "The file has already been deleted"
msgstr "El fitxer ja ha estat esborrat"
@ -396,7 +396,7 @@ msgstr "El correu ja està enviat."
msgid "The original (and only for now) author is <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. If you want to support him, you can do it via <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> or via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
msgstr "L'autor original (i per ara l'únic) és <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. Si voleu fer una contribució podeu fer-ho via <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> o via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
#: lib/Lufi/Controller/Files.pm:182
#: lib/Lufi/Controller/Files.pm:179
msgid "The server was unable to find the file record to add your file part to. Please, contact the administrator."
msgstr "El servidor no ha pogut trobar el registre del fitxer per afegir-hi el tros del fitxer. Si us plau, contacteu l'administrador."
@ -476,11 +476,11 @@ msgid "You must give email addresses."
msgstr "Heu de donar l'adreça de correu electrònic."
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:57
#: lib/Lufi/Controller/Files.pm:56
msgid "Your file is too big: %1 (maximum size allowed: %2)"
msgstr "El fitxer és massa gran: %1 (mida màxima admesa: %2)"
#: lib/Lufi/Controller/Files.pm:276
#: lib/Lufi/Controller/Files.pm:273
msgid "Your password is not valid. Please refresh the page to retry."
msgstr ""

View File

@ -90,15 +90,15 @@ msgstr ""
msgid "Copy to clipboard"
msgstr ""
#: lib/Lufi/Controller/Files.pm:423
#: lib/Lufi/Controller/Files.pm:429
msgid "Could not delete the file. You are not authenticated."
msgstr ""
#: lib/Lufi/Controller/Files.pm:407
#: lib/Lufi/Controller/Files.pm:411
msgid "Could not find the file. Are you sure of the URL and the token?"
msgstr ""
#: lib/Lufi/Controller/Files.pm:323
#: lib/Lufi/Controller/Files.pm:322
msgid "Could not find the file. Are you sure of the URL?"
msgstr ""
@ -154,15 +154,15 @@ msgstr ""
msgid "Encrypting part XX1 of XX2"
msgstr ""
#: lib/Lufi/Controller/Files.pm:230
#: lib/Lufi/Controller/Files.pm:225
msgid "Error: the file existed but was deleted."
msgstr ""
#: lib/Lufi/Controller/Files.pm:292
#: lib/Lufi/Controller/Files.pm:291
msgid "Error: the file has not been sent entirely."
msgstr ""
#: lib/Lufi/Controller/Files.pm:302
#: lib/Lufi/Controller/Files.pm:301
msgid "Error: unable to find the file. Are you sure of your URL?"
msgstr ""
@ -178,7 +178,7 @@ msgstr ""
msgid "Export localStorage data"
msgstr ""
#: lib/Lufi/Controller/Files.pm:391
#: lib/Lufi/Controller/Files.pm:393
msgid "File deleted"
msgstr ""
@ -271,7 +271,7 @@ msgid "My files"
msgstr ""
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:70
#: lib/Lufi/Controller/Files.pm:69
msgid "No enough space available on the server for this file (size: %1)."
msgstr ""
@ -296,7 +296,7 @@ msgstr ""
msgid "Please wait while we are getting your file. We first need to download and decrypt all parts before you can get it."
msgstr ""
#: lib/Lufi.pm:300
#: lib/Lufi.pm:191
msgid "Please, check your credentials: unable to authenticate."
msgstr ""
@ -337,7 +337,7 @@ msgstr ""
msgid "Signin"
msgstr ""
#: lib/Lufi.pm:303
#: lib/Lufi.pm:194
msgid "Sorry mate, you are not authorised to use that service. Contact your sysadmin if you think there's a glitch in the matrix."
msgstr ""
@ -345,7 +345,7 @@ msgstr ""
msgid "Sorry, the uploading is currently disabled. Please try again later."
msgstr ""
#: lib/Lufi/Controller/Files.pm:44
#: lib/Lufi/Controller/Files.pm:43
msgid "Sorry, uploading is disabled."
msgstr ""
@ -365,7 +365,7 @@ msgstr ""
msgid "The email subject can't be empty."
msgstr ""
#: lib/Lufi/Controller/Files.pm:388
#: lib/Lufi/Controller/Files.pm:390
msgid "The file has already been deleted"
msgstr ""
@ -390,7 +390,7 @@ msgstr ""
msgid "The original (and only for now) author is <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. If you want to support him, you can do it via <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> or via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
msgstr ""
#: lib/Lufi/Controller/Files.pm:182
#: lib/Lufi/Controller/Files.pm:179
msgid "The server was unable to find the file record to add your file part to. Please, contact the administrator."
msgstr ""
@ -470,11 +470,11 @@ msgid "You must give email addresses."
msgstr ""
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:57
#: lib/Lufi/Controller/Files.pm:56
msgid "Your file is too big: %1 (maximum size allowed: %2)"
msgstr ""
#: lib/Lufi/Controller/Files.pm:276
#: lib/Lufi/Controller/Files.pm:273
msgid "Your password is not valid. Please refresh the page to retry."
msgstr ""

View File

@ -92,15 +92,15 @@ msgstr "Copier tous les liens dans le presse-papier"
msgid "Copy to clipboard"
msgstr "Copier dans le presse-papier"
#: lib/Lufi/Controller/Files.pm:423
#: lib/Lufi/Controller/Files.pm:429
msgid "Could not delete the file. You are not authenticated."
msgstr "Impossible de supprimer le fichier. Vous nêtes pas connecté·e."
#: lib/Lufi/Controller/Files.pm:407
#: lib/Lufi/Controller/Files.pm:411
msgid "Could not find the file. Are you sure of the URL and the token?"
msgstr "Impossible de retrouver le fichier. Êtes-vous sûr(e) que lURL et le jeton sont les bons ?"
#: lib/Lufi/Controller/Files.pm:323
#: lib/Lufi/Controller/Files.pm:322
msgid "Could not find the file. Are you sure of the URL?"
msgstr "Impossible de retrouver le fichier. Êtes-vous sûr(e) que lURL est la bonne ?"
@ -156,15 +156,15 @@ msgstr "Mails"
msgid "Encrypting part XX1 of XX2"
msgstr "Chiffrement du fragment XX1 sur XX2"
#: lib/Lufi/Controller/Files.pm:230
#: lib/Lufi/Controller/Files.pm:225
msgid "Error: the file existed but was deleted."
msgstr "Erreur : le fichier existait mais a été supprimé"
#: lib/Lufi/Controller/Files.pm:292
#: lib/Lufi/Controller/Files.pm:291
msgid "Error: the file has not been sent entirely."
msgstr "Erreur : le fichier na pas été envoyé dans son intégralité"
#: lib/Lufi/Controller/Files.pm:302
#: lib/Lufi/Controller/Files.pm:301
msgid "Error: unable to find the file. Are you sure of your URL?"
msgstr "Erreur : impossible de retrouver le fichier. Êtes-vous sûr(e) de lURL ?"
@ -180,7 +180,7 @@ msgstr "Expire le"
msgid "Export localStorage data"
msgstr "Exporter les données localStorage"
#: lib/Lufi/Controller/Files.pm:391
#: lib/Lufi/Controller/Files.pm:393
msgid "File deleted"
msgstr "Fichier supprimé"
@ -273,7 +273,7 @@ msgid "My files"
msgstr "Mes fichiers"
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:70
#: lib/Lufi/Controller/Files.pm:69
msgid "No enough space available on the server for this file (size: %1)."
msgstr "Espace disque insuffisant sur le serveur pour ce fichier (taille du fichier : %1)."
@ -298,7 +298,7 @@ msgstr "Veuillez contacter ladministrateur : %1"
msgid "Please wait while we are getting your file. We first need to download and decrypt all parts before you can get it."
msgstr "Veuillez patientez pendant la récupération de votre fichier. Nous devons dabord récupérer et déchiffrer tous les fragments avant que vous puissiez le télécharger."
#: lib/Lufi.pm:300
#: lib/Lufi.pm:191
msgid "Please, check your credentials: unable to authenticate."
msgstr "Veuillez vérifier vos identifiants : impossible de vous authentifier."
@ -339,7 +339,7 @@ msgstr "Partagez vos fichiers en toute confidentialité sur %1"
msgid "Signin"
msgstr "Connexion"
#: lib/Lufi.pm:303
#: lib/Lufi.pm:194
msgid "Sorry mate, you are not authorised to use that service. Contact your sysadmin if you think there's a glitch in the matrix."
msgstr "Désolé, vous nêtes pas autorisé à utiliser ce service. Contactez votre administrateur si vous pensez quil sagit dune erreur."
@ -347,7 +347,7 @@ msgstr "Désolé, vous nêtes pas autorisé à utiliser ce service. Contactez
msgid "Sorry, the uploading is currently disabled. Please try again later."
msgstr "Désolé, lenvoi de fichier est actuellement désactivé. Veuillez réessayer plus tard."
#: lib/Lufi/Controller/Files.pm:44
#: lib/Lufi/Controller/Files.pm:43
msgid "Sorry, uploading is disabled."
msgstr "Désolé, lenvoi de fichier est désactivé."
@ -367,7 +367,7 @@ msgstr "Le corps du mail ne peut être vide."
msgid "The email subject can't be empty."
msgstr "Le sujet du mail ne peut être vide."
#: lib/Lufi/Controller/Files.pm:388
#: lib/Lufi/Controller/Files.pm:390
msgid "The file has already been deleted"
msgstr "Le fichier a déjà été supprimé"
@ -392,7 +392,7 @@ msgstr "Le mail a été envoyé."
msgid "The original (and only for now) author is <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. If you want to support him, you can do it via <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> or via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
msgstr "Lauteur originel (et pour linstant, le seul) est <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. Si vous avez envie de le supporter, vous pouvez le faire via <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> ou via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
#: lib/Lufi/Controller/Files.pm:182
#: lib/Lufi/Controller/Files.pm:179
msgid "The server was unable to find the file record to add your file part to. Please, contact the administrator."
msgstr "Le serveur a été incapable de retrouver lenregistrement du fichier auquel ajouter votre fragment de fichier. Veuillez contacter ladministrateur."
@ -472,11 +472,11 @@ msgid "You must give email addresses."
msgstr "Vous devez envoyer des adresses mail."
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:57
#: lib/Lufi/Controller/Files.pm:56
msgid "Your file is too big: %1 (maximum size allowed: %2)"
msgstr "Votre fichier est trop volumineux : %1 (la taille maximum autorisée est %2)"
#: lib/Lufi/Controller/Files.pm:276
#: lib/Lufi/Controller/Files.pm:273
msgid "Your password is not valid. Please refresh the page to retry."
msgstr "Votre mot de passe est invalide. Veuillez rafraîchir la page pour réessayer."

View File

@ -92,15 +92,15 @@ msgstr "Copiare tutti i link negli appunti"
msgid "Copy to clipboard"
msgstr "Copiare negli appunti"
#: lib/Lufi/Controller/Files.pm:423
#: lib/Lufi/Controller/Files.pm:429
msgid "Could not delete the file. You are not authenticated."
msgstr "Impossibile cancellare il file. Non siete autenticati."
#: lib/Lufi/Controller/Files.pm:407
#: lib/Lufi/Controller/Files.pm:411
msgid "Could not find the file. Are you sure of the URL and the token?"
msgstr "Impossibile trovare il file. Sei sicuro che URL e token siano corretti ?"
#: lib/Lufi/Controller/Files.pm:323
#: lib/Lufi/Controller/Files.pm:322
msgid "Could not find the file. Are you sure of the URL?"
msgstr "Impossibile trovare il file. Sei sicuro che l'URL sia corretto?"
@ -156,15 +156,15 @@ msgstr "Email"
msgid "Encrypting part XX1 of XX2"
msgstr "Cifratura della parte XX1 di XX2"
#: lib/Lufi/Controller/Files.pm:230
#: lib/Lufi/Controller/Files.pm:225
msgid "Error: the file existed but was deleted."
msgstr "Errore: il file esisteva ma è stato eliminato"
#: lib/Lufi/Controller/Files.pm:292
#: lib/Lufi/Controller/Files.pm:291
msgid "Error: the file has not been sent entirely."
msgstr "Errore: il file non è stato inviato completamente"
#: lib/Lufi/Controller/Files.pm:302
#: lib/Lufi/Controller/Files.pm:301
msgid "Error: unable to find the file. Are you sure of your URL?"
msgstr "Errore: impossibile trovare il file. Sei certo dell'URL ?"
@ -180,7 +180,7 @@ msgstr "Scade il"
msgid "Export localStorage data"
msgstr "Esportare i dati del localStorage"
#: lib/Lufi/Controller/Files.pm:391
#: lib/Lufi/Controller/Files.pm:393
msgid "File deleted"
msgstr "File cancellato"
@ -273,7 +273,7 @@ msgid "My files"
msgstr "I miei file"
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:70
#: lib/Lufi/Controller/Files.pm:69
msgid "No enough space available on the server for this file (size: %1)."
msgstr "Spazio disco insufficiente sul server per questo file (dimensione: %1)."
@ -298,7 +298,7 @@ msgstr "Contattare l'amministratore : %1"
msgid "Please wait while we are getting your file. We first need to download and decrypt all parts before you can get it."
msgstr "Attendere mentre otteniamo il vostro file. Dobbiamo prima scaricare e decifrare tutte le parti prima che possiate averlo."
#: lib/Lufi.pm:300
#: lib/Lufi.pm:191
msgid "Please, check your credentials: unable to authenticate."
msgstr ""
@ -339,7 +339,7 @@ msgstr "Condividi tutti i file in totale riservatezza su %1"
msgid "Signin"
msgstr "Autenticazione"
#: lib/Lufi.pm:303
#: lib/Lufi.pm:194
msgid "Sorry mate, you are not authorised to use that service. Contact your sysadmin if you think there's a glitch in the matrix."
msgstr ""
@ -347,7 +347,7 @@ msgstr ""
msgid "Sorry, the uploading is currently disabled. Please try again later."
msgstr "L'invio del file è attualemente disattivato. Riprovare più tardi."
#: lib/Lufi/Controller/Files.pm:44
#: lib/Lufi/Controller/Files.pm:43
msgid "Sorry, uploading is disabled."
msgstr "L'invio del file è attualemente disattivato."
@ -367,7 +367,7 @@ msgstr "Il corpo dell'email non può essere vuoto."
msgid "The email subject can't be empty."
msgstr "Il soggetto dell'email non può essere vuoto."
#: lib/Lufi/Controller/Files.pm:388
#: lib/Lufi/Controller/Files.pm:390
msgid "The file has already been deleted"
msgstr "Il file è già stato cancellato"
@ -392,7 +392,7 @@ msgstr "Email inviata."
msgid "The original (and only for now) author is <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. If you want to support him, you can do it via <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> or via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
msgstr "L'autore ( e per ora l'unico) è <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. Se aveste voglia di aiutarlo, potreste farlo tramite <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> ou via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
#: lib/Lufi/Controller/Files.pm:182
#: lib/Lufi/Controller/Files.pm:179
msgid "The server was unable to find the file record to add your file part to. Please, contact the administrator."
msgstr "Il server non è stato in grado di trovare il file record a cui aggiungere la vostra porzione di file. Prego contattare l'amministratore."
@ -472,11 +472,11 @@ msgid "You must give email addresses."
msgstr "Devi fornire gli indirizzi email."
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:57
#: lib/Lufi/Controller/Files.pm:56
msgid "Your file is too big: %1 (maximum size allowed: %2)"
msgstr "Il vostro file è troppo grande : %1 (la dimensione massima permessa è %2)"
#: lib/Lufi/Controller/Files.pm:276
#: lib/Lufi/Controller/Files.pm:273
msgid "Your password is not valid. Please refresh the page to retry."
msgstr ""

View File

@ -79,15 +79,15 @@ msgstr "Kopieer alle links naar klembord"
msgid "Copy to clipboard"
msgstr "Kopieer naar klembord"
#: lib/Lufi/Controller/Files.pm:423
#: lib/Lufi/Controller/Files.pm:429
msgid "Could not delete the file. You are not authenticated."
msgstr "Kan het bestand niet verwijderen. Je bent niet geautoriseerd."
#: lib/Lufi/Controller/Files.pm:407
#: lib/Lufi/Controller/Files.pm:411
msgid "Could not find the file. Are you sure of the URL and the token?"
msgstr "Kan het bestand niet vinden. Klopt de URL en token wel?"
#: lib/Lufi/Controller/Files.pm:323
#: lib/Lufi/Controller/Files.pm:322
msgid "Could not find the file. Are you sure of the URL?"
msgstr "Kan het bestand niet vinden. Klopt de URL?"
@ -143,15 +143,15 @@ msgstr "Emails"
msgid "Encrypting part XX1 of XX2"
msgstr "Encrypten deel XX1 van XX2 "
#: lib/Lufi/Controller/Files.pm:230
#: lib/Lufi/Controller/Files.pm:225
msgid "Error: the file existed but was deleted."
msgstr "Fout: het bestand bestond wel maar is verwijderd."
#: lib/Lufi/Controller/Files.pm:292
#: lib/Lufi/Controller/Files.pm:291
msgid "Error: the file has not been sent entirely."
msgstr "Fout: het bestand is niet volledig opgestuurd."
#: lib/Lufi/Controller/Files.pm:302
#: lib/Lufi/Controller/Files.pm:301
msgid "Error: unable to find the file. Are you sure of your URL?"
msgstr "Fout: kan het bestand niet vinden. Is de URL juist?"
@ -167,7 +167,7 @@ msgstr "Vervalt op"
msgid "Export localStorage data"
msgstr "Exporteer opgeslagen data"
#: lib/Lufi/Controller/Files.pm:391
#: lib/Lufi/Controller/Files.pm:393
msgid "File deleted"
msgstr "Bestand verwijderd"
@ -260,7 +260,7 @@ msgid "My files"
msgstr "Mijn bestanden"
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:70
#: lib/Lufi/Controller/Files.pm:69
msgid "No enough space available on the server for this file (size: %1)."
msgstr "Geen genoeg ruimte op de server voor deze bestand (grootte: %1)."
@ -285,7 +285,7 @@ msgstr "Neem contact op met administrator: %1"
msgid "Please wait while we are getting your file. We first need to download and decrypt all parts before you can get it."
msgstr "Een ogenblik geduld, we pakken je bestand er bij. We moeten alle delen downloaden en decrypten voordat je het kan downloaden."
#: lib/Lufi.pm:300
#: lib/Lufi.pm:191
msgid "Please, check your credentials: unable to authenticate."
msgstr ""
@ -330,7 +330,7 @@ msgstr "Deel je bestanden met volledige privacy op %1"
msgid "Signin"
msgstr "Inloggen"
#: lib/Lufi.pm:303
#: lib/Lufi.pm:194
msgid "Sorry mate, you are not authorised to use that service. Contact your sysadmin if you think there's a glitch in the matrix."
msgstr ""
@ -338,7 +338,7 @@ msgstr ""
msgid "Sorry, the uploading is currently disabled. Please try again later."
msgstr "Sorry, uploaden is momenteel uitgeschakeld. Probeer het later nogmaals."
#: lib/Lufi/Controller/Files.pm:44
#: lib/Lufi/Controller/Files.pm:43
msgid "Sorry, uploading is disabled."
msgstr "SOrry, uploaden is uitgeschakeld."
@ -358,7 +358,7 @@ msgstr "Mail inhoud kan niet leeg zijn."
msgid "The email subject can't be empty."
msgstr "Onderwerp kan niet leeg zijn."
#: lib/Lufi/Controller/Files.pm:388
#: lib/Lufi/Controller/Files.pm:390
msgid "The file has already been deleted"
msgstr "Bestand is reeds verwijderd"
@ -383,7 +383,7 @@ msgstr "Email is verzonden."
msgid "The original (and only for now) author is <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. If you want to support him, you can do it via <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> or via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
msgstr "De oorspronkelijke auteur is <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. Als je hem wilt ondersteunen, dan kan dat via <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> of via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
#: lib/Lufi/Controller/Files.pm:182
#: lib/Lufi/Controller/Files.pm:179
msgid "The server was unable to find the file record to add your file part to. Please, contact the administrator."
msgstr "Server kon een deel van het bestand niet vinden. Neem contact op met beheerder."
@ -463,11 +463,11 @@ msgid "You must give email addresses."
msgstr "Je moet een mail adres opgeven."
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:57
#: lib/Lufi/Controller/Files.pm:56
msgid "Your file is too big: %1 (maximum size allowed: %2)"
msgstr "Je bestand is te groot: %1 (max: %2)"
#: lib/Lufi/Controller/Files.pm:276
#: lib/Lufi/Controller/Files.pm:273
msgid "Your password is not valid. Please refresh the page to retry."
msgstr ""

View File

@ -92,15 +92,15 @@ msgstr "Copiar totes los ligams dins lo quichapapièrs"
msgid "Copy to clipboard"
msgstr "Copiar dins lo quichapapièrs"
#: lib/Lufi/Controller/Files.pm:423
#: lib/Lufi/Controller/Files.pm:429
msgid "Could not delete the file. You are not authenticated."
msgstr "Impossible de suprimir lo fichièr. Sètz pas connectat-ada."
#: lib/Lufi/Controller/Files.pm:407
#: lib/Lufi/Controller/Files.pm:411
msgid "Could not find the file. Are you sure of the URL and the token?"
msgstr "Impossible de trobar lo fichièr. Sètz segur-a que lURL e lo geton son bons ?"
#: lib/Lufi/Controller/Files.pm:323
#: lib/Lufi/Controller/Files.pm:322
msgid "Could not find the file. Are you sure of the URL?"
msgstr "Impossible de trobar lo fichièr. Sètz segur-a que lURL es bona ?"
@ -156,15 +156,15 @@ msgstr "Corrièl"
msgid "Encrypting part XX1 of XX2"
msgstr "Chiframent del tròç XX1 sus XX2"
#: lib/Lufi/Controller/Files.pm:230
#: lib/Lufi/Controller/Files.pm:225
msgid "Error: the file existed but was deleted."
msgstr "Error : lo fichièr existissiá mas es estat suprimit"
#: lib/Lufi/Controller/Files.pm:292
#: lib/Lufi/Controller/Files.pm:291
msgid "Error: the file has not been sent entirely."
msgstr "Error : lo fichièr es pas estat mandat completament"
#: lib/Lufi/Controller/Files.pm:302
#: lib/Lufi/Controller/Files.pm:301
msgid "Error: unable to find the file. Are you sure of your URL?"
msgstr "Error : impossible de trobar lo fichièr. Sètz segur-a de lURL ?"
@ -180,7 +180,7 @@ msgstr "Expira lo"
msgid "Export localStorage data"
msgstr "Exportar las donadas localStorage"
#: lib/Lufi/Controller/Files.pm:391
#: lib/Lufi/Controller/Files.pm:393
msgid "File deleted"
msgstr "Fichièr suprimit"
@ -273,7 +273,7 @@ msgid "My files"
msgstr "Mos fichièrs"
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:70
#: lib/Lufi/Controller/Files.pm:69
msgid "No enough space available on the server for this file (size: %1)."
msgstr "Espaci disc insufisent sul servidor per aqueste fichièr (talha del fichièr : \"%1)."
@ -298,7 +298,7 @@ msgstr "Mercés de contactar ladministrator : %1"
msgid "Please wait while we are getting your file. We first need to download and decrypt all parts before you can get it."
msgstr "Mercés desperar pendent la recuperacion de vòstre fichièr. Nos cal den primièr recuperar e deschifrar totes los fragaments abans que poscatz o telecargar."
#: lib/Lufi.pm:300
#: lib/Lufi.pm:191
msgid "Please, check your credentials: unable to authenticate."
msgstr ""
@ -339,7 +339,7 @@ msgstr "Partejatz vòstres fichièrs en tota confidencialitat sus %1"
msgid "Signin"
msgstr "Connexion"
#: lib/Lufi.pm:303
#: lib/Lufi.pm:194
msgid "Sorry mate, you are not authorised to use that service. Contact your sysadmin if you think there's a glitch in the matrix."
msgstr ""
@ -347,7 +347,7 @@ msgstr ""
msgid "Sorry, the uploading is currently disabled. Please try again later."
msgstr "O planhèm, la foncion per mandar de fichièr es desactivada pel moment. Mercés de tornar ensajar mai tard."
#: lib/Lufi/Controller/Files.pm:44
#: lib/Lufi/Controller/Files.pm:43
msgid "Sorry, uploading is disabled."
msgstr "O planhèm, la foncion per mandar de fichièr es desactivada."
@ -367,7 +367,7 @@ msgstr "Lo contengut del corrièl pòt pas èsser void."
msgid "The email subject can't be empty."
msgstr "Lo sujècte del corrièl pòt pas èsser void."
#: lib/Lufi/Controller/Files.pm:388
#: lib/Lufi/Controller/Files.pm:390
msgid "The file has already been deleted"
msgstr "Lo fichièr es ja estat suprimit"
@ -392,7 +392,7 @@ msgstr "Lo corrièl es estat mandat."
msgid "The original (and only for now) author is <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. If you want to support him, you can do it via <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> or via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
msgstr "Lautor original (e pel moment, lo sol) es <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. Savètz enveja de lo sostenir, podètz o far via <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> o via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
#: lib/Lufi/Controller/Files.pm:182
#: lib/Lufi/Controller/Files.pm:179
msgid "The server was unable to find the file record to add your file part to. Please, contact the administrator."
msgstr "Lo servidor es pas estat capable de retrobar lenregistrament del fichièr que li cal ajustar vòstre tròç de fichièr. Mercés de contactar ladministrator."
@ -472,11 +472,11 @@ msgid "You must give email addresses."
msgstr "Vos cal donar dadreças."
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:57
#: lib/Lufi/Controller/Files.pm:56
msgid "Your file is too big: %1 (maximum size allowed: %2)"
msgstr "Vòstre fichièr es tròp voluminós : %1 (la talha maximum autorizada es %2)"
#: lib/Lufi/Controller/Files.pm:276
#: lib/Lufi/Controller/Files.pm:273
msgid "Your password is not valid. Please refresh the page to retry."
msgstr ""

View File

@ -93,15 +93,15 @@ msgstr "Copiar todos os links para a área de transferência"
msgid "Copy to clipboard"
msgstr "Copiar para a área de transferência"
#: lib/Lufi/Controller/Files.pm:423
#: lib/Lufi/Controller/Files.pm:429
msgid "Could not delete the file. You are not authenticated."
msgstr "Impossível apagar o ficheiro. Não está conectado."
#: lib/Lufi/Controller/Files.pm:407
#: lib/Lufi/Controller/Files.pm:411
msgid "Could not find the file. Are you sure of the URL and the token?"
msgstr "Impossível encontrar o ficheiro.Tem a certeza que o URL e os símbolos estão corretos?"
#: lib/Lufi/Controller/Files.pm:323
#: lib/Lufi/Controller/Files.pm:322
msgid "Could not find the file. Are you sure of the URL?"
msgstr "Impossível encontar o ficheiro. Tem a certeza de que o URL está correto?"
@ -161,15 +161,15 @@ msgstr "E-mails"
msgid "Encrypting part XX1 of XX2"
msgstr "Codificação do fragmento XX1 de XX2"
#: lib/Lufi/Controller/Files.pm:230
#: lib/Lufi/Controller/Files.pm:225
msgid "Error: the file existed but was deleted."
msgstr "Erro: o ficheiro existia mas foi apagado."
#: lib/Lufi/Controller/Files.pm:292
#: lib/Lufi/Controller/Files.pm:291
msgid "Error: the file has not been sent entirely."
msgstr "Erro: o ficheiro não foi enviado na totalidade."
#: lib/Lufi/Controller/Files.pm:302
#: lib/Lufi/Controller/Files.pm:301
msgid "Error: unable to find the file. Are you sure of your URL?"
msgstr "Erro: impossível encontrar o ficheiro. Tem a certeza do URL?"
@ -185,7 +185,7 @@ msgstr "Expira no"
msgid "Export localStorage data"
msgstr "Exportar os dados localStorage"
#: lib/Lufi/Controller/Files.pm:391
#: lib/Lufi/Controller/Files.pm:393
msgid "File deleted"
msgstr "Ficheiro apagado"
@ -282,7 +282,7 @@ msgid "My files"
msgstr "Meus ficheiros"
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:70
#: lib/Lufi/Controller/Files.pm:69
msgid "No enough space available on the server for this file (size: %1)."
msgstr "O servidor não tem espaço suficiente para este ficheiro (tamanho: %1)."
@ -307,7 +307,7 @@ msgstr "Contacte o administrador: %1"
msgid "Please wait while we are getting your file. We first need to download and decrypt all parts before you can get it."
msgstr "Por favor aguarde durante a recuperação do seu ficheiro. Primeiro devemos recuperar e descodificar todos os fragmentos e depois poderá descarregar o ficheiro."
#: lib/Lufi.pm:300
#: lib/Lufi.pm:191
msgid "Please, check your credentials: unable to authenticate."
msgstr ""
@ -348,7 +348,7 @@ msgstr "Partilhe os seus ficheiros com toda a privacidade em %1"
msgid "Signin"
msgstr "Conexão"
#: lib/Lufi.pm:303
#: lib/Lufi.pm:194
msgid "Sorry mate, you are not authorised to use that service. Contact your sysadmin if you think there's a glitch in the matrix."
msgstr ""
@ -356,7 +356,7 @@ msgstr ""
msgid "Sorry, the uploading is currently disabled. Please try again later."
msgstr "Desculpe, o envio do ficheiro está atualmente desativado. Tente mais tarde."
#: lib/Lufi/Controller/Files.pm:44
#: lib/Lufi/Controller/Files.pm:43
msgid "Sorry, uploading is disabled."
msgstr "Desculpe, o envio do ficheiro está desativado."
@ -376,7 +376,7 @@ msgstr "A mensagem do e-mail não pode estar vazia."
msgid "The email subject can't be empty."
msgstr "O assunto do e-mail não pode estar vazio."
#: lib/Lufi/Controller/Files.pm:388
#: lib/Lufi/Controller/Files.pm:390
msgid "The file has already been deleted"
msgstr "O ficheiro já foi apagado"
@ -401,7 +401,7 @@ msgstr "O e-mail foi enviado."
msgid "The original (and only for now) author is <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. If you want to support him, you can do it via <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> or via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
msgstr "O autor original (e por agora, o único) é <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>. Se o desejar apoiar pode fazer-lo via <a href=\"https://www.tipeee.com/fiat-tux\" class=\"classic\">Tipeee</a> ou via <a href=\"https://liberapay.com/sky/\" class=\"classic\">Liberapay</a>."
#: lib/Lufi/Controller/Files.pm:182
#: lib/Lufi/Controller/Files.pm:179
msgid "The server was unable to find the file record to add your file part to. Please, contact the administrator."
msgstr "O servidor foi incapaz de encontrar o registo do ficheiro no qual devia-se juntar o fragmento do seu ficheiro. Contacte o administrador."
@ -485,11 +485,11 @@ msgid "You must give email addresses."
msgstr "Deve escrever os e-mails."
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:57
#: lib/Lufi/Controller/Files.pm:56
msgid "Your file is too big: %1 (maximum size allowed: %2)"
msgstr "O seu ficheiro é grande de mais: %1 (o tamanho máximo autorizado é de %2)"
#: lib/Lufi/Controller/Files.pm:276
#: lib/Lufi/Controller/Files.pm:273
msgid "Your password is not valid. Please refresh the page to retry."
msgstr ""

View File

@ -106,6 +106,10 @@ function spawnWebsocket(pa) {
innerHTML.push('<video class="responsive-video" controls>',
'<source src="', blobURL, '" type="', data.type, '">',
'</video>');
} else if (data.type.match(/^audio\//) !== null) {
innerHTML.push('<audio class="responsive-video" controls>',
'<source src="', blobURL, '" type="', data.type, '">',
'</audio>');
}
pbd.html(innerHTML.join(''));

View File

@ -0,0 +1,27 @@
-- 1 up
CREATE TABLE IF NOT EXISTS files (
short text PRIMARY KEY,
deleted boolean default false,
mediatype text,
filename text,
filesize integer,
counter integer default 0,
delete_at_first_view boolean,
delete_at_day integer,
created_at integer,
created_by text,
last_access_at integer,
mod_token text,
nbslices integer,
complete boolean default false,
passwd text
);
CREATE TABLE IF NOT EXISTS slices (
short text REFERENCES files(short) ON DELETE CASCADE,
j integer NOT NULL,
path text unique NOT NULL,
);
-- 1 down
DROP TABLE slices;
DROP TABLE files;